[MIRROR] Cleans up the fallout from plane cube [MDB IGNORE] (#17003)

* Cleans up the fallout from plane cube (#70235)

* Cleans up the fallout from plane cube

Alright.
Makes cleaning bubbles respect planes
Adds support for updating overlays on move, fixing an issue with pointing at items
Adds better error messages for failing to provide args for mutable_appearance()
Fixes a bug where string overlays were not respecting insertion order

* Adds documentation for offset spokesman and offset_const

* Better stack trace

* Removes some redundant uses of cached MAs

At this scale, attempting to cache MAs like this has 0 impact on anything
And just makes things more messy then they need to be

* ensures fullscreen objects START offset, so things are always proper

* ensures chatmessages always have the right offset

* fixes compile

* whoops, the above lighting plane should actually be ABOVE the lighting plane

* fixes compile, also cleans up the fire overlay a tad

* Adds a unit test for plane masters that are shrunk by multiz being double shrunk

This is slightly hacky because of how I'm handing the plane master
group, but it's not THAT bad, and gives me some real good coverage

* Properly targets the seethrough plane at the game world plate. This fixes unit tests, and also just makes more sense

* whoops

* oh

* adds datum support for allocate(), cleans up a harddel from testing

* Makes camera chunks index at 1, and also makes them support non powers of two sizes, since that was unneeded

* fixes runtime in allocate

* Cleans up the fallout from plane cube

* liquid tweaks

* oop

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: tastyfish <crazychris32@gmail.com>
This commit is contained in:
SkyratBot
2022-10-20 01:43:05 +02:00
committed by GitHub
parent 3bdde7cb2a
commit 59dc5c36b7
27 changed files with 254 additions and 126 deletions

View File

@@ -45,14 +45,14 @@
#define O_LIGHTING_VISUAL_PLANE 11
#define O_LIGHTING_VISUAL_RENDER_TARGET "O_LIGHT_VISUAL_PLANE"
///Things that should render ignoring lighting
#define ABOVE_LIGHTING_PLANE 12
/// This plane masks out lighting to create an "emissive" effect, ie for glowing lights in otherwise dark areas.
#define EMISSIVE_PLANE 14
#define RENDER_PLANE_LIGHTING 15
///Things that should render ignoring lighting
#define ABOVE_LIGHTING_PLANE 16
///---------------- MISC -----------------------
///Pipecrawling images

View File

@@ -14,6 +14,8 @@
screen.update_for_view(client.view)
client.screen += screen
SET_PLANE_EXPLICIT(screen, PLANE_TO_TRUE(screen.plane), src)
return screen
/mob/proc/clear_fullscreen(category, animated = 10)

View File

@@ -153,7 +153,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master)
/// This allows us to mirror any hidden sets from before we were created, no matter how low that chance is
/atom/movable/screen/plane_master/proc/mirror_parent_hidden()
var/mob/our_mob = home?.our_hud?.mymob
var/atom/movable/screen/plane_master/true_plane = our_mob?.hud_used.get_plane_master(plane)
var/atom/movable/screen/plane_master/true_plane = our_mob?.hud_used?.get_plane_master(plane)
if(true_plane == src || !true_plane)
return
@@ -301,7 +301,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master)
documentation = "Holds the seethrough versions (done using image overrides) of large objects. Mouse transparent, so you can click through them."
plane = SEETHROUGH_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
render_relay_planes = list(GAME_PLANE)
render_relay_planes = list(RENDER_PLANE_GAME_WORLD)
start_hidden = TRUE
/atom/movable/screen/plane_master/game_world_above
@@ -347,7 +347,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master)
var/datum/hud/hud = home.our_hud
if(hud)
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change)
offset_change(0, hud.current_plane_offset)
offset_change(0, hud?.current_plane_offset || 0)
/atom/movable/screen/plane_master/blackness/hide_from(mob/oldmob)
. = ..()

View File

