[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_PLANE 11
#define O_LIGHTING_VISUAL_RENDER_TARGET "O_LIGHT_VISUAL_PLANE" #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. /// This plane masks out lighting to create an "emissive" effect, ie for glowing lights in otherwise dark areas.
#define EMISSIVE_PLANE 14 #define EMISSIVE_PLANE 14
#define RENDER_PLANE_LIGHTING 15 #define RENDER_PLANE_LIGHTING 15
///Things that should render ignoring lighting
#define ABOVE_LIGHTING_PLANE 16
///---------------- MISC ----------------------- ///---------------- MISC -----------------------
///Pipecrawling images ///Pipecrawling images

View File

@@ -14,6 +14,8 @@
screen.update_for_view(client.view) screen.update_for_view(client.view)
client.screen += screen client.screen += screen
SET_PLANE_EXPLICIT(screen, PLANE_TO_TRUE(screen.plane), src)
return screen return screen
/mob/proc/clear_fullscreen(category, animated = 10) /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 /// 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() /atom/movable/screen/plane_master/proc/mirror_parent_hidden()
var/mob/our_mob = home?.our_hud?.mymob 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) if(true_plane == src || !true_plane)
return 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." documentation = "Holds the seethrough versions (done using image overrides) of large objects. Mouse transparent, so you can click through them."
plane = SEETHROUGH_PLANE plane = SEETHROUGH_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT mouse_opacity = MOUSE_OPACITY_TRANSPARENT
render_relay_planes = list(GAME_PLANE) render_relay_planes = list(RENDER_PLANE_GAME_WORLD)
start_hidden = TRUE start_hidden = TRUE
/atom/movable/screen/plane_master/game_world_above /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 var/datum/hud/hud = home.our_hud
if(hud) if(hud)
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change) 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) /atom/movable/screen/plane_master/blackness/hide_from(mob/oldmob)
. = ..() . = ..()

View File

@@ -151,3 +151,20 @@
if(use_scale) if(use_scale)
return ..(source, new_offset, source.should_use_scale()) return ..(source, new_offset, source.should_use_scale())
return ..() 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 var/datum/hud/hud = home.our_hud
if(hud) if(hud)
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change) 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) /atom/movable/screen/plane_master/rendering_plate/master/hide_from(mob/oldmob)
. = ..() . = ..()
@@ -138,7 +138,7 @@
var/datum/hud/hud = home.our_hud var/datum/hud/hud = home.our_hud
if(hud) if(hud)
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change) 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) set_alpha(mymob.lighting_alpha)
@@ -278,10 +278,3 @@
return relay return relay
return null 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 initialized = INITIALIZATION_INSSATOMS
/datum/controller/subsystem/atoms/Initialize() /datum/controller/subsystem/atoms/Initialize()
GLOB.fire_overlay.appearance_flags = RESET_COLOR
setupGenetics() //to set the mutations' sequence setupGenetics() //to set the mutations' sequence
initialized = INITIALIZATION_INNEW_MAPLOAD initialized = INITIALIZATION_INNEW_MAPLOAD

View File

@@ -765,8 +765,6 @@ GLOBAL_LIST_EMPTY(the_station_areas)
create_plane_offsets(gen_from, new_offset) create_plane_offsets(gen_from, new_offset)
for(var/offset in gen_from to new_offset) for(var/offset in gen_from to new_offset)
GLOB.fullbright_overlays += create_fullbright_overlay(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) for(var/datum/gas/gas_type as anything in GLOB.meta_gas_info)
var/list/gas_info = GLOB.meta_gas_info[gas_type] var/list/gas_info = GLOB.meta_gas_info[gas_type]

View File

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

View File

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

View File

