diff --git a/cev_eris.dme b/cev_eris.dme index ec1885774cd..ccf1870a32a 100644 --- a/cev_eris.dme +++ b/cev_eris.dme @@ -232,6 +232,7 @@ #include "code\_onclick\hud\HUD_element\types\custom_buttons.dm" #include "code\_onclick\hud\HUD_element\types\layout.dm" #include "code\_onclick\hud\HUD_element\types\threePartBox.dm" +#include "code\_onclick\hud\rendering\render_plate.dm" #include "code\_onclick\hud\screen_objects\base_screen_objects.dm" #include "code\_onclick\hud\screen_objects\robot_screen_objects.dm" #include "code\ATMOSPHERICS\_atmos_setup.dm" diff --git a/code/__DEFINES/_planes+layers.dm b/code/__DEFINES/_planes+layers.dm index 732a3148635..29072481d3b 100644 --- a/code/__DEFINES/_planes+layers.dm +++ b/code/__DEFINES/_planes+layers.dm @@ -49,31 +49,44 @@ What is the naming convention for planes or layers? */ //Defines for atom layers and planes -//KEEP THESE IN A NICE ACSCENDING ORDER, PLEASE +//KEEP THESE IN A NICE ACSCENDING ORDER, PLEASE //lol + +//DISCLAIMER: ALL PLANES WHICH WILL BE RENDERED INGAME -MUST- HAVE AN ASSOCIATED PLANE MASTER. +//This is because plane masters collect plane content, send it to render plates +//which then relay it to a master render plate which renders 'above' everything +//unclaimed planes are left behind outside that master plate and WILL NOT be visible ingame + +//NEVER HAVE ANYTHING BELOW THIS PLANE ADJUST IF YOU NEED MORE SPACE +#define LOWEST_EVER_PLANE -200 #define CLICKCATCHER_PLANE -99 #define PLANE_SPACE -95 #define PLANE_SPACE_PARALLAX -80 +#define GRAVITY_PULSE_PLANE -12 +#define GRAVITY_PULSE_RENDER_TARGET "*GRAVPULSE_RENDER_TARGET" + #define OPENSPACE_PLANE -10 #define OVER_OPENSPACE_PLANE -8 -#define FLOOR_PLANE -2 -#define GAME_PLANE -1 +#define FLOOR_PLANE -5 +#define GAME_PLANE -4 +//whoever did this should be drawn and quartered //Partial porting of bay defines, with our own values reinserted as placeholder //The full list of planes and layers needs ported -#define HIDING_MOB_PLANE -1//-16 on bay. + +//#define HIDING_MOB_PLANE -1//-16 on bay. #define HIDING_MOB_LAYER 2.54 //-0 on bay -#define LYING_MOB_PLANE -1 //-14 on bay// other mobs that are lying down. +#define LYING_MOB_PLANE -4 //-14 on bay// other mobs that are lying down. #define LYING_MOB_LAYER 3.8 //0 on bay -#define LYING_HUMAN_PLANE -1 //-13 on bay// humans that are lying down +//#define LYING_HUMAN_PLANE -1 //-13 on bay// humans that are lying down #define LYING_HUMAN_LAYER 3.8 //0 on bay @@ -156,37 +169,58 @@ What is the naming convention for planes or layers? #define MASSIVE_OBJ_LAYER 11 #define POINT_LAYER 12 -#define LIGHTING_PLANE 15 +#define LIGHTING_PLANE 100 #define LIGHTING_LAYER 15 -#define ABOVE_LIGHTING_PLANE 16 +#define ABOVE_LIGHTING_PLANE 110 #define ABOVE_LIGHTING_LAYER 16 -#define BYOND_LIGHTING_PLANE 17 +#define BYOND_LIGHTING_PLANE 120 #define BYOND_LIGHTING_LAYER 17 +#define WEATHER_PLANE 150 + //HUD layer defines -#define FULLSCREEN_PLANE 9900 +//-------------------- Rendering --------------------- +#define RENDER_PLANE_GAME 990 +#define RENDER_PLANE_NON_GAME 995 +#define RENDER_PLANE_MASTER 999 + +#define FULLSCREEN_PLANE 2000 + #define FLASH_LAYER 18 #define FULLSCREEN_LAYER 18.1 #define UI_DAMAGE_LAYER 18.2 -#define HUD_PLANE 9910 -#define HUD_LAYER 19 -#define ABOVE_HUD_PLANE 9920 -#define ABOVE_HUD_LAYER 20 +#define BELOW_HUD_PLANE 2900 +#define BELOW_HUD_LAYER 19 +#define HUD_PLANE 3000 +#define HUD_LAYER 20 +#define ABOVE_HUD_PLANE 4000 +#define ABOVE_HUD_LAYER 21 -#define RUNECHAT_PLANE 9930 +#define RUNECHAT_PLANE 5000 -#define BALLOON_CHAT_PLANE 9935 +#define BALLOON_CHAT_PLANE 6000 -#define CINEMATIC_PLANE 9950 -#define CINEMATIC_LAYER 22 +#define CINEMATIC_PLANE 8000 +#define CINEMATIC_LAYER 24 #define BELOW_PLATING_LEVEL 1 #define ABOVE_PLATING_LEVEL 2 + +//---------- Plane Master multi_z_flags ------------- +// Describes how different plane masters behave regarding being offset by z-levels +/// This plane master will not be duped, existing only once at the 'base' z-level +/// Mostly used for planes that really don't need to be duplicated +#define BLOCKS_PLANE_OFFSETTING (1<<0) +/// This plane master will offset relays to match the highest possible rendering Z +/// Mainly used for effects that need to render above all z's +#define OFFSET_RELAYS_MATCH_HIGHEST (1<<1) + + /atom/proc/reset_plane_and_layer() set_plane(original_plane) layer = initial(layer) diff --git a/code/__HELPERS/filters.dm b/code/__HELPERS/filters.dm index 7be7ca5d732..5e15de59541 100644 --- a/code/__HELPERS/filters.dm +++ b/code/__HELPERS/filters.dm @@ -294,7 +294,14 @@ GLOBAL_LIST_INIT(master_filter_info, list( if(!isnull(flags)) .["flags"] = flags -/proc/apply_wibbly_filters(atom/in_atom, length) + + +//filter procs & elements, including distortion elements(using the distortion filter on the game plate. See render_plate.dm) + + +///produces a heavy warping effect that displaces an object across multiple axes simutaneously. +///incredibly necrotic old code I don't fully understand. But tg uses it so it must be fine :D +/atom/proc/apply_wibbly_filters(length) for(var/i in 1 to 7) //This is a very baffling and strange way of doing this but I am just preserving old functionality var/X @@ -306,14 +313,168 @@ GLOBAL_LIST_INIT(master_filter_info, list( rsq = X*X + Y*Y while(rsq<100 || rsq>900) // Yeah let's just loop infinitely due to bad luck what's the worst that could happen? var/random_roll = rand() - in_atom.add_filter("wibbly-[i]", 5, wave_filter(x = X, y = Y, size = rand() * 2.5 + 0.5, offset = random_roll)) - var/filter = in_atom.get_filter("wibbly-[i]") + add_filter("wibbly-[i]", 5, wave_filter(x = X, y = Y, size = rand() * 2.5 + 0.5, offset = random_roll)) + var/filter = get_filter("wibbly-[i]") animate(filter, offset = random_roll, time = 0, loop = -1, flags = ANIMATION_PARALLEL) animate(offset = random_roll - 1, time = rand() * 20 + 10) -/proc/remove_wibbly_filters(atom/in_atom) +///removes the 'wibbling' effect(see apply_wibbly_filters) +/atom/proc/remove_wibbly_filters() var/filter for(var/i in 1 to 7) - filter = in_atom.get_filter("wibbly-[i]") + filter = get_filter("wibbly-[i]") animate(filter) - in_atom.remove_filter("wibbly-[i]") + remove_filter("wibbly-[i]") + +///normal map used for advanced wibbling +/obj/effect/abstract/normalmap_bumpy + icon = 'icons/effects/light_overlays/normalmap_bumpy.dmi' + icon_state = "normalmap_bumpy" + appearance_flags = RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE + plane = GRAVITY_PULSE_PLANE + + +///Proc which replaces an atom's visual appearance with a wobbly distortion mask, using render target +/atom/movable/proc/apply_wibble_invisible(strength=50) + var/obj/effect/abstract/normalmap_bumpy/normal_bumpy = new(src) + var/render_tgt = "*warped_invis_[REF(normal_bumpy)]" + if(render_target) + render_tgt += "_oldtgt_" + render_target + normal_bumpy.alpha = (255/100) * strength + render_target = render_tgt + normal_bumpy.apply_wibbly_filters() + normal_bumpy.add_filter("wibble_mask", 1, alpha_mask_filter(-48, -48, render_source = render_target)) + vis_contents += normal_bumpy + update_overlays() + update_icon() + update_filters() + +/atom/movable/proc/remove_wibble_invisible() + var/list/split_result = splittext(render_target, "_oldtgt_") + var/ref_part = split_result[1] + if(length(split_result) > 1) + var/old_part = split_result[2] + render_target = old_part + else + render_target = null + ref_part = copytext(ref_part, 15) + var/obj/effect/abstract/normalmap_bumpy/normal_bumpy = locate(ref_part) in vis_contents + vis_contents -= normal_bumpy + qdel(normal_bumpy) + +///Applies a subtle, vapour-like distortion effect to an atom, but keeps it visible. +/atom/movable/proc/add_mirage_mask(strength=50) + var/obj/effect/abstract/normalmap_bumpy/normal_bumpy = new(src) + // var/render_tgt = "*warped_invis_[REF(normal_bumpy)]" + // if(render_target) + // render_tgt += "_oldtgt_" + render_target + normal_bumpy.alpha = (255/100) * strength + // render_target = render_tgt + normal_bumpy.apply_wibbly_filters() + normal_bumpy.add_filter("wibble_mask", 1, alpha_mask_filter(-48, -48, render_source="*[REF(src)]")) + var/mutable_appearance/mask = mutable_appearance() + mask.appearance = src.appearance + mask.render_target = "*[REF(src)]" + //mask.alpha = 125 + normal_bumpy.overlays += mask + //note: because this doesn't currently produce a searchable ref, it'll need to be manually tracked and removed. + vis_contents += normal_bumpy + +//notes on looping an animate() sequence: +//the inherent 'loop' function on animate() will not directly 'reset' the conditions it created +//in this case, radius = 1 > radius = 32 && size = 2 > size = 4 +//a second, immediately following animate command is needed to reset these back to their original conditions +//to make the loop actually do anything the second time onwards +//second animate() will be treated as an extension of the first, if it does not have an obj target + +///applies a repeating rippling effect to a target atom. +///args: length(duration of ripple), strength(intensity of ripple) +/atom/proc/apply_ripple_filter(length = 1.5 SECONDS, strength = 4) + add_filter("basic_ripple", 3, ripple_filter(1, strength, flags = WAVE_BOUNDED)) + animate(get_filter("basic_ripple"), radius = 32, time = length, size = (strength * 2), loop = -1, easing = LINEAR_EASING) + animate(radius = 0, size = 2) + +///removes the affect of apply_ripple_filter() +/atom/proc/remove_ripple_filter() + remove_filter("basic_ripple") + +///A basic temporary displacement effect +/obj/effect/temp_visual/space_warp + icon = 'icons/effects/light_overlays/light_128.dmi' + icon_state = "light" + plane = GRAVITY_PULSE_PLANE + pixel_x = -48 + pixel_y = -48 + duration = 4 + +/obj/effect/temp_visual/space_warp/Initialize() + . = ..() + animate(src, time=duration, transform=matrix().Scale(0.1,0.1)) + +///A distortion effect which remains in place and effects a wide area through walls. Useful for large, dramatic distortions +/atom/movable/static_distortion + plane = GRAVITY_PULSE_PLANE + appearance_flags = PIXEL_SCALE|LONG_GLIDE // no tile bound so you can see it around corners and so + icon = 'icons/effects/light_overlays/light_352.dmi' + icon_state = "light" + pixel_x = -176 + pixel_y = -176 + +/obj/effect/temp_visual/blink_drive + icon = 'icons/effects/light_overlays/light_128.dmi' + icon_state = "light" + plane = GRAVITY_PULSE_PLANE + duration = 8 + appearance_flags = PIXEL_SCALE|LONG_GLIDE + alpha = 0 + +/obj/effect/temp_visual/blink_drive/Initialize(mapload) + . = ..() + src.transform *= 0 + var/image/I = image(icon, src, icon_state, 10, pixel_x = -48, pixel_y = -48) + overlays += I //we use an overlay so the icon and light source are both in the correct location + icon_state = null + animate(src, time=(duration), transform=matrix().Scale(1,1)) + // animate(src, time=(duration / 2), alpha = 255) + // animate(time=(duration / 2), alpha = 0) + +/obj/effect/temp_visual/bluespace_pulse + icon = 'icons/effects/light_overlays/normalmap_bumpy.dmi' + icon_state = "normalmap_bumpy_circle" + plane = GRAVITY_PULSE_PLANE + duration = 4 + alpha = 125 + +/obj/effect/temp_visual/bluespace_pulse/Initialize(mapload) + . = ..() + var/image/I = image(icon, src, icon_state, 10, pixel_x = -144, pixel_y = -144) + overlays += I //we use an overlay so the icon and light source are both in the correct location + icon_state = null + animate(src, time=(duration+0.1), transform=matrix().Scale(0.1,0.1)) + set_light(4, 4, COLOR_LIGHTING_BLUE_DARK) + + +/** + * Visual shockwave effect using a displacement filter applied to the game world plate + * Args: + * * radius: visual max radius of the effect + * * speed_rate: propagation rate of the effect as a ratio (0.5 is twice as fast) + * * easing_type: easing type to use in the anim + * * y_offset: additional pixel_y offsets + * * x_offset: additional pixel_x offsets + */ +/obj/effect/temp_visual/shockwave + icon = 'icons/effects/light_overlays/normalmap_shockwave.dmi' + icon_state = "shockwave" + plane = GRAVITY_PULSE_PLANE + pixel_x = -496 + pixel_y = -496 + +/obj/effect/temp_visual/shockwave/Initialize(mapload, radius=12, direction, speed_rate=1, easing_type = LINEAR_EASING, y_offset=0, x_offset=0) + . = ..() + pixel_x += x_offset + pixel_y += y_offset + duration = 0.5 * radius * speed_rate + transform = matrix().Scale(32 / 1024, 32 / 1024) + animate(src, time = 1/2 * radius * speed_rate, transform=matrix().Scale((32 / 1024) * radius * 1.5, (32 / 1024) * radius * 1.5), easing=easing_type) + diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm index 001826c6408..fe0f18eee1d 100644 --- a/code/_onclick/hud/plane_master.dm +++ b/code/_onclick/hud/plane_master.dm @@ -1,4 +1,5 @@ /atom/movable/screen/plane_master + name = "generic plane master" screen_loc = "CENTER" icon_state = "blank" appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR @@ -6,6 +7,22 @@ var/show_alpha = 255 var/hide_alpha = 0 + plane = LOWEST_EVER_PLANE + + //--rendering relay vars-- + ///integer: what plane we will relay this planes render to + var/render_relay_plane = RENDER_PLANE_MASTER + ///bool: Whether this plane should get a render target automatically generated + var/generate_render_target = TRUE + ///integer: blend mode to apply to the render relay in case you dont want to use the plane_masters blend_mode + var/blend_mode_override + ///reference to render relay screen object to avoid backdropping multiple times + var/atom/movable/render_plane_relay/relay + + /// If our plane master has different offsetting logic + /// Possible flags are defined in [_DEFINES/_planes+layers.dm] + var/offsetting_flags = NONE + /atom/movable/screen/plane_master/proc/Show(override) alpha = override || show_alpha @@ -14,48 +31,80 @@ //Why do plane masters need a backdrop sometimes? Read https://secure.byond.com/forum/?post=2141928 //Trust me, you need one. Period. If you don't think you do, you're doing something extremely wrong. -/atom/movable/screen/plane_master/proc/backdrop(mob/mymob) +/atom/movable/screen/plane_master/proc/backdrop(mob/mymob, ourz) + SHOULD_CALL_PARENT(TRUE) + if(!isnull(render_relay_plane)) + relay_render_to_plane(mymob, render_relay_plane, ourz) + /atom/movable/screen/plane_master/floor name = "floor plane master" plane = FLOOR_PLANE appearance_flags = PLANE_MASTER blend_mode = BLEND_OVERLAY + render_relay_plane = RENDER_PLANE_GAME /atom/movable/screen/plane_master/game_world name = "game world plane master" plane = GAME_PLANE appearance_flags = PLANE_MASTER //should use client color blend_mode = BLEND_OVERLAY + render_relay_plane = RENDER_PLANE_GAME /atom/movable/screen/plane_master/game_world/backdrop(mob/mymob) - clear_filters() + . = ..() + remove_filter("ambient_occlusion") + if(mymob.client && mymob.client.get_preference_value(/datum/client_preference/ambient_occlusion) == GLOB.PREF_YES) add_filter("ambient_occlusion", 2, drop_shadow_filter(x=0, y=-2, size=4, color="#04080FAA")) +/atom/movable/screen/plane_master/above_lighting + name = "above lighting plane master" + plane = ABOVE_LIGHTING_PLANE + appearance_flags = PLANE_MASTER //should use client color + blend_mode = BLEND_OVERLAY + render_relay_plane = RENDER_PLANE_GAME + /atom/movable/screen/plane_master/lighting name = "lighting plane master" plane = LIGHTING_PLANE - blend_mode = BLEND_MULTIPLY + //blend_mode = BLEND_MULTIPLY + blend_mode_override = BLEND_MULTIPLY mouse_opacity = MOUSE_OPACITY_TRANSPARENT + render_relay_plane = RENDER_PLANE_GAME /* /atom/movable/screen/plane_master/lighting/backdrop(mob/mymob) + . = ..() mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/lighting_backdrop/lit) mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/lighting_backdrop/unlit) */ -/* -/atom/movable/screen/plane_master/parallax - name = "parallax plane master" - plane = PLANE_SPACE_PARALLAX - mouse_opacity = MOUSE_OPACITY_TRANSPARENT -*/ -/atom/movable/screen/plane_master/parallax_white - name = "parallax whitifier plane master" - plane = PLANE_SPACE + +// /atom/movable/screen/plane_master/parallax +// name = "parallax plane master" +// plane = PLANE_SPACE_PARALLAX +// mouse_opacity = MOUSE_OPACITY_TRANSPARENT +// render_relay_plane = RENDER_PLANE_GAME +// offsetting_flags = BLOCKS_PLANE_OFFSETTING + +// /atom/movable/screen/plane_master/parallax_white +// name = "parallax whitifier plane master" +// plane = PLANE_SPACE +// blend_mode = BLEND_MULTIPLY +// render_relay_plane = RENDER_PLANE_GAME +// offsetting_flags = BLOCKS_PLANE_OFFSETTING /atom/movable/screen/plane_master/open_space_plane name = "open space shadow plane" plane = OPENSPACE_PLANE + appearance_flags = PLANE_MASTER + render_relay_plane = RENDER_PLANE_GAME + +/atom/movable/screen/plane_master/openspace_backdrop + name = "open space backdrop plane master" + plane = OVER_OPENSPACE_PLANE + appearance_flags = PLANE_MASTER + //blend_mode = BLEND_MULTIPLY + render_relay_plane = RENDER_PLANE_GAME /** * Plane master handling byond internal blackness @@ -68,3 +117,71 @@ mouse_opacity = MOUSE_OPACITY_TRANSPARENT blend_mode = BLEND_MULTIPLY appearance_flags = PLANE_MASTER | NO_CLIENT_COLOR | PIXEL_SCALE + //byond internal code end + render_relay_plane = RENDER_PLANE_GAME + + +/atom/movable/screen/plane_master/gravpulse + name = "gravpulse plane" + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + plane = GRAVITY_PULSE_PLANE + render_target = GRAVITY_PULSE_RENDER_TARGET + render_relay_plane = null + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + +/atom/movable/screen/plane_master/gravpulse/backdrop(mob/mymob, ourz) + render_target = "[render_target] #[ourz]" + ..() + +/atom/movable/screen/plane_master/weather + name = "weather plane" + plane = WEATHER_PLANE + render_relay_plane = RENDER_PLANE_GAME + +/atom/movable/screen/plane_master/balloon + name = "balloon chat plane" + plane = BALLOON_CHAT_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_plane = RENDER_PLANE_NON_GAME + +// /atom/movable/screen/plane_master/below_hud +// name = "below hud plane" +// plane = BELOW_HUD_PLANE +// appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR +// render_relay_plane = RENDER_PLANE_NON_GAME +// offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST + +// /atom/movable/screen/plane_master/hud +// name = "hud plane" +// plane = HUD_PLANE +// appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR +// render_relay_plane = RENDER_PLANE_NON_GAME +// offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST + +// /atom/movable/screen/plane_master/above_hud +// name = "above hud plane" +// plane = ABOVE_HUD_PLANE +// appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR +// render_relay_plane = RENDER_PLANE_NON_GAME +// offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST + +/atom/movable/screen/plane_master/runechat + name = "runechat plane" + plane = RUNECHAT_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_plane = RENDER_PLANE_NON_GAME + offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST + +/atom/movable/screen/plane_master/cinema + name = "absolute cinema" + plane = CINEMATIC_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_plane = RENDER_PLANE_NON_GAME + offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST + +/atom/movable/screen/plane_master/fullscreen + name = "fullscreen alert plane" + plane = FULLSCREEN_PLANE + render_relay_plane = RENDER_PLANE_NON_GAME + offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST + diff --git a/code/_onclick/hud/rendering/_render_readme.md b/code/_onclick/hud/rendering/_render_readme.md new file mode 100644 index 00000000000..a2e70340553 --- /dev/null +++ b/code/_onclick/hud/rendering/_render_readme.md @@ -0,0 +1,52 @@ +# The Render Readme + +1. [Byond internal functionality](#byond-internal-functionality) +2. [Known internal snowflake](#known-internal-snowflake) +3. [The rendering solution](#the-rendering-solution) +4. [Render plates](#render-plates) + +## Byond internal functionality +This part of the guide will assume that you have read the byond reference entry for rendering at www.byond.com/docs/ref//#/{notes}/renderer + +When you create an atom, this will always create an internal byond structure called an "appearance". This appearance you will likely be familiar with, as it is exposed through the /atom/var/appearance var. This appearance var holds data on how to render the object, ie what icon/icon_state/color etc it is using. Note that appearance vars will always copy, and do not hold a reference. When you update a var, for example lets pretend we add a filter, the appearance will be updated to include the filter. Note that, however, vis_contents objets are uniquely excluded from appearances. Then, when the filter is updated, the appearance will be recreated, and the atom marked as "dirty". After it has been updated, the SendMaps() function (sometimes also called maptick), which is a internal byond function that iterates over all objects in a clients view and in the clients.mob.contents, checks for "dirty" atoms, then resends any "dirty" appearances to clients as needed and unmarks them as dirty. This function is notoriosly slow, but we can see it's tick usage through the world.map_cpu var. We can also avoid more complex checks checking whether an object is visible on a clients screen by using the TILE_BOUND appearance flag. + +Finally, we arrive at clientside behavior, where we have two main clientside functions: GetMapIcons, and Render. GetMapIcons is repsonsible for actual rendering calculations on the clientside, such as "Group Icons and Set bounds", which performs clientside calculations for transform matrixes. Note that particles here are handled in a seperate thread and are not diplayed in the clientside profiler. Render handles the actual drawing of the screen. + +## Known internal snowflake +The following is an incomplete list of pitfalls that come from byond snowflake that are known, this list is obviously incomplete. + +1. Transforms are very slow on clientside. This is not usually noticable, but if you start using large amounts of them it will grind you to a halt quickly, regardless of whether its on overlays or objs +2. The darkness plane. The darkness plane has specific variables it needs to render correctly, and these can be found in the plane masters file. it is composed internally of two parts, a black mask over the clients screen, and a non rendering mask that blocks all luminosity=0 turfs and their contents from rendering if the SEE_BLACKNESS flag is set properly. It behaves very oddly, such as forcing itself to ALWAYS render or pre-render on blend_multiply blend mode or refusing to render the black mask properly otherwise. The blocker will always block rendering but the mask can be layered under other objects. +3. render_target/source. Render_target/source will only copy certain rendering instructions, and these are only defined as "etc." in the byond reference. Known non copied appearance vars include: blend_mode, plane, layer, vis_contents, mouse_opacity... +4. Large icons on the screen that peek over the edge will instead of only rendering partly like you would expect will instead stretch the screen while not adgusting the render buffer, which means that you can actively see as tiles and map objects are rendered. You can use this for an easy "offscreen" UI. +5. Numerically large filters on objects of any size will torpedo performance, even though large objects with small filters will perform massively better. (ie blur(size=20) BAD) +6. Texture Atlas: the texture atlas byond uses to render icons is very susceptible to corruption and can regularily replace icons with other icons or just not render at all. This can be exasperated by alt tabbing or pausing the dreamseeker process. +7. The renderer is awful code and lummox said he will try changing a large part of it for 515 so keep an eye on that +8. Byond uses DirectX 9 (Lummox said he wants to update to DirectX 11) +9. Particles are just fancy overlays and are not independent of their owner +10. Maptick items inside mob.contents are cheaper compared to most other movables + +## The rendering solution +One of the main issues with making pretty effects is how objects can only render to one plane, and how filters can only be applied to single objects. Quite simply it means we cant apply effects to multiple planes at once, and an effect to one plane only by treating it as a single unit: + +![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/rendering/renderpipe_old.png) + +A semi-fix to stop from having to apply effects to every single plane is to use the render controllers, to automatically apply filters and colors automatically onto their controlled planes. + +The solution is thus instead we replace plane masters rendering directly to client with planes that render multiple planes onto them as objects in order to be able to affect multiple planes while treating them as a single object. This is done by relaying the plane using a "render relay" onto a "render plate" which acts as a plane master of plane masters of sorts, and since planes are rendered onto it as single objects any filters we apply to them will render over the planes, treating them as a single unit. + +![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/rendering/renderpipe_refactored.png) + +We can also choose to render these by decreasing the scaling all applied effects (effect_size/number_of_plates_rendered_to) then rendering it onto multiple planes: + +![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/rendering/renderpipe_refactored_multiple.png) + +Through these this allows us to treat planes as single objects, and lets us distort them as a single unit, most notably works wonders with the displacement filter. Specifically, here you can displacement_filter a plane onto a plate, which then will treat all the other planes rendered on that plate as a single unit. + +## Render plates + +The rendering system uses two objects to unify planes: render_relay and render_plates. Render relays use render_target/source and the relay_render_to_plane proc to replicate the plane master on the render relay. This render relay is then rendered onto a render_plate, which is a plane master that renders the render_relays onto itself. This plate can then be hierachically rendered with the same process until it reaches the master render_plate, which is the plate that will actually render to the player. These plates naturally in the byond style have quirks. For example, rendering to two plates will double any effects such as color or filters, and as such you need to carefully manage how you render them. Keep in mind as well that when sorting the layers for rendering on a plane that they should not be negative, this is handled automatically in relay_render_to_plane. When debugging note that mouse_opacity can act bizzarly with this method, such as only allowing you to click things that are layered over objects on a certain plane but auomatically setting the mouse_opacity should be handling this. Note that if you decide to manipulate a plane with internal byond objects that you will have to manually extrapolate the vars that are set if you want to render them to another plane (See blackness plane for example), and that this is not documented anywhere. + + +Goodluck and godspeed with coding + - Just another contributor diff --git a/code/_onclick/hud/rendering/render_plate.dm b/code/_onclick/hud/rendering/render_plate.dm new file mode 100644 index 00000000000..d71868d89eb --- /dev/null +++ b/code/_onclick/hud/rendering/render_plate.dm @@ -0,0 +1,105 @@ +/*! + * Custom rendering solution to allow for advanced effects + * We (ab)use plane masters and render source/target to cheaply render 2+ planes as 1 + * if you want to read more read the _render_readme.md + */ + + +/** + * Render relay object assigned to a plane master to be able to relay it's render onto other planes that are not it's own + */ +/atom/movable/render_plane_relay + name = "render plate relay" + screen_loc = "CENTER" + layer = -1 + plane = 0 + appearance_flags = PASS_MOUSE | NO_CLIENT_COLOR | KEEP_TOGETHER + +/** + * ## Rendering plate + * + * Acts like a plane master, but for plane masters + * Renders other planes onto this plane, through the use of render objects + * Any effects applied onto this plane will act on the unified plane + * IE a bulge filter will apply as if the world was one object + * remember that once planes are unified on a render plate you cant change the layering of them! + */ +/atom/movable/screen/plane_master/rendering_plate + name = "default rendering plate" + //offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST + +///this plate renders the final screen to show to the player +/atom/movable/screen/plane_master/rendering_plate/master + name = "master rendering plate" + plane = RENDER_PLANE_MASTER + render_relay_plane = null + generate_render_target = FALSE + +// /atom/movable/screen/plane_master/rendering_plate/lighting +// name = "Lighting plate" +// plane = RENDER_PLANE_GAME +// blend_mode_override = BLEND_MULTIPLY +// mouse_opacity = MOUSE_OPACITY_TRANSPARENT +// render_relay_plane = RENDER_PLANE_MASTER + +///renders general in charachter game objects +/atom/movable/screen/plane_master/rendering_plate/game_world + name = "game rendering plate" + plane = RENDER_PLANE_GAME + render_relay_plane = RENDER_PLANE_MASTER + +//applies the contents of the grav pulse plane to this plate, via. their "displaced" outline created by the displacement filter +//atoms with their plane set to GRAV_PULSE_PLANE(and offsets thereof) won't directly render an icon +//but will instead act as a target for this displacement filter to act on, with it instead distorting the plate's contents +//this can be combined with special icons like normal maps to create more subtle distortions +/atom/movable/screen/plane_master/rendering_plate/game_world/backdrop(mob/mymob, ourz) + ..() + var/gravpulse_target = "[GRAVITY_PULSE_RENDER_TARGET] #[ourz]" + add_filter("displacer", 1, displacement_map_filter(render_source = gravpulse_target, size = 10)) + +///render plate for OOC stuff like ghosts, hud-screen effects, etc +/atom/movable/screen/plane_master/rendering_plate/non_game + name = "non-game rendering plate" + plane = RENDER_PLANE_NON_GAME + render_relay_plane = RENDER_PLANE_MASTER + + +/** + * Plane master proc called in backdrop() that creates a relay object, sets it as needed and then adds it to the clients screen + * Sets: + * * layer from plane to avoid z-fighting + * * plane to relay the render to + * * render_source so that the plane will render on this object + * * mouse opacity to ensure proper mouse hit tracking + * * name for debugging purposes + * Other vars such as alpha will automatically be applied with the render source + * Arguments: + * * mymob: mob whose plane is being backdropped + * * relay_plane: plane we are relaying this plane master to + */ +/atom/movable/screen/plane_master/proc/relay_render_to_plane(mob/mymob, relay_plane, ourz) + if(relay && relay?.plane == relay_plane) + return + + // //if we already have a relay & it's already been linked to this plane, stop + // if(relay && relay.plane == relay_plane) + // return + if(!render_target && generate_render_target) + render_target = "*[name]: AUTOGENERATED RENDER TGT #[(ourz)]" + + relay = new() + relay.screen_loc = "SCREEN_SOUTHWEST" + relay.render_source = render_target + relay.plane = calculate_plane(ourz, relay_plane) + relay.layer = (original_plane + abs(LOWEST_EVER_PLANE))*0.5 //layer must be positive but can be a decimal + if(blend_mode_override) + relay.blend_mode = blend_mode_override + else + relay.blend_mode = blend_mode + relay.mouse_opacity = mouse_opacity + relay.name = render_target + mymob.client.screen += relay + //explanation: + //So basically, the darkness plane sucks. + if(blend_mode == BLEND_MULTIPLY) + blend_mode = BLEND_DEFAULT diff --git a/code/_onclick/hud/screen_objects/base_screen_objects.dm b/code/_onclick/hud/screen_objects/base_screen_objects.dm index cd645c38f36..3ea8b5dc03d 100644 --- a/code/_onclick/hud/screen_objects/base_screen_objects.dm +++ b/code/_onclick/hud/screen_objects/base_screen_objects.dm @@ -22,9 +22,10 @@ var/hideflag = 0 var/list/image/ovrls = list() -/atom/movable/screen/New(_name = "unnamed", mob/living/_parentmob, _icon, _icon_state)//(_name = "unnamed", _screen_loc = "7,7", mob/living/_parentmob, _icon, _icon_state) +/atom/movable/screen/New(_name, mob/living/_parentmob, _icon, _icon_state)//(_name = "unnamed", _screen_loc = "7,7", mob/living/_parentmob, _icon, _icon_state) src.parentmob = _parentmob - src.name = _name + if(_name) + src.name = _name // src.screen_loc = _screen_loc if (_icon) src.icon = _icon @@ -1524,10 +1525,14 @@ name = "" layer = HUD_LAYER -/atom/movable/screen/frippery/New(_icon_state,_screen_loc = "7,7", mob/living/_parentmob) +/atom/movable/screen/frippery/New(_icon_state,_screen_loc = "7,7", mob/living/_parentmob, _plane, _layer) src.parentmob = _parentmob src.screen_loc = _screen_loc src.icon_state = _icon_state + if(_plane) + set_plane(_plane) + if(_layer) + layer = _layer /atom/movable/screen/glasses_overlay icon = null diff --git a/code/datums/datum_hud.dm b/code/datums/datum_hud.dm index 4213fc08a7d..91536d7e17b 100644 --- a/code/datums/datum_hud.dm +++ b/code/datums/datum_hud.dm @@ -18,6 +18,7 @@ var/list/atom/movable/screen/openspace_overlay/openspace_overlays = list() var/atom/movable/screen/vis_holder/vis_holder + var/list/our_relays = list() /datum/hud/proc/updatePlaneMasters(mob/mymob) if(!mymob || !mymob.client) @@ -54,22 +55,36 @@ mymob.client.screen -= instance qdel(instance) + for(var/relay in our_relays) + var/atom/movable/render_plane_relay/instance = relay + mymob.client.screen -= instance + qdel(instance) + openspace_overlays.Cut() + our_relays.Cut() if(!LD) return; - var/local_z = z-(LD.original_level-1) + //we stow it here so we can adjust it later + var/list/ourtypes = subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/rendering_plate + for(var/zi in 1 to local_z) - for(var/mytype in subtypesof(/atom/movable/screen/plane_master)) - var/atom/movable/screen/plane_master/instance = new mytype() + for(var/mytype in ourtypes) + var/atom/movable/screen/plane_master/instance = new mytype(null, mymob) + if(instance.offsetting_flags & BLOCKS_PLANE_OFFSETTING) + ourtypes.Remove(mytype)//only do one iteration of this type - instance.plane = calculate_plane(zi,instance.plane) + //if match highest is on, always map to highest(local) z + //if block plane offsetting is on -without- match highest, always map to base z. + //otherwise, continue with current z. + var/plane_z = ((instance.offsetting_flags & OFFSET_RELAYS_MATCH_HIGHEST) ? local_z : (instance.offsetting_flags & OFFSET_RELAYS_MATCH_HIGHEST) ? 1 : zi) + instance.plane = calculate_plane(plane_z,instance.plane) plane_masters["[zi]-[mytype]"] = instance mymob.client.screen += instance - instance.backdrop(mymob) + instance.backdrop(mymob, zi) for(var/pl in list(GAME_PLANE,FLOOR_PLANE)) if(zi < local_z) @@ -81,6 +96,10 @@ openspace_overlays["[zi]-[oover.plane]"] = oover mymob.client.screen += oover + for(var/master as anything in plane_masters) + var/atom/movable/screen/plane_master/thamaster = plane_masters[master] + if(thamaster.relay && !our_relays.Find(thamaster.relay)) + our_relays += thamaster.relay /mob/update_plane() ..() @@ -195,7 +214,15 @@ list("loc" = "EAST+1,BOTTOM+2:25", "icon_state" = "frame3-3"), list("loc" = "EAST+1,BOTTOM+2:25", "icon_state" = "frame0-4"), list("loc" = "EAST+1,BOTTOM+8:14", "icon_state" = "frame0-1"), - list("loc" = "EAST+1,BOTTOM+8:14", "icon_state" = "frame3-1") + list("loc" = "EAST+1,BOTTOM+8:14", "icon_state" = "frame3-1"), + //screen border elements + list("loc" = "EAST+1,BOTTOM+14 to EAST+1, BOTTOM+2", "icon_state" = "veneer_vertical", "plane" = HUD_PLANE, "layer" = BELOW_HUD_LAYER), + list("loc" = "EAST+1,BOTTOM+15", "icon_state" = "veneer_vertical_top", "plane" = HUD_PLANE, "layer" = BELOW_HUD_LAYER), + list("loc" = "EAST+1,BOTTOM+1", "icon_state" = "veneer_vertical_bottom", "plane" = HUD_PLANE, "layer" = BELOW_HUD_LAYER), + list("loc" = "EAST+1,BOTTOM", "icon_state" = "veneer_corner", "plane" = HUD_PLANE, "layer" = BELOW_HUD_LAYER), + list("loc" = "EAST,BOTTOM", "icon_state" = "veneer_horizontal_right", "plane" = BELOW_HUD_PLANE, "layer" = BELOW_HUD_LAYER), + list("loc" = "EAST-13,BOTTOM to EAST-2, BOTTOM", "icon_state" = "veneer_horizontal", "plane" = HUD_PLANE, "layer" = BELOW_HUD_LAYER), + list("loc" = "EAST-14, BOTTOM", "icon_state" = "veneer_horizontal_left", "plane" = HUD_PLANE, "layer" = BELOW_HUD_LAYER) ) //list("loc" = "2,3", "icon_state" = "block", "hideflag" = TOGGLE_INVENTORY_FLAG), @@ -231,7 +258,6 @@ var/image/I = IconUnderlays[p] I.alpha = 200 - /datum/hud/human/liberty name = "LibertyStyle" icon = 'icons/mob/screen/LibertyStyle.dmi' diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 92d451c92bc..8a624251bd4 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -950,3 +950,4 @@ /// Called after we wrench/unwrench this object /obj/proc/wrenched_change() return + diff --git a/code/game/gamemodes/events/weather.dm b/code/game/gamemodes/events/weather.dm index f6e08182c3a..416e6497868 100644 --- a/code/game/gamemodes/events/weather.dm +++ b/code/game/gamemodes/events/weather.dm @@ -115,7 +115,7 @@ for(var/V in affectareas) var/area/N = V N.layer = overlay_layer - N.plane = 150 + N.set_plane(WEATHER_PLANE) N.icon = 'icons/effects/weather_effects.dmi' N.color = weather_color N.alpha = 128 diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm index 86ac0418e9b..b1b585d6c86 100644 --- a/code/game/objects/effects/decals/Cleanable/misc.dm +++ b/code/game/objects/effects/decals/Cleanable/misc.dm @@ -212,7 +212,7 @@ desc = "A graffiti." density = FALSE anchored = TRUE - plane = -1 + plane = FLOOR_PLANE icon = 'icons/effects/wall_graffiti.dmi' icon_state = "kot" random_rotation = 0 diff --git a/code/game/objects/effects/temporary_visual.dm b/code/game/objects/effects/temporary_visual.dm index ee60d577dfd..21a4c5e2d34 100644 --- a/code/game/objects/effects/temporary_visual.dm +++ b/code/game/objects/effects/temporary_visual.dm @@ -38,3 +38,4 @@ /obj/effect/temp_visual/long //temp visual with longer duration randomdir = FALSE duration = 25 + diff --git a/code/game/objects/items/weapons/tools/_tools.dm b/code/game/objects/items/weapons/tools/_tools.dm index 30dbf0ed5b1..e075ec1fa71 100644 --- a/code/game/objects/items/weapons/tools/_tools.dm +++ b/code/game/objects/items/weapons/tools/_tools.dm @@ -27,6 +27,7 @@ health = 600 maxHealth = 600 + appearance_flags = TILE_BOUND|PIXEL_SCALE|LONG_GLIDE|KEEP_TOGETHER var/tool_in_use = FALSE var/force_upgrade_mults = 1 @@ -987,7 +988,7 @@ var/safety = H.eyecheck() if(safety <= FLASH_PROTECTION_REDUCED) to_chat(H, span_danger("Your equipment intensify the welder's glow. Your eyes itch and burn severely.")) - H.eye_hazy += rand(2,6) + H.eye_hazy += rand(4,8) H.eye_blurry += rand(12,20) E.take_damage(rand(16, 20)) else if(safety <= FLASH_PROTECTION_NONE) @@ -995,7 +996,7 @@ E.take_damage(rand(8, 12), BURN) if(E.damage > 10) E.take_damage(rand(4, 12)) - H.eye_hazy += rand(1,3) + H.eye_hazy += rand(4,5) H.eye_blurry += rand(4,8) else if(safety <= FLASH_PROTECTION_MINOR) to_chat(H, span_warning("The searing light burns your eyes through your insufficient protection.")) diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm index 3b33644bcff..4dcf3818d14 100644 --- a/code/modules/holodeck/HolodeckControl.dm +++ b/code/modules/holodeck/HolodeckControl.dm @@ -275,7 +275,7 @@ holographic_objs = A.copy_contents_to(linkedholodeck , 0) for(var/obj/holo_obj in holographic_objs) holo_obj.alpha *= 0.9 //give holodeck objs a slight transparency - holo_obj.plane = 63 //This makes all objects load on the plane that Eris's 3rd z-level uses for objects. This is not dynamic. + holo_obj.plane = 60 //This makes all objects load on the plane that Eris's 3rd z-level uses for objects. This is not dynamic. if(HP.ambience) linkedholodeck.forced_ambience = HP.ambience diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 9698ab5762b..f99eb1c888f 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -1,4 +1,5 @@ /mob/living/carbon/human + appearance_flags = TILE_BOUND|PIXEL_SCALE|LONG_GLIDE|KEEP_TOGETHER name = "unknown" real_name = "unknown" voice_name = "unknown" diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 289b3a56a7d..601f6f40bd2 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -120,13 +120,13 @@ /mob/living/carbon/human/reset_layer() /// The forklift handles it for us here. if(istype(loc, /obj/item/mech_equipment/forklifting_system)) - if(lying) set_plane(LYING_HUMAN_PLANE) + if(lying) set_plane(LYING_MOB_PLANE) return if(hiding) - set_plane(HIDING_MOB_PLANE) + set_plane(LYING_MOB_PLANE) layer = HIDING_MOB_LAYER else if(lying) - set_plane(LYING_HUMAN_PLANE) + set_plane(LYING_MOB_PLANE) layer = LYING_HUMAN_LAYER else ..() diff --git a/code/modules/mob/living/carbon/human/human_hud.dm b/code/modules/mob/living/carbon/human/human_hud.dm index 6fc4226356f..74e7a986a0b 100644 --- a/code/modules/mob/living/carbon/human/human_hud.dm +++ b/code/modules/mob/living/carbon/human/human_hud.dm @@ -194,7 +194,7 @@ for (var/list/whistle in HUDdatum.HUDfrippery) - var/atom/movable/screen/frippery/F = new (whistle["icon_state"],whistle["loc"],H) + var/atom/movable/screen/frippery/F = new (whistle["icon_state"],whistle["loc"],H, whistle["plane"], whistle["layer"]) F.icon = HUDdatum.icon if(whistle["hideflag"]) F.hideflag = whistle["hideflag"] diff --git a/code/modules/mob/living/carbon/shock.dm b/code/modules/mob/living/carbon/shock.dm index 8be83698a0e..c22eadf7759 100644 --- a/code/modules/mob/living/carbon/shock.dm +++ b/code/modules/mob/living/carbon/shock.dm @@ -126,7 +126,7 @@ //haze warning for imminent paincrit if(shock_stage >= hard_crit_threshold * 0.90) if(prob(10)) - eye_hazy += 5 + eye_hazy += 6 if(shock_stage >= hard_crit_threshold) enter_hard_crit() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 2fbe26be3fb..afc32721f5d 100755 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -765,7 +765,7 @@ default behaviour is: /mob/living/reset_layer() if(hiding) - set_plane(HIDING_MOB_PLANE) + set_plane(LYING_MOB_PLANE) layer = HIDING_MOB_LAYER else ..() diff --git a/code/modules/mob/observer/freelook/chunk.dm b/code/modules/mob/observer/freelook/chunk.dm index ff6395f568c..518bc761300 100644 --- a/code/modules/mob/observer/freelook/chunk.dm +++ b/code/modules/mob/observer/freelook/chunk.dm @@ -102,8 +102,8 @@ var/turf/t = turf if(obscuredTurfs[t]) if(!t.obfuscations[obfuscation.type]) - var/image/I = image(obfuscation.icon, t, obfuscation.icon_state, BYOND_LIGHTING_LAYER+0.1) - I.plane = t.get_relative_plane(BYOND_LIGHTING_PLANE) + var/image/I = image(obfuscation.icon, t, obfuscation.icon_state, BYOND_LIGHTING_LAYER) + I.plane = t.get_relative_plane(ABOVE_LIGHTING_PLANE) t.obfuscations[obfuscation.type] = I obscured += t.obfuscations[obfuscation.type] @@ -143,8 +143,8 @@ for(var/turf in obscuredTurfs) var/turf/t = turf if(!t.obfuscations[obfuscation.type]) - var/image/I = image(obfuscation.icon, t, obfuscation.icon_state, BYOND_LIGHTING_LAYER+0.1) - I.plane = t.get_relative_plane(BYOND_LIGHTING_PLANE) + var/image/I = image(obfuscation.icon, t, obfuscation.icon_state, BYOND_LIGHTING_LAYER) + I.plane = t.get_relative_plane(ABOVE_LIGHTING_PLANE) t.obfuscations[obfuscation.type] = I obscured += t.obfuscations[obfuscation.type] diff --git a/code/modules/mob/observer/ghost/ghost.dm b/code/modules/mob/observer/ghost/ghost.dm index d4fc2196fab..dfb1e40301e 100755 --- a/code/modules/mob/observer/ghost/ghost.dm +++ b/code/modules/mob/observer/ghost/ghost.dm @@ -70,7 +70,7 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images var/turf/T = pick_spawn_location("Observer") if(istype(T)) src.forceMove(T) - + plane = ABOVE_LIGHTING_PLANE //ghosts aren't real dummy if(!name) //To prevent nameless ghosts name = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) real_name = name diff --git a/code/modules/mob/observer/observer.dm b/code/modules/mob/observer/observer.dm index 9278464f0c0..db39fa8b694 100644 --- a/code/modules/mob/observer/observer.dm +++ b/code/modules/mob/observer/observer.dm @@ -19,7 +19,7 @@ var/const/GHOST_IMAGE_ALL = ~GHOST_IMAGE_NONE return FALSE /mob/observer/New() - ..() + . = ..() ghost_image = image(src.icon,src) ghost_image.appearance = src ghost_image.appearance_flags = RESET_ALPHA @@ -29,6 +29,7 @@ var/const/GHOST_IMAGE_ALL = ~GHOST_IMAGE_NONE ghost_sightless_images |= ghost_image //so ghosts can see the eye when they disable ghost sight updateallghostimages() + /mob/observer/Destroy() if (ghost_image) ghost_darkness_images -= ghost_image diff --git a/code/modules/multiz/planes.dm b/code/modules/multiz/planes.dm index 1fd95a54569..7a55ab3b27b 100644 --- a/code/modules/multiz/planes.dm +++ b/code/modules/multiz/planes.dm @@ -17,10 +17,13 @@ if(LD != null) return min(32767,((z-LD.original_level)*PLANES_PER_Z_LEVEL) + original_plane) -/atom/proc/update_plane() //Updates plane using local z-coordinate +///Updates plane using local z-coordinate. +/atom/proc/update_plane() if(z > 0) plane = calculate_plane(z,original_plane) - else + else if(ismovable(loc) && loc.z > 0)//are we inside something's vis contents or something like that? + plane = calculate_plane(loc.z,original_plane) + else//otherwise, just give up plane = ABOVE_HUD_PLANE /atom/proc/get_relative_plane(plane) diff --git a/code/modules/organs/internal/internal_organ_processes.dm b/code/modules/organs/internal/internal_organ_processes.dm index 69b96a3ec83..c4f312d4cac 100644 --- a/code/modules/organs/internal/internal_organ_processes.dm +++ b/code/modules/organs/internal/internal_organ_processes.dm @@ -165,17 +165,17 @@ status_flags &= ~BLEEDOUT if(blood_volume < 1) - eye_hazy = max(eye_hazy,6) + eye_hazy = max(eye_hazy,10) adjustOxyLoss(20) if(prob(15)) to_chat(src, span_warning("You feel extremely [pick("dizzy","woosey","faint")].")) else if(blood_volume < total_blood_req) - eye_blurry = max(eye_hazy,4) + eye_blurry = max(eye_hazy,6) adjustOxyLoss(4.5) // this damage threshold kills people with good airflow if(prob(15)) to_chat(src, span_warning("You feel highly [pick("dizzy","woosey","faint")].")) else if(blood_volume < blood_bad) - eye_blurry = max(eye_blurry,6) + eye_blurry = max(eye_blurry,8) adjustOxyLoss(2) if(prob(15)) to_chat(src, span_warning("You feel very [pick("dizzy","woosey","faint")].")) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 7aeb7762530..172b30b748c 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -32,6 +32,7 @@ health = 600 maxHealth = 600 + appearance_flags = TILE_BOUND|PIXEL_SCALE|LONG_GLIDE|KEEP_TOGETHER var/list/custom_default = list() // used to preserve changes to stats past refresh_upgrades proccing var/damage_multiplier = 1 //Multiplies damage of projectiles fired from this gun var/halloss_multiplier = 1 //Multiplies agony damage of projectiles fired from this gun diff --git a/icons/effects/light_overlays/light_128.dmi b/icons/effects/light_overlays/light_128.dmi new file mode 100644 index 00000000000..22dc0b01087 Binary files /dev/null and b/icons/effects/light_overlays/light_128.dmi differ diff --git a/icons/effects/light_overlays/light_160.dmi b/icons/effects/light_overlays/light_160.dmi new file mode 100644 index 00000000000..26dfa453c51 Binary files /dev/null and b/icons/effects/light_overlays/light_160.dmi differ diff --git a/icons/effects/light_overlays/light_192.dmi b/icons/effects/light_overlays/light_192.dmi new file mode 100644 index 00000000000..aca94ee0caf Binary files /dev/null and b/icons/effects/light_overlays/light_192.dmi differ diff --git a/icons/effects/light_overlays/light_224.dmi b/icons/effects/light_overlays/light_224.dmi new file mode 100644 index 00000000000..9fab531d1a6 Binary files /dev/null and b/icons/effects/light_overlays/light_224.dmi differ diff --git a/icons/effects/light_overlays/light_256.dmi b/icons/effects/light_overlays/light_256.dmi new file mode 100644 index 00000000000..701562efcd8 Binary files /dev/null and b/icons/effects/light_overlays/light_256.dmi differ diff --git a/icons/effects/light_overlays/light_288.dmi b/icons/effects/light_overlays/light_288.dmi new file mode 100644 index 00000000000..b6eac180f7a Binary files /dev/null and b/icons/effects/light_overlays/light_288.dmi differ diff --git a/icons/effects/light_overlays/light_32.dmi b/icons/effects/light_overlays/light_32.dmi new file mode 100644 index 00000000000..5269b1fba36 Binary files /dev/null and b/icons/effects/light_overlays/light_32.dmi differ diff --git a/icons/effects/light_overlays/light_320.dmi b/icons/effects/light_overlays/light_320.dmi new file mode 100644 index 00000000000..bf263c4b29b Binary files /dev/null and b/icons/effects/light_overlays/light_320.dmi differ diff --git a/icons/effects/light_overlays/light_352.dmi b/icons/effects/light_overlays/light_352.dmi new file mode 100644 index 00000000000..f895792da42 Binary files /dev/null and b/icons/effects/light_overlays/light_352.dmi differ diff --git a/icons/effects/light_overlays/light_64.dmi b/icons/effects/light_overlays/light_64.dmi new file mode 100644 index 00000000000..37fc5084abc Binary files /dev/null and b/icons/effects/light_overlays/light_64.dmi differ diff --git a/icons/effects/light_overlays/light_96.dmi b/icons/effects/light_overlays/light_96.dmi new file mode 100644 index 00000000000..b689a137016 Binary files /dev/null and b/icons/effects/light_overlays/light_96.dmi differ diff --git a/icons/effects/light_overlays/normalmap_bumpy.dmi b/icons/effects/light_overlays/normalmap_bumpy.dmi new file mode 100644 index 00000000000..f9a2a31c3bc Binary files /dev/null and b/icons/effects/light_overlays/normalmap_bumpy.dmi differ diff --git a/icons/effects/light_overlays/normalmap_shockwave.dmi b/icons/effects/light_overlays/normalmap_shockwave.dmi new file mode 100644 index 00000000000..c22acfa1d59 Binary files /dev/null and b/icons/effects/light_overlays/normalmap_shockwave.dmi differ diff --git a/icons/effects/light_overlays/normalmaps_256.dmi b/icons/effects/light_overlays/normalmaps_256.dmi new file mode 100644 index 00000000000..4e15cfd936a Binary files /dev/null and b/icons/effects/light_overlays/normalmaps_256.dmi differ diff --git a/icons/mob/screen/ErisStyleHolo.dmi b/icons/mob/screen/ErisStyleHolo.dmi index 5cdcb2e3c9d..2561cba9b4e 100644 Binary files a/icons/mob/screen/ErisStyleHolo.dmi and b/icons/mob/screen/ErisStyleHolo.dmi differ