@@ -91,7 +91,7 @@
// It would be nice to setup parallaxing for stairs and things when doing this
// So they look nicer. if you can't it's all good, if you think you can sanely look at monster's work
// It's hard, and potentially expensive. be careful
// It's hard, and potentially expensive. be careful
/datum/plane_master_group/proc/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE)
// No offset? piss off
if(!SSmapping.max_plane_offset)
@@ -151,3 +151,20 @@
if(use_scale)
return ..(source, new_offset, source.should_use_scale())
return ..()
/// Hudless group. Exists for testing
/datum/plane_master_group/hudless
var/mob/our_mob
/datum/plane_master_group/hudless/Destroy()
. = ..()
our_mob = null
/datum/plane_master_group/hudless/hide_hud()
for(var/thing in plane_masters)
var/atom/movable/screen/plane_master/plane = plane_masters[thing]
plane.hide_from(our_mob)
/// This is mostly a proc so it can be overriden by popups, since they have unique behavior they want to do
/datum/plane_master_group/hudless/show_plane(atom/movable/screen/plane_master/plane)
plane.show_to(our_mob)

View File

@@ -45,7 +45,7 @@
var/datum/hud/hud = home.our_hud
if(hud)
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change)
offset_change(hud.current_plane_offset)
offset_change(hud?.current_plane_offset || 0)
/atom/movable/screen/plane_master/rendering_plate/master/hide_from(mob/oldmob)
. = ..()
@@ -138,7 +138,7 @@
var/datum/hud/hud = home.our_hud
if(hud)
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change)
offset_change(hud.current_plane_offset)
offset_change(hud?.current_plane_offset || 0)
set_alpha(mymob.lighting_alpha)
@@ -278,10 +278,3 @@
return relay
return null
/// Basically, trigger a full hud rebuild so our relays will be added to the screen
/// I hate hud code
/atom/movable/screen/plane_master/proc/rebuild_relays()
relays = list()
var/datum/hud/hud = home.our_hud
hud.show_hud(hud.hud_version)

View File

@@ -29,7 +29,6 @@ SUBSYSTEM_DEF(atoms)
initialized = INITIALIZATION_INSSATOMS
/datum/controller/subsystem/atoms/Initialize()
GLOB.fire_overlay.appearance_flags = RESET_COLOR
setupGenetics() //to set the mutations' sequence
initialized = INITIALIZATION_INNEW_MAPLOAD

View File

@@ -765,8 +765,6 @@ GLOBAL_LIST_EMPTY(the_station_areas)
create_plane_offsets(gen_from, new_offset)
for(var/offset in gen_from to new_offset)
GLOB.fullbright_overlays += create_fullbright_overlay(offset)
GLOB.cryo_overlays_cover_on += create_cryo_overlay(offset, "cover-on")
GLOB.cryo_overlays_cover_off += create_cryo_overlay(offset, "cover-off")
for(var/datum/gas/gas_type as anything in GLOB.meta_gas_info)
var/list/gas_info = GLOB.meta_gas_info[gas_type]

View File

@@ -37,7 +37,7 @@ SUBSYSTEM_DEF(overlays)
iconbro.icon = icon
return iconbro.appearance
/atom/proc/build_appearance_list(build_overlays)
/atom/proc/build_appearance_list(list/build_overlays)
if (!islist(build_overlays))
build_overlays = list(build_overlays)
for (var/overlay in build_overlays)
@@ -53,11 +53,11 @@ SUBSYSTEM_DEF(overlays)
stack_trace("Invalid overlay: Icon object '[icon_file]' [REF(icon)] used in '[src]' [type] is missing icon state [overlay].")
continue
#endif
build_overlays -= overlay
build_overlays += iconstate2appearance(icon, overlay)
var/index = build_overlays.Find(overlay)
build_overlays[index] = iconstate2appearance(icon, overlay)
else if(isicon(overlay))
build_overlays -= overlay
build_overlays += icon2appearance(overlay)
var/index = build_overlays.Find(overlay)
build_overlays[index] = icon2appearance(overlay)
return build_overlays
/atom/proc/cut_overlays()

View File