@@ -212,7 +212,7 @@
// Build message image // Build message image
message = image(loc = message_loc, layer = CHAT_LAYER + CHAT_LAYER_Z_STEP * current_z_idx++) 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.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART
message.alpha = 0 message.alpha = 0
message.pixel_y = target.maptext_height 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. * Component that can be used to clean things.
* Takes care of duration, cleaning skill and special cleaning interactions. * 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) /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 if(!HAS_TRAIT(target, CURRENTLY_CLEANING)) //add the trait and overlay
ADD_TRAIT(target, CURRENTLY_CLEANING, src) 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) // We need to update our planes on overlay changes
else if(target.plane == GLOB.cleaning_bubbles_lower.plane) RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, .proc/cleaning_target_moved)
if(target.layer > GLOB.cleaning_bubbles_lower.layer) var/mutable_appearance/low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, GAME_PLANE)
target.add_overlay(GLOB.cleaning_bubbles_higher) 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 else
target.add_overlay(GLOB.cleaning_bubbles_lower) target.add_overlay(low_bubble)
else //(target.plane < GLOB.cleaning_bubbles_lower.plane) else //(target.plane < low_bubble.plane)
target.add_overlay(GLOB.cleaning_bubbles_lower) target.add_overlay(low_bubble)
//set the cleaning duration //set the cleaning duration
var/cleaning_duration = base_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) on_cleaned_callback?.Invoke(source, target, user)
//remove the cleaning overlay //remove the cleaning overlay
target.cut_overlay(GLOB.cleaning_bubbles_lower) var/mutable_appearance/low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, GAME_PLANE)
target.cut_overlay(GLOB.cleaning_bubbles_higher) 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) 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) if(!to_copy)
plane = FLOAT_PLANE 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) /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) if(plane != FLOAT_PLANE)
// Essentially, we allow users that only want one static offset to pass one in // Essentially, we allow users that only want one static offset to pass one in
if(!isnull(offset_const)) if(!isnull(offset_const))
plane = GET_NEW_PLANE(plane, offset_const) plane = GET_NEW_PLANE(plane, offset_const)
// That, or you need to pass in some non null object to reference // 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 // 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 // Not passing ANYTHING in, key difference
var/turf/our_turf = get_turf(offset_spokesman) var/turf/our_turf = get_turf(offset_spokesman)
plane = MUTATE_PLANE(plane, our_turf) plane = MUTATE_PLANE(plane, our_turf)
// otherwise if you're setting plane you better have the guts to back it up // otherwise if you're setting plane you better have the guts to back it up
else 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() var/mutable_appearance/MA = new()
MA.icon = icon MA.icon = icon
MA.icon_state = icon_state 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 /// You will need to manage adding/removing from this yourself, but I'll do the updating for you
var/list/image/update_on_z 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 ///Cooldown tick timer for buckle messages
var/buckle_message_cooldown = 0 var/buckle_message_cooldown = 0
///Last fingerprints to touch this atom ///Last fingerprints to touch this atom

View File

@@ -1052,9 +1052,17 @@
// so we do this. sucks to suck // so we do this. sucks to suck
update_appearance() update_appearance()
if(update_on_z)
// I so much wish this could be somewhere else. alas, no. // I so much wish this could be somewhere else. alas, no.
for(var/image/update in update_on_z) for(var/image/update in update_on_z)
SET_PLANE(update, PLANE_TO_TRUE(update.plane), new_turf) 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) if(!notify_contents)
return return

View File

@@ -135,6 +135,7 @@
. = ..() . = ..()
if(same_z_layer) if(same_z_layer)
return return
if(warp)
SET_PLANE(warp, PLANE_TO_TRUE(warp.plane), new_turf) SET_PLANE(warp, PLANE_TO_TRUE(warp.plane), new_turf)
/obj/effect/anomaly/grav/anomalyEffect(delta_time) /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(fire_overlay, /mutable_appearance, mutable_appearance('icons/effects/fire.dmi', "fire", appearance_flags = RESET_COLOR))
GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons/effects/welding_effect.dmi', "welding_sparks", GASFIRE_LAYER, ABOVE_LIGHTING_PLANE))
/// Anything you can pick up and hold. /// Anything you can pick up and hold.
/obj/item /obj/item

View File

@@ -120,9 +120,12 @@
qdel(src) qdel(src)
/obj/item/weldingtool/use_tool(atom/target, mob/living/user, delay, amount, volume, datum/callback/extra_checks) /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) /obj/item/weldingtool/attack(mob/living/carbon/human/attacked_humanoid, mob/living/user)
if(!istype(attacked_humanoid)) if(!istype(attacked_humanoid))