@@ -214,12 +214,12 @@
//speech bubble
if(owner.client)
var/mutable_appearance/MA = mutable_appearance('icons/mob/effects/talk.dmi', src, "default[say_test(message)]", FLY_LAYER)
SET_PLANE_EXPLICIT(MA, ABOVE_GAME_PLANE, src)
MA.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
INVOKE_ASYNC(GLOBAL_PROC, /proc/flick_overlay, MA, list(owner.client), 30)
LAZYADD(update_on_z, MA)
addtimer(CALLBACK(src, .proc/clear_saypopup, MA), 3.5 SECONDS)
var/image/bubble = mutable_appearance('icons/mob/effects/talk.dmi', src, "default[say_test(message)]", FLY_LAYER)
SET_PLANE_EXPLICIT(bubble, ABOVE_GAME_PLANE, src)
bubble.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
INVOKE_ASYNC(GLOBAL_PROC, /proc/flick_overlay, bubble, list(owner.client), 30)
LAZYADD(update_on_z, bubble)
addtimer(CALLBACK(src, .proc/clear_saypopup, bubble), 3.5 SECONDS)
for(var/mob/M in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(M, owner)

View File

@@ -212,7 +212,7 @@
// Build message image
message = image(loc = message_loc, layer = CHAT_LAYER + CHAT_LAYER_Z_STEP * current_z_idx++)
SET_PLANE(message, RUNECHAT_PLANE, message_loc)
SET_PLANE_EXPLICIT(message, RUNECHAT_PLANE, message_loc)
message.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART
message.alpha = 0
message.pixel_y = target.maptext_height

View File

@@ -1,6 +1,3 @@
GLOBAL_DATUM_INIT(cleaning_bubbles_lower, /mutable_appearance, mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, GAME_PLANE)) //displays at the top of floor tiles, but under mobs
GLOBAL_DATUM_INIT(cleaning_bubbles_higher, /mutable_appearance, mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, ABOVE_GAME_PLANE)) //displays above mobs
/**
* Component that can be used to clean things.
* Takes care of duration, cleaning skill and special cleaning interactions.
@@ -93,15 +90,20 @@ GLOBAL_DATUM_INIT(cleaning_bubbles_higher, /mutable_appearance, mutable_appearan
/datum/component/cleaner/proc/clean(datum/source, atom/target, mob/living/user, clean_target = TRUE)
if(!HAS_TRAIT(target, CURRENTLY_CLEANING)) //add the trait and overlay
ADD_TRAIT(target, CURRENTLY_CLEANING, src)
if(target.plane > GLOB.cleaning_bubbles_lower.plane) //check if the higher overlay is necessary
target.add_overlay(GLOB.cleaning_bubbles_higher)
else if(target.plane == GLOB.cleaning_bubbles_lower.plane)
if(target.layer > GLOB.cleaning_bubbles_lower.layer)
target.add_overlay(GLOB.cleaning_bubbles_higher)
// We need to update our planes on overlay changes
RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, .proc/cleaning_target_moved)
var/mutable_appearance/low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, GAME_PLANE)
var/mutable_appearance/high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, ABOVE_GAME_PLANE)
if(target.plane > low_bubble.plane) //check if the higher overlay is necessary
target.add_overlay(high_bubble)
else if(target.plane == low_bubble.plane)
if(target.layer > low_bubble.layer)
target.add_overlay(high_bubble)
else
target.add_overlay(GLOB.cleaning_bubbles_lower)
else //(target.plane < GLOB.cleaning_bubbles_lower.plane)
target.add_overlay(GLOB.cleaning_bubbles_lower)
target.add_overlay(low_bubble)
else //(target.plane < low_bubble.plane)
target.add_overlay(low_bubble)
//set the cleaning duration
var/cleaning_duration = base_cleaning_duration
@@ -121,6 +123,23 @@ GLOBAL_DATUM_INIT(cleaning_bubbles_higher, /mutable_appearance, mutable_appearan
on_cleaned_callback?.Invoke(source, target, user)
//remove the cleaning overlay
target.cut_overlay(GLOB.cleaning_bubbles_lower)
target.cut_overlay(GLOB.cleaning_bubbles_higher)
var/mutable_appearance/low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, GAME_PLANE)
var/mutable_appearance/high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, ABOVE_GAME_PLANE)
target.cut_overlay(low_bubble)
target.cut_overlay(high_bubble)
REMOVE_TRAIT(target, CURRENTLY_CLEANING, src)
/datum/component/cleaner/proc/cleaning_target_moved(atom/movable/source, turf/old_turf, turf/new_turf, same_z_layer)
if(same_z_layer)
return
// First, get rid of the old overlay
var/mutable_appearance/old_low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, old_turf, GAME_PLANE)
var/mutable_appearance/old_high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, old_turf, ABOVE_GAME_PLANE)
source.cut_overlay(old_low_bubble)
source.cut_overlay(old_high_bubble)
// Now, add the new one
var/mutable_appearance/new_low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, new_turf, GAME_PLANE)
var/mutable_appearance/new_high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, new_turf, ABOVE_GAME_PLANE)
source.add_overlay(new_low_bubble)
source.add_overlay(new_high_bubble)

View File

@@ -11,21 +11,35 @@
if(!to_copy)
plane = FLOAT_PLANE
/// Helper similar to image()
/** Helper similar to image()
*
* icon - Our appearance's icon
* icon_state - Our appearance's icon state
* layer - Our appearance's layer
* atom/offset_spokesman - An atom to use as reference for the z position of this appearance.
* Only required if a plane is passed in. If this is not passed in we accept offset_const as a substitute
* plane - The plane to use for the appearance. If this is not FLOAT_PLANE we require context for the offset to use
* alpha - Our appearance's alpha
* appearance_flags - Our appearance's appearance_flags
* offset_const - A constant to offset our plane by, so it renders on the right "z layer"
**/
/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, atom/offset_spokesman, plane = FLOAT_PLANE, alpha = 255, appearance_flags = NONE, offset_const)
if(plane != FLOAT_PLANE)
// Essentially, we allow users that only want one static offset to pass one in
if(!isnull(offset_const))
plane = GET_NEW_PLANE(plane, offset_const)
// That, or you need to pass in some non null object to reference
else if(!isnull(offset_spokesman))
else if(isatom(offset_spokesman))
// Note, we are ok with null turfs, that's not an error condition we'll just default to 0, the error would be
// Not passing ANYTHING in, key difference
var/turf/our_turf = get_turf(offset_spokesman)
plane = MUTATE_PLANE(plane, our_turf)
// otherwise if you're setting plane you better have the guts to back it up
else
stack_trace("No plane offset passed in as context for a non floating mutable appearance, ya done fucked up")
stack_trace("No plane offset passed in as context for a non floating mutable appearance, things are gonna go to hell on multiz maps")
else if(!isnull(offset_spokesman) && !isatom(offset_spokesman))
stack_trace("Why did you pass in offset_spokesman as [offset_spokesman]? We need an atom to properly offset planes")
var/mutable_appearance/MA = new()
MA.icon = icon
MA.icon_state = icon_state

View File

@@ -64,6 +64,11 @@
/// You will need to manage adding/removing from this yourself, but I'll do the updating for you
var/list/image/update_on_z
/// Lazylist of all overlays attached to us to update when we change z levels
/// You will need to manage adding/removing from this yourself, but I'll do the updating for you
/// Oh and note, if order of addition is important this WILL break that. so mind yourself
var/list/image/update_overlays_on_z
///Cooldown tick timer for buckle messages
var/buckle_message_cooldown = 0
///Last fingerprints to touch this atom

View File

@@ -1052,9 +1052,17 @@
// so we do this. sucks to suck
update_appearance()
// I so much wish this could be somewhere else. alas, no.
for(var/image/update in update_on_z)
SET_PLANE(update, PLANE_TO_TRUE(update.plane), new_turf)
if(update_on_z)
// I so much wish this could be somewhere else. alas, no.
for(var/image/update in update_on_z)
SET_PLANE(update, PLANE_TO_TRUE(update.plane), new_turf)
if(update_overlays_on_z)
// This EVEN more so
cut_overlay(update_overlays_on_z)
// This even more so
for(var/mutable_appearance/update in update_overlays_on_z)
SET_PLANE(update, PLANE_TO_TRUE(update.plane), new_turf)
add_overlay(update_overlays_on_z)
if(!notify_contents)
return