View File

@@ -213,22 +213,16 @@
. = ..() . = ..()
SET_PLANE_IMPLICIT(src, initial(plane)) 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() /obj/machinery/atmospherics/components/unary/cryo_cell/update_overlays()
. = ..() . = ..()
if(panel_open) if(panel_open)
. += "pod-panel" . += "pod-panel"
if(state_open) if(state_open)
return return
var/turf/our_turf = get_turf(src) if(on && is_operational)
var/offset = GET_TURF_PLANE_OFFSET(our_turf) + 1 . += mutable_appearance('icons/obj/medical/cryogenics.dmi', "cover-on", ABOVE_ALL_MOB_LAYER, src, plane = ABOVE_GAME_PLANE)
. += (on && is_operational) ? GLOB.cryo_overlays_cover_on[offset] : GLOB.cryo_overlays_cover_off[offset] 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) /obj/machinery/atmospherics/components/unary/cryo_cell/nap_violation(mob/violator)
open_machine() open_machine()

View File

@@ -3,7 +3,8 @@
// The datum containing all the chunks. // 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.. #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) GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
/datum/cameranet /datum/cameranet
@@ -39,17 +40,17 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
/// Checks if a chunk has been Generated in x, y, z. /// Checks if a chunk has been Generated in x, y, z.
/datum/cameranet/proc/chunkGenerated(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 = GET_CHUNK_COORD(x)
x &= ~(CHUNK_SIZE - 1) y = GET_CHUNK_COORD(y)
y &= ~(CHUNK_SIZE - 1) var/turf/lowest = get_lowest_turf(locate(x, y, z))
return chunks["[x],[y],[lowest.z]"] return chunks["[x],[y],[lowest.z]"]
// Returns the chunk in the x, y, z. // Returns the chunk in the x, y, z.
// If there is no chunk, it creates a new chunk and returns that. // If there is no chunk, it creates a new chunk and returns that.
/datum/cameranet/proc/getCameraChunk(x, y, z) /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)) var/turf/lowest = get_lowest_turf(locate(x, y, z))
x &= ~(CHUNK_SIZE - 1)
y &= ~(CHUNK_SIZE - 1)
var/key = "[x],[y],[lowest.z]" var/key = "[x],[y],[lowest.z]"
. = chunks[key] . = chunks[key]
if(!.) if(!.)
@@ -67,12 +68,11 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
for(var/mob/camera/ai_eye/eye as anything in moved_eyes) for(var/mob/camera/ai_eye/eye as anything in moved_eyes)
var/list/visibleChunks = list() var/list/visibleChunks = list()
if(eye.loc) if(eye.loc)
// 0xf = 15
var/static_range = eye.static_visibility_range var/static_range = eye.static_visibility_range
var/x1 = max(0, eye.x - static_range) & ~(CHUNK_SIZE - 1) var/x1 = max(1, eye.x - static_range)
var/y1 = max(0, eye.y - static_range) & ~(CHUNK_SIZE - 1) var/y1 = max(1, eye.y - static_range)
var/x2 = min(world.maxx, eye.x + static_range) & ~(CHUNK_SIZE - 1) var/x2 = min(world.maxx, eye.x + static_range)
var/y2 = min(world.maxy, eye.y + static_range) & ~(CHUNK_SIZE - 1) var/y2 = min(world.maxy, eye.y + static_range)
for(var/x = x1; x <= x2; x += CHUNK_SIZE) for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += 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) var/turf/T = get_turf(c)
if(T) if(T)
var/x1 = max(0, T.x - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1) var/x1 = max(1, T.x - (CHUNK_SIZE / 2))
var/y1 = max(0, T.y - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1) var/y1 = max(1, T.y - (CHUNK_SIZE / 2))
var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1) var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2))
var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1) var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2))
for(var/x = x1; x <= x2; x += CHUNK_SIZE) for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += CHUNK_SIZE) for(var/y = y1; y <= y2; y += CHUNK_SIZE)
var/datum/camerachunk/chunk = chunkGenerated(x, y, T.z) 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. /// Create a new camera chunk, since the chunks are made as they are needed.
/datum/camerachunk/New(x, y, lower_z) /datum/camerachunk/New(x, y, lower_z)
x &= ~(CHUNK_SIZE - 1) x = GET_CHUNK_COORD(x)
y &= ~(CHUNK_SIZE - 1) y = GET_CHUNK_COORD(y)
src.x = x src.x = x
src.y = y src.y = y
@@ -171,3 +171,4 @@
#undef UPDATE_BUFFER_TIME #undef UPDATE_BUFFER_TIME
#undef CHUNK_SIZE #undef CHUNK_SIZE
#undef GET_CHUNK_COORD