View File

@@ -135,7 +135,8 @@
. = ..()
if(same_z_layer)
return
SET_PLANE(warp, PLANE_TO_TRUE(warp.plane), new_turf)
if(warp)
SET_PLANE(warp, PLANE_TO_TRUE(warp.plane), new_turf)
/obj/effect/anomaly/grav/anomalyEffect(delta_time)
..()

View File

@@ -1,5 +1,4 @@
GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/effects/fire.dmi', "fire"))
GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons/effects/welding_effect.dmi', "welding_sparks", GASFIRE_LAYER, ABOVE_LIGHTING_PLANE))
GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/effects/fire.dmi', "fire", appearance_flags = RESET_COLOR))
/// Anything you can pick up and hold.
/obj/item

View File

@@ -120,9 +120,12 @@
qdel(src)
/obj/item/weldingtool/use_tool(atom/target, mob/living/user, delay, amount, volume, datum/callback/extra_checks)
target.add_overlay(GLOB.welding_sparks)
var/mutable_appearance/sparks = mutable_appearance('icons/effects/welding_effect.dmi', "welding_sparks", GASFIRE_LAYER, src, ABOVE_LIGHTING_PLANE)
target.add_overlay(sparks)
target.update_overlays_on_z += sparks
. = ..()
target.cut_overlay(GLOB.welding_sparks)
target.update_overlays_on_z -= sparks
target.cut_overlay(sparks)
/obj/item/weldingtool/attack(mob/living/carbon/human/attacked_humanoid, mob/living/user)
if(!istype(attacked_humanoid))

View File

@@ -213,22 +213,16 @@
. = ..()
SET_PLANE_IMPLICIT(src, initial(plane))
GLOBAL_LIST_INIT_TYPED(cryo_overlays_cover_on, /mutable_appearance, list(create_cryo_overlay(0, "cover-on")))
GLOBAL_LIST_INIT_TYPED(cryo_overlays_cover_off, /mutable_appearance, list(create_cryo_overlay(0, "cover-off")))
/proc/create_cryo_overlay(offset, icon_state)
var/mutable_appearance/cryo_overlay = mutable_appearance('icons/obj/medical/cryogenics.dmi', icon_state, ABOVE_ALL_MOB_LAYER, plane = ABOVE_GAME_PLANE, offset_const = offset)
return cryo_overlay
/obj/machinery/atmospherics/components/unary/cryo_cell/update_overlays()
. = ..()
if(panel_open)
. += "pod-panel"
if(state_open)
return
var/turf/our_turf = get_turf(src)
var/offset = GET_TURF_PLANE_OFFSET(our_turf) + 1
. += (on && is_operational) ? GLOB.cryo_overlays_cover_on[offset] : GLOB.cryo_overlays_cover_off[offset]
if(on && is_operational)
. += mutable_appearance('icons/obj/medical/cryogenics.dmi', "cover-on", ABOVE_ALL_MOB_LAYER, src, plane = ABOVE_GAME_PLANE)
else
. += mutable_appearance('icons/obj/medical/cryogenics.dmi', "cover-on", ABOVE_ALL_MOB_LAYER, src, plane = ABOVE_GAME_PLANE)
/obj/machinery/atmospherics/components/unary/cryo_cell/nap_violation(mob/violator)
open_machine()

View File

@@ -3,7 +3,8 @@
// The datum containing all the chunks.
#define CHUNK_SIZE 16 // Only chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc..
/// Takes a position, transforms it into a chunk bounded position. Indexes at 1 so it'll land on actual turfs always
#define GET_CHUNK_COORD(v) (FLOOR(v, CHUNK_SIZE) + 1)
GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
/datum/cameranet
@@ -39,17 +40,17 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
/// Checks if a chunk has been Generated in x, y, z.
/datum/cameranet/proc/chunkGenerated(x, y, z)
var/turf/lowest = get_lowest_turf(locate(max(x, 1), max(y, 1), z))
x &= ~(CHUNK_SIZE - 1)
y &= ~(CHUNK_SIZE - 1)
x = GET_CHUNK_COORD(x)
y = GET_CHUNK_COORD(y)
var/turf/lowest = get_lowest_turf(locate(x, y, z))
return chunks["[x],[y],[lowest.z]"]
// Returns the chunk in the x, y, z.
// If there is no chunk, it creates a new chunk and returns that.
/datum/cameranet/proc/getCameraChunk(x, y, z)
x = GET_CHUNK_COORD(x)
y = GET_CHUNK_COORD(y)
var/turf/lowest = get_lowest_turf(locate(x, y, z))
x &= ~(CHUNK_SIZE - 1)
y &= ~(CHUNK_SIZE - 1)
var/key = "[x],[y],[lowest.z]"
. = chunks[key]
if(!.)
@@ -67,12 +68,11 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
for(var/mob/camera/ai_eye/eye as anything in moved_eyes)
var/list/visibleChunks = list()
if(eye.loc)
// 0xf = 15
var/static_range = eye.static_visibility_range
var/x1 = max(0, eye.x - static_range) & ~(CHUNK_SIZE - 1)
var/y1 = max(0, eye.y - static_range) & ~(CHUNK_SIZE - 1)
var/x2 = min(world.maxx, eye.x + static_range) & ~(CHUNK_SIZE - 1)
var/y2 = min(world.maxy, eye.y + static_range) & ~(CHUNK_SIZE - 1)
var/x1 = max(1, eye.x - static_range)
var/y1 = max(1, eye.y - static_range)
var/x2 = min(world.maxx, eye.x + static_range)
var/y2 = min(world.maxy, eye.y + static_range)
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
@@ -126,10 +126,10 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
var/turf/T = get_turf(c)
if(T)
var/x1 = max(0, T.x - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
var/y1 = max(0, T.y - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
var/x1 = max(1, T.x - (CHUNK_SIZE / 2))
var/y1 = max(1, T.y - (CHUNK_SIZE / 2))
var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2))
var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2))
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
var/datum/camerachunk/chunk = chunkGenerated(x, y, T.z)

View File

@@ -126,8 +126,8 @@
/// Create a new camera chunk, since the chunks are made as they are needed.
/datum/camerachunk/New(x, y, lower_z)
x &= ~(CHUNK_SIZE - 1)
y &= ~(CHUNK_SIZE - 1)
x = GET_CHUNK_COORD(x)
y = GET_CHUNK_COORD(y)
src.x = x
src.y = y
@@ -171,3 +171,4 @@
#undef UPDATE_BUFFER_TIME
#undef CHUNK_SIZE
#undef GET_CHUNK_COORD

View File

@@ -57,11 +57,11 @@
thought_bubble.overlays += point_visual
add_overlay(thought_bubble)
LAZYADD(update_on_z, thought_bubble)
LAZYADD(update_overlays_on_z, thought_bubble)
addtimer(CALLBACK(src, .proc/clear_point_bubble, thought_bubble), POINT_TIME)
/atom/movable/proc/clear_point_bubble(mutable_appearance/thought_bubble)
LAZYREMOVE(update_on_z, thought_bubble)
LAZYREMOVE(update_overlays_on_z, thought_bubble)
cut_overlay(thought_bubble)
/obj/effect/temp_visual/point

View File