View File

@@ -57,11 +57,11 @@
thought_bubble.overlays += point_visual thought_bubble.overlays += point_visual
add_overlay(thought_bubble) 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) addtimer(CALLBACK(src, .proc/clear_point_bubble, thought_bubble), POINT_TIME)
/atom/movable/proc/clear_point_bubble(mutable_appearance/thought_bubble) /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) cut_overlay(thought_bubble)
/obj/effect/temp_visual/point /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) /obj/item/gun/energy/plasmacutter/use_tool(atom/target, mob/living/user, delay, amount=1, volume=0, datum/callback/extra_checks)
if(amount) 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 else
. = ..(amount=1) . = ..(amount=1)

View File

@@ -140,6 +140,7 @@
#include "outfit_sanity.dm" #include "outfit_sanity.dm"
#include "paintings.dm" #include "paintings.dm"
#include "pills.dm" #include "pills.dm"
#include "plane_double_transform.dm"
#include "plane_dupe_detector.dm" #include "plane_dupe_detector.dm"
#include "plantgrowth_tests.dm" #include "plantgrowth_tests.dm"
#include "preference_species.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 /// Instances allocated through this proc will be destroyed when the test is over
/datum/unit_test/proc/allocate(type, ...) /datum/unit_test/proc/allocate(type, ...)
var/list/arguments = args.Copy(2) var/list/arguments = args.Copy(2)
if(ispath(type, /atom))
if (!arguments.len) if (!arguments.len)
arguments = list(run_loc_floor_bottom_left) arguments = list(run_loc_floor_bottom_left)
else if (arguments[1] == null) else if (arguments[1] == null)
arguments[1] = run_loc_floor_bottom_left arguments[1] = run_loc_floor_bottom_left
var/instance = new type(arglist(arguments)) 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 allocated += instance
return instance return instance

View File

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

View File

@@ -15,18 +15,37 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT mouse_opacity = MOUSE_OPACITY_TRANSPARENT
anchored = TRUE anchored = TRUE
layer = ABOVE_MOB_LAYER layer = ABOVE_MOB_LAYER
vis_flags = VIS_INHERIT_PLANE plane = GAME_PLANE_UPPER
/obj/effect/overlay/water/top /obj/effect/overlay/water/top
icon_state = "top" icon_state = "top"
layer = BELOW_MOB_LAYER 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) /turf/open/water/overlay/Initialize(mapload)
. = ..() . = ..()
var/obj/effect/overlay/water/water_overlay = new()
var/obj/effect/overlay/water/top/water_top_overlay = new() var/obj/effect/overlay/water/bottom = new()
vis_contents += water_overlay SET_PLANE(bottom, PLANE_TO_TRUE(bottom.plane), src)
vis_contents += water_top_overlay 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) /turf/open/water/overlay/Entered(atom/movable/arrived)
..() ..()
@@ -50,25 +69,18 @@
mood_change = 4 mood_change = 4
timeout = 20 MINUTES timeout = 20 MINUTES
// Planetside water, indestructible. /**
/turf/open/water/overlay * Planetside water, indestructible.
name = "shallow water" *
desc = "A natural body of shallow water." * Use this for outdoors. It normalises to it's initial airmix over time!
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!
/turf/open/water/overlay/outdoors /turf/open/water/overlay/outdoors
baseturfs = /turf/open/water/overlay/outdoors baseturfs = /turf/open/water/overlay/outdoors
planetary_atmos = TRUE 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 /turf/open/water/overlay/hotspring
name = "hotspring" name = "hotspring"
desc = "A warm, steamy swimming pool." desc = "A warm, steamy swimming pool."