@@ -176,9 +176,12 @@
/obj/item/gun/energy/plasmacutter/use_tool(atom/target, mob/living/user, delay, amount=1, volume=0, datum/callback/extra_checks)
if(amount)
target.add_overlay(GLOB.welding_sparks)
var/mutable_appearance/sparks = mutable_appearance('icons/effects/welding_effect.dmi', "welding_sparks", GASFIRE_LAYER, src, ABOVE_LIGHTING_PLANE)
target.add_overlay(sparks)
target.update_overlays_on_z += sparks
. = ..()
target.cut_overlay(GLOB.welding_sparks)
target.update_overlays_on_z -= sparks
target.cut_overlay(sparks)
else
. = ..(amount=1)

View File

@@ -140,6 +140,7 @@
#include "outfit_sanity.dm"
#include "paintings.dm"
#include "pills.dm"
#include "plane_double_transform.dm"
#include "plane_dupe_detector.dm"
#include "plantgrowth_tests.dm"
#include "preference_species.dm"

View File

@@ -0,0 +1,44 @@
/// Ensures plane masters that get shrunk by multiz NEVER render into each other
/datum/unit_test/plane_double_transform
/datum/unit_test/plane_double_transform/Run()
// We're going to operate off the actual plane master setup of an actual mob
// It's not perfect, but it'll help things a lot
var/mob/living/carbon/human/judger = allocate(/mob/living/carbon/human)
// Hack to account for not having an actual hud
var/datum/plane_master_group/hudless/our_group = allocate(/datum/plane_master_group/hudless)
our_group.our_mob = judger
our_group.show_hud()
// End hack
// Generates a list of render target -> PM for future use
var/list/render_target_to_plane = list()
for(var/plane_key as anything in our_group.plane_masters)
var/atom/movable/screen/plane_master/plane = our_group.plane_masters[plane_key]
if(plane.render_target)
render_target_to_plane[plane.render_target] = plane
for(var/plane_key as anything in our_group.plane_masters)
var/atom/movable/screen/plane_master/plane = our_group.plane_masters[plane_key]
if(!plane.multiz_scaled)
continue
// Walk the relay targets
for(var/target_plane in plane.render_relay_planes)
var/atom/movable/screen/plane_master/target = our_group.plane_masters["[target_plane]"]
if(target.multiz_scaled)
TEST_FAIL("[plane.type] draws a render relay into [target.type]. Both are scaled by multiz, so this will cause strange transforms.\n\
consider making a new render plate that they can both draw to instead, or something of that nature.")
// Now we walk for filters that take from us
for(var/filter_id in plane.filter_data)
var/list/filter = plane.filter_data[filter_id]
if(!filter["render_source"])
continue
var/atom/movable/screen/plane_master/target = render_target_to_plane[filter["render_source"]]
if(target.multiz_scaled)
TEST_FAIL("[plane.type] draws a render relay into [target.type]. Both are scaled by multiz, so this will cause strange transforms.\n\
consider making a new render plate that they can both draw to instead, or something of that nature.")

View File

@@ -76,11 +76,17 @@ GLOBAL_LIST_EMPTY(unit_test_mapping_logs)
/// Instances allocated through this proc will be destroyed when the test is over
/datum/unit_test/proc/allocate(type, ...)
var/list/arguments = args.Copy(2)
if (!arguments.len)
arguments = list(run_loc_floor_bottom_left)
else if (arguments[1] == null)
arguments[1] = run_loc_floor_bottom_left
var/instance = new type(arglist(arguments))
if(ispath(type, /atom))
if (!arguments.len)
arguments = list(run_loc_floor_bottom_left)
else if (arguments[1] == null)
arguments[1] = run_loc_floor_bottom_left
var/instance
// Byond will throw an index out of bounds if arguments is empty in that arglist call. Sigh
if(length(arguments))
instance = new type(arglist(arguments))
else
instance = new type()
allocated += instance
return instance

View File

@@ -193,6 +193,25 @@
if(harderforce)
. = ..()
/**
* Add liquid effect overlay.
*
* Arguments:
* * overlay_state - the icon state of the new overlay
* * overlay_layer - the layer
* * overlay_plane - the plane
*/
/obj/effect/abstract/liquid_turf/proc/add_liquid_overlay(overlay_state, overlay_layer, overlay_plane)
PRIVATE_PROC(TRUE)
add_overlay(mutable_appearance(
'modular_skyrat/modules/liquids/icons/obj/effects/liquid_overlays.dmi',
overlay_state,
overlay_layer,
src,
overlay_plane,
))
/**
* Add over and underlays for different liquid states.
*
@@ -201,24 +220,14 @@
* * has_top - if this stage has a top.
*/
/obj/effect/abstract/liquid_turf/proc/add_state_layer(state, has_top)
add_overlay(mutable_appearance(
'modular_skyrat/modules/liquids/icons/obj/effects/liquid_overlays.dmi',
"stage[state]_bottom",
offset_spokesman = src,
plane = GAME_PLANE,
layer = ABOVE_MOB_LAYER,
))
PRIVATE_PROC(TRUE)
add_liquid_overlay("stage[state]_bottom", ABOVE_MOB_LAYER, GAME_PLANE_UPPER)
if(!has_top)
return
add_overlay(mutable_appearance(
'modular_skyrat/modules/liquids/icons/obj/effects/liquid_overlays.dmi',
"stage[state]_top",
offset_spokesman = src,
plane = GAME_PLANE,
layer = GATEWAY_UNDERLAY_LAYER
))
add_liquid_overlay("stage[state]_top", GATEWAY_UNDERLAY_LAYER, GAME_PLANE)
/obj/effect/abstract/liquid_turf/proc/set_new_liquid_state(new_state)
liquid_state = new_state

View File

@@ -15,18 +15,37 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
anchored = TRUE
layer = ABOVE_MOB_LAYER
vis_flags = VIS_INHERIT_PLANE
plane = GAME_PLANE_UPPER
/obj/effect/overlay/water/top
icon_state = "top"
layer = BELOW_MOB_LAYER
plane = GAME_PLANE
/**
* Planetside water, indestructible.
*
* Use this for indoors.
*/
/turf/open/water/overlay
name = "shallow water"
desc = "A natural body of shallow water."
icon = 'modular_skyrat/modules/mapping/icons/unique/pool.dmi'
icon_state = "rocky"
baseturfs = /turf/open/water/overlay
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
planetary_atmos = FALSE
/turf/open/water/overlay/Initialize(mapload)
. = ..()
var/obj/effect/overlay/water/water_overlay = new()
var/obj/effect/overlay/water/top/water_top_overlay = new()
vis_contents += water_overlay
vis_contents += water_top_overlay
. = ..()
var/obj/effect/overlay/water/bottom = new()
SET_PLANE(bottom, PLANE_TO_TRUE(bottom.plane), src)
vis_contents += bottom
var/obj/effect/overlay/water/top/top = new()
SET_PLANE(top, PLANE_TO_TRUE(top.plane), src)
vis_contents += top
/turf/open/water/overlay/Entered(atom/movable/arrived)
..()
@@ -50,25 +69,18 @@
mood_change = 4
timeout = 20 MINUTES
// Planetside water, indestructible.
/turf/open/water/overlay
name = "shallow water"
desc = "A natural body of shallow water."
icon = 'modular_skyrat/modules/mapping/icons/unique/pool.dmi'
icon_state = "rocky"
baseturfs = /turf/open/water/overlay
var/obj/effect/overlay/water/water_overlay
var/obj/effect/overlay/water/top/water_top_overlay
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
planetary_atmos = FALSE
// Use this for indoors. It has a roof!
/**
* Planetside water, indestructible.
*
* Use this for outdoors. It normalises to it's initial airmix over time!
*/
/turf/open/water/overlay/outdoors
baseturfs = /turf/open/water/overlay/outdoors
planetary_atmos = TRUE
// Use this for outdoors. It normalises to it's initial airmix over time!
// Hotpsrings! They give a positive mood event.
/**
* Hotpsrings! They give a positive mood event.
*/
/turf/open/water/overlay/hotspring
name = "hotspring"
desc = "A warm, steamy swimming pool."