From 2dd9152d967be545421a3254ce3c7afc2ce441cc Mon Sep 17 00:00:00 2001 From: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> Date: Sat, 8 Mar 2025 21:53:32 +0100 Subject: [PATCH 1/2] 516 Renderer update --- code/ZAS/Fire.dm | 7 + code/ZAS/Zone.dm | 14 +- code/__DEFINES/atmos.dm | 5 + code/__DEFINES/layers.dm | 5 + code/__HELPERS/global_lists.dm | 7 + code/_onclick/hud/rendering/_renderer.dm | 256 +++++++++++++----- code/defines/gases.dm | 2 + code/game/machinery/atmoalter/canister.dm | 6 + code/game/objects/items/camping.dm | 11 +- code/game/turfs/simulated.dm | 2 - .../effects/particles/native_particles.dm | 101 +++++++ code/modules/mob/login.dm | 2 +- code/modules/mob/logout.dm | 2 +- code/modules/xgm/xgm_gas_data.dm | 69 +++-- code/modules/xgm/xgm_gas_mixture.dm | 83 ++++-- html/changelogs/fluffyghost-516renderer.yml | 60 ++++ icons/effects/particles.dmi | Bin 0 -> 2054 bytes icons/effects/tile_effects.dmi | Bin 4874 -> 6727 bytes 18 files changed, 517 insertions(+), 115 deletions(-) create mode 100644 html/changelogs/fluffyghost-516renderer.yml create mode 100644 icons/effects/particles.dmi diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index 708721dfec3..afa7507f1c5 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -118,6 +118,13 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin return 0 +/obj/heat + icon = 'icons/effects/fire.dmi' + icon_state = "3" + appearance_flags = PIXEL_SCALE | NO_CLIENT_COLOR + render_target = HEAT_EFFECT_TARGET + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + /obj/fire //Icon for fire on turfs. diff --git a/code/ZAS/Zone.dm b/code/ZAS/Zone.dm index 9affbfa503d..b1097b16a8a 100644 --- a/code/ZAS/Zone.dm +++ b/code/ZAS/Zone.dm @@ -53,6 +53,9 @@ Class Procs: var/datum/gas_mixture/air = new + var/list/graphic_add = list() + var/list/graphic_remove = list() + /zone/New() SSair.add_zone(src) air.temperature = TCMB @@ -148,21 +151,20 @@ Class Procs: air.group_multiplier = contents.len+1 /zone/proc/tick() + // Update fires. if(air.temperature >= PHORON_FLASHPOINT && !(src in SSair.active_fire_zones) && air.check_combustability() && contents.len) var/turf/T = pick(contents) if(istype(T)) T.create_fire(GLOB.vsc.fire_firelevel_multiplier) - var/world_time_counter = world.time - var/list/graphic_add = list() - var/list/graphic_remove = list() + // Update gas overlays. if(air.check_tile_graphic(graphic_add, graphic_remove)) for(var/turf/simulated/T in contents) T.update_graphic(graphic_add, graphic_remove) - var/delta_time = world.time - world_time_counter - if(delta_time > 5 SECONDS) - log_admin("AN AREA IS TAKING EXTREMELY LONG TO UPDATE: [name] WITH CONTENTS LENGTH [length(contents)] TELL MATT WITH THE ROUND ID!") + graphic_add.Cut() + graphic_remove.Cut() + // Update connected edges. for(var/connection_edge/E in edges) if(E.sleeping) E.recheck() diff --git a/code/__DEFINES/atmos.dm b/code/__DEFINES/atmos.dm index ae6f22c4f8d..e9b462b81a3 100644 --- a/code/__DEFINES/atmos.dm +++ b/code/__DEFINES/atmos.dm @@ -49,6 +49,9 @@ #define CARBON_LIFEFORM_FIRE_RESISTANCE (T0C + 200) #define CARBON_LIFEFORM_FIRE_DAMAGE 4 +#define FOGGING_TEMPERATURE (T0C + 5) +#define MAX_FOG_TEMPERATURE (T0C - 50) + // Phoron fire properties. #define PHORON_MINIMUM_BURN_TEMPERATURE (T0C + 126) //400 K - autoignite temperature in tanks and canisters - enclosed environments I guess #define PHORON_FLASHPOINT (T0C + 246) //519 K - autoignite temperature in air if that ever gets implemented. @@ -122,6 +125,8 @@ #define GAS_DEUTERIUM "deuterium" #define GAS_TRITIUM "tritium" #define GAS_BORON "boron" +#define GAS_HEAT "heat" //Not a real gas, used for visual effects +#define GAS_COLD "cold" //Not a real gas, used for visual effects #define PIPE_COLOR_GREY "#ffffff" //yes white is grey #define PIPE_COLOR_RED "#ff0000" diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index cd4bff185f1..d79d51ec91e 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -36,6 +36,11 @@ #define OVER_OPENSPACE_PLANE -4 +#define HEAT_EFFECT_PLANE -4 +#define HEAT_EFFECT_TARGET "*heat" +#define COLD_EFFECT_TARGET "*cold" +#define COLD_EFFECT_BACK_TARGET "*coldb" +#define HEAT_COMPOSITE_TARGET "*heatc" #define WARP_EFFECT_PLANE -3 #define BLACKNESS_PLANE 0 //Blackness plane as per DM documentation. diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 8194a0b7fff..1f715579bfe 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -133,6 +133,8 @@ GLOBAL_LIST_EMPTY(contained_clothing_species_adaption_cache) /// Cache for outfit selection. GLOBAL_LIST_EMPTY(outfit_cache) +GLOBAL_LIST_EMPTY(all_particles) + ////////////////////////// /////Initial Building///// ////////////////////////// @@ -240,6 +242,11 @@ GLOBAL_LIST_EMPTY(outfit_cache) if(S.spawn_flags & IS_WHITELISTED) GLOB.whitelisted_species += S.name + paths = typesof(/particles) + for (var/path in paths) + var/particles/P = new path() + GLOB.all_particles[P.name] = P + return TRUE GLOBAL_LIST_INIT(correct_punctuation, list("!" = TRUE, "." = TRUE, "?" = TRUE, "-" = TRUE, "~" = TRUE, \ diff --git a/code/_onclick/hud/rendering/_renderer.dm b/code/_onclick/hud/rendering/_renderer.dm index 51b8274562e..a4b0153dce0 100644 --- a/code/_onclick/hud/rendering/_renderer.dm +++ b/code/_onclick/hud/rendering/_renderer.dm @@ -7,13 +7,23 @@ * visual effects. */ +/// Add one instance of this renderer on mob/Login with no special setup +#define RENDERER_FLAG_AUTO BITFLAG(1) + +/// This renderer can be used with mob/AddRenderer & mob/RemoveRenderer +#define RENDERER_FLAG_OPTIONAL BITFLAG(2) + + /// The base /renderer definition and defaults. ABSTRACT_TYPE(/atom/movable/renderer) appearance_flags = DEFAULT_RENDERER_APPEARANCE_FLAGS - screen_loc = "CENTER" + screen_loc = "1,1" plane = LOWEST_PLANE blend_mode = BLEND_OVERLAY + /// A bitfield of RENDERER_* defines. + var/renderer_flags = NONE + /// The compositing renderer this renderer belongs to. var/group = RENDER_GROUP_FINAL @@ -23,21 +33,20 @@ ABSTRACT_TYPE(/atom/movable/renderer) /// Optional blend mode override for the renderer's composition relay. var/relay_blend_mode - /// If text, uses the text or, if TRUE, uses "*AUTO-[name]" + /// If text, uses the text or, if TRUE, uses "*AUTO-[name]". var/render_target_name = TRUE - var/mob/owner = null + /// When not shared, the mob associated with this renderer. + var/mob/owner /atom/movable/renderer/Destroy() - owner = null QDEL_NULL(relay) + owner = null return ..() INITIALIZE_IMMEDIATE(/atom/movable/renderer) - - /atom/movable/renderer/Initialize(mapload, mob/owner) . = ..() if (. == INITIALIZE_HINT_QDEL) @@ -51,8 +60,10 @@ INITIALIZE_IMMEDIATE(/atom/movable/renderer) render_target = render_target_name else if (render_target_name) render_target = "*[ckey(name)]" + if (owner.client?.byond_version < 516) + screen_loc = "CENTER" relay = new - relay.screen_loc = "CENTER" + relay.screen_loc = screen_loc relay.appearance_flags = PASS_MOUSE | NO_CLIENT_COLOR | KEEP_TOGETHER relay.name = "[render_target] relay" relay.mouse_opacity = mouse_opacity @@ -64,10 +75,11 @@ INITIALIZE_IMMEDIATE(/atom/movable/renderer) else relay.blend_mode = relay_blend_mode + /** * Graphic preferences -* -* Some renderers may be able to use a graphic preference to determine how to display effects. For example reduce particle counts or filter variables. +* Some renderers may be able to use a graphic preference to determine how to display effects. +* For example reduce particle counts or filter variables. */ /atom/movable/renderer/proc/GraphicsUpdate() return @@ -81,111 +93,155 @@ INITIALIZE_IMMEDIATE(/atom/movable/renderer) * to share them globally. */ -/// The list of renderers associated with this mob. -/mob/var/list/atom/movable/renderer/renderers +/// A map of (instance = plane) renderers in use by this mob. +/mob/var/list/atom/movable/renderer/renderer_plane_map + +/// A map of (type = instance) renderers in use by this mob. +/mob/var/list/atom/movable/renderer/path_renderer_map /// Creates the mob's renderers on /Login() -/mob/proc/CreateRenderers() - if (!renderers) - renderers = list() - for (var/renderer as anything in subtypesof(/atom/movable/renderer)) - if(ispath(renderer, /atom/movable/renderer/shared)) - continue - var/atom/movable/renderer/render = new renderer (null, src) - renderers["[render.plane]"] = render // (render = plane) format for visual debugging - if (render.relay) - my_client.screen += render.relay - my_client.screen += render - - for (var/atom/movable/renderer/zrenderer as anything in GLOB.zmimic_renderers) - if (zrenderer.relay) - my_client.screen += zrenderer.relay - my_client.screen += zrenderer +/mob/proc/AddDefaultRenderers() + if (renderer_plane_map) + ClearRenderers() + renderer_plane_map = list() + path_renderer_map = list() + for (var/atom/movable/renderer/renderer as anything in subtypesof(/atom/movable/renderer)) + if (initial(renderer.renderer_flags) & RENDERER_FLAG_AUTO) + renderer = new renderer(null, src) + renderer_plane_map[renderer] = renderer.plane + path_renderer_map[renderer.type] = renderer + if (renderer.relay) + my_client.screen += renderer.relay + my_client.screen += renderer + var/list/zmimic_renderers = list() + path_renderer_map[/atom/movable/renderer/zmimic] = zmimic_renderers + for (var/i = 0 to OPENTURF_MAX_DEPTH) + var/atom/movable/renderer/zmimic/renderer = new (null, src, OPENTURF_MAX_PLANE - i) + renderer_plane_map[renderer] = renderer.plane + zmimic_renderers += renderer + if (renderer.relay) + my_client.screen += renderer.relay + my_client.screen += renderer + /// Removes the mob's renderers on /Logout() -/mob/proc/RemoveRenderers() - if(my_client) - for(var/renderer as anything in renderers) - var/atom/movable/renderer/render = renderers[renderer] - my_client.screen -= render - if (render.relay) - my_client.screen -= render.relay - qdel(render) - for (var/atom/movable/renderer/renderer as anything in GLOB.zmimic_renderers) +/mob/proc/ClearRenderers() + if (my_client) + for (var/atom/movable/renderer/renderer as anything in renderer_plane_map) + if (renderer.relay) + my_client.screen -= renderer.relay my_client.screen -= renderer - if (renderers) - renderers.Cut() + qdel(renderer) + renderer_plane_map = null + path_renderer_map = null + + +/// Returns the renderer instance of_type if the mob has one and it is not shared. +/mob/proc/GetRenderer(atom/movable/renderer/of_type) + if (!my_client) + return + return path_renderer_map[of_type] + + +/// Adds a non-main renderer to the mob by type if the mob doesn't already have it. +/mob/proc/AddRenderer(atom/movable/renderer/of_type) + if (!my_client) + return + if (~initial(of_type.renderer_flags) & RENDERER_FLAG_OPTIONAL) + return + if (of_type in path_renderer_map) + return + var/atom/movable/renderer/renderer = new of_type (null, src) + if (renderer.relay) + my_client.screen += renderer.relay + my_client.screen += renderer + renderer_plane_map[renderer] = renderer.plane + path_renderer_map[of_type] = renderer + return renderer + + +/// Removes a non-main renderer to the mob by type. +/mob/proc/RemoveRenderer(atom/movable/renderer/of_type) + if (!my_client) + return + if (~initial(of_type.renderer_flags) & RENDERER_FLAG_OPTIONAL) + return + if (!length(path_renderer_map)) + return + var/atom/movable/renderer/renderer = path_renderer_map[of_type] + if (!renderer) + return + if (renderer.relay) + my_client.screen -= renderer.relay + my_client.screen -= renderer + path_renderer_map -= of_type + renderer_plane_map -= renderer + qdel(renderer) + /* * * Plane Renderers * We treat some renderers as planes with layers. When some atom has the same plane * as a Plane Renderer, it is drawn by that renderer. The layer of the atom determines * its draw order within the scope of the renderer. The draw order of same-layered things -* is probably by atom contents order, but can be assumed not to matter - if it's out of -* order, it should have a more appropriate layer value. +* is probably by atom contents order, but can be assumed not to matter - if it's visibly +* incorrect, it should have a more appropriate layer value. * Higher plane values are composited over lower. Here, they are ordered from under to over. */ -/// Handles byond internal letterboxing. Avoid touching. + + /// Handles byond internal letterboxing. Avoid touching. /atom/movable/renderer/letterbox name = "Letterbox" group = RENDER_GROUP_SCENE plane = BLACKNESS_PLANE blend_mode = BLEND_MULTIPLY mouse_opacity = MOUSE_OPACITY_TRANSPARENT + renderer_flags = RENDERER_FLAG_AUTO + /atom/movable/renderer/space name = "Space" group = RENDER_GROUP_SCENE plane = SPACE_PLANE + renderer_flags = RENDERER_FLAG_AUTO + /atom/movable/renderer/skybox name = "Skybox" group = RENDER_GROUP_SCENE plane = SKYBOX_PLANE relay_blend_mode = BLEND_MULTIPLY + renderer_flags = RENDERER_FLAG_AUTO -//Z Mimic planemasters -> Could apply scaling for parallax though that requires copying appearances from adjacent turfs -GLOBAL_LIST_EMPTY(zmimic_renderers) - -/hook/startup/proc/create_global_renderers() //Some (most) renderers probably do not need to be instantiated per mob. So may as well make them global and just add to screen - //Zmimic planemasters - for(var/i = 0 to OPENTURF_MAX_DEPTH) - GLOB.zmimic_renderers += new /atom/movable/renderer/shared/zmimic(null, null, OPENTURF_MAX_PLANE - i) - return TRUE - -/atom/movable/renderer/shared/zmimic +/atom/movable/renderer/zmimic name = "Zrenderer" group = RENDER_GROUP_SCENE -/atom/movable/renderer/shared/zmimic/Initialize(mapload, _owner, _plane) + +/atom/movable/renderer/zmimic/Initialize(mapload, _owner, _plane) plane = _plane name = "Zrenderer [plane]" - . = ..() - -/atom/movable/renderer/shared/zmimic/Destroy() - GLOB.zmimic_renderers -= src return ..() + // Draws the game world; live mobs, items, turfs, etc. /atom/movable/renderer/game name = "Game" group = RENDER_GROUP_SCENE plane = DEFAULT_PLANE + renderer_flags = RENDERER_FLAG_AUTO + /// Draws observers; ghosts, camera eyes, etc. /atom/movable/renderer/observers name = "Observers" group = RENDER_GROUP_SCENE plane = OBSERVER_PLANE + renderer_flags = RENDERER_FLAG_AUTO -/atom/movable/renderer/roofs - name = "Roofs" - group = RENDER_GROUP_SCENE - plane = ROOF_PLANE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT /// Draws darkness effects. /atom/movable/renderer/lighting @@ -194,6 +250,8 @@ GLOBAL_LIST_EMPTY(zmimic_renderers) plane = LIGHTING_PLANE relay_blend_mode = BLEND_MULTIPLY mouse_opacity = MOUSE_OPACITY_TRANSPARENT + renderer_flags = RENDERER_FLAG_AUTO + /atom/movable/renderer/lighting/Initialize() . = ..() @@ -203,11 +261,13 @@ GLOBAL_LIST_EMPTY(zmimic_renderers) flags = MASK_INVERSE ) + /// Draws visuals that should not be affected by darkness. /atom/movable/renderer/above_lighting name = "Above Lighting" group = RENDER_GROUP_SCENE plane = EFFECTS_ABOVE_LIGHTING_PLANE + renderer_flags = RENDERER_FLAG_AUTO /// Draws full screen visual effects, like pain and bluespace. @@ -216,6 +276,7 @@ GLOBAL_LIST_EMPTY(zmimic_renderers) group = RENDER_GROUP_SCENE plane = FULLSCREEN_PLANE mouse_opacity = MOUSE_OPACITY_TRANSPARENT + renderer_flags = RENDERER_FLAG_AUTO /// Draws user interface elements. @@ -223,6 +284,7 @@ GLOBAL_LIST_EMPTY(zmimic_renderers) name = "Interface" group = RENDER_GROUP_SCREEN plane = HUD_PLANE + renderer_flags = RENDERER_FLAG_AUTO /* * @@ -235,17 +297,21 @@ GLOBAL_LIST_EMPTY(zmimic_renderers) * granular manipulation of how the final scene is composed. */ + /// Render group for stuff INSIDE the typical game context - people, items, lighting, etc. /atom/movable/renderer/scene_group name = "Scene Group" group = RENDER_GROUP_FINAL plane = RENDER_GROUP_SCENE + renderer_flags = RENDERER_FLAG_AUTO + /// Render group for stuff OUTSIDE the typical game context - UI, full screen effects, etc. /atom/movable/renderer/screen_group name = "Screen Group" group = RENDER_GROUP_FINAL plane = RENDER_GROUP_SCREEN + renderer_flags = RENDERER_FLAG_AUTO /// Render group for final compositing before user display. @@ -253,6 +319,7 @@ GLOBAL_LIST_EMPTY(zmimic_renderers) name = "Final Group" group = RENDER_GROUP_NONE plane = RENDER_GROUP_FINAL + renderer_flags = RENDERER_FLAG_AUTO /* * @@ -264,6 +331,7 @@ GLOBAL_LIST_EMPTY(zmimic_renderers) * behavior, such as the effect atom below, causes them to be noticeable. */ + /// Renders the /obj/effect/warp example effect as well as gravity catapult effects /atom/movable/renderer/warp name = "Warp Effect" @@ -271,14 +339,57 @@ GLOBAL_LIST_EMPTY(zmimic_renderers) plane = WARP_EFFECT_PLANE render_target_name = "*warp" mouse_opacity = MOUSE_OPACITY_TRANSPARENT + renderer_flags = RENDERER_FLAG_AUTO + + +//Similar to warp but not as strong +/atom/movable/renderer/heat + name = "Heat Effect" + group = RENDER_GROUP_NONE + plane = HEAT_EFFECT_PLANE + render_target_name = HEAT_COMPOSITE_TARGET + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + renderer_flags = RENDERER_FLAG_AUTO + + var/obj/gas_heat_object + var/obj/gas_cold_object + + +/atom/movable/renderer/heat/Initialize() + . = ..() + GraphicsUpdate() + +/atom/movable/renderer/heat/GraphicsUpdate() + if (!ismob(owner)) + return + if (gas_heat_object) + vis_contents -= gas_heat_object + if (gas_cold_object) + vis_contents -= gas_cold_object + QDEL_NULL(gas_heat_object) + QDEL_NULL(gas_cold_object) + gas_cold_object = new /obj/particle_emitter/mist/gas + gas_heat_object = new /obj/particle_emitter/heat/high + vis_contents += gas_heat_object + // if (config.enable_cold_mist) + // vis_contents += gas_cold_object /atom/movable/renderer/scene_group/Initialize() . = ..() - filters += filter(type = "displace", render_source = "*warp", size = 5) + filters += filter( + type = "displace", + render_source = "*warp", + size = 5 + ) + filters += filter( + type = "displace", + render_source = HEAT_COMPOSITE_TARGET, + size = 2.5 + ) /*! - * This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers. + * Emmissives work by exploiting BYONDs color matrix filter to use layers to handle emissive blockers. * * Emissive overlays are pasted with an atom color that converts them to be entirely some specific color. * Emissive blockers are pasted with an atom color that converts them to be entirely some different color. @@ -290,12 +401,16 @@ GLOBAL_LIST_EMPTY(zmimic_renderers) * This works best if emissive overlays applied only to objects that emit light, * since luminosity=0 turfs may not be rendered. */ + + /atom/movable/renderer/emissive name = "Emissive" group = RENDER_GROUP_NONE plane = EMISSIVE_PLANE mouse_opacity = MOUSE_OPACITY_TRANSPARENT render_target_name = EMISSIVE_TARGET + renderer_flags = RENDERER_FLAG_AUTO + /atom/movable/renderer/emissive/Initialize() . = ..() @@ -303,3 +418,18 @@ GLOBAL_LIST_EMPTY(zmimic_renderers) type = "color", color = GLOB.em_mask_matrix ) + + + + + +/* + AURORA SNOWFLAKES +*/ + +/atom/movable/renderer/roofs + name = "Roofs" + group = RENDER_GROUP_SCENE + plane = ROOF_PLANE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + renderer_flags = RENDERER_FLAG_AUTO diff --git a/code/defines/gases.dm b/code/defines/gases.dm index 95730de67bf..a5d8f3ecb1b 100644 --- a/code/defines/gases.dm +++ b/code/defines/gases.dm @@ -32,6 +32,7 @@ molar_mass = 0.405 // kg/mol tile_overlay = "phoron" + tile_color = "#ff9940" overlay_limit = 0.7 flags = XGM_GAS_FUEL | XGM_GAS_CONTAMINANT @@ -108,6 +109,7 @@ /singleton/xgm_gas/chlorine id = GAS_CHLORINE name = "Chlorine" + tile_color = "#c5f72d" tile_overlay = "chlorine" overlay_limit = 0.5 specific_heat = 5 // J/(mol*K) diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 1b82b83f951..ab7581dbddd 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -55,8 +55,10 @@ /obj/machinery/portable_atmospherics/canister/oxygen/Initialize() . = ..() src.air_contents.adjust_gas(GAS_OXYGEN, MolesForPressure()) + /obj/machinery/portable_atmospherics/canister/oxygen/prechilled name = "Canister: \[O2 (Cryo)\]" + /obj/machinery/portable_atmospherics/canister/oxygen/prechilled/Initialize() . = ..() src.air_contents.temperature = 80 @@ -69,6 +71,7 @@ /obj/machinery/portable_atmospherics/canister/phoron/Initialize() . = ..() src.air_contents.adjust_gas(GAS_PHORON, MolesForPressure()) + /obj/machinery/portable_atmospherics/canister/phoron_scarce // replacing on-station canisters with this for scarcity - full-capacity canisters are staying to avoid mapping errors in future name = "Canister \[Phoron\]" icon_state = "orange" @@ -92,6 +95,7 @@ /obj/machinery/portable_atmospherics/canister/hydrogen/Initialize() . = ..() air_contents.adjust_gas(GAS_HYDROGEN, MolesForPressure()) + /obj/machinery/portable_atmospherics/canister/hydrogen/deuterium name = "Canister \[2H\]" icon_state = "teal" @@ -100,6 +104,7 @@ /obj/machinery/portable_atmospherics/canister/hydrogen/deuterium/Initialize() . = ..() air_contents.adjust_gas(GAS_DEUTERIUM, MolesForPressure()) + /obj/machinery/portable_atmospherics/canister/hydrogen/tritium name = "Canister \[3H\]" icon_state = "pink" @@ -126,6 +131,7 @@ /obj/machinery/portable_atmospherics/canister/boron/Initialize() . = ..() air_contents.adjust_gas(GAS_BORON, MolesForPressure()) + /obj/machinery/portable_atmospherics/canister/chlorine name = "\improper Chlorine \[Cl2\]" icon_state = "darkyellow" diff --git a/code/game/objects/items/camping.dm b/code/game/objects/items/camping.dm index ccf96f6e27a..bf91b88ea72 100644 --- a/code/game/objects/items/camping.dm +++ b/code/game/objects/items/camping.dm @@ -59,17 +59,18 @@ . = ..() if(!.) return - var/mob/M = entering - if(!M.renderers) + if(!istype(entering, /mob)) return - var/atom/movable/renderer/roofs/roof_plane = M.renderers["[ROOF_PLANE]"] + + var/mob/M = entering + var/atom/movable/renderer/roofs/roof_plane = M.GetRenderer(/atom/movable/renderer/roofs) if(roof_plane) roof_plane.alpha = 76 /datum/large_structure/tent/mob_moved(mob/mover, turf/exit_point) . = ..() if(!.) - var/atom/movable/renderer/roofs/roof_plane = mover.renderers["[ROOF_PLANE]"] + var/atom/movable/renderer/roofs/roof_plane = mover.GetRenderer(/atom/movable/renderer/roofs) if(roof_plane) roof_plane.alpha = 255 @@ -262,7 +263,7 @@ /obj/structure/component/tent_canvas/Destroy() //When we're destroyed, make sure we return the roof plane to anyone inside for(var/mob/M in loc) - var/atom/movable/renderer/roofs/roof_plane = M.renderers["[ROOF_PLANE]"] + var/atom/movable/renderer/roofs/roof_plane = M.GetRenderer(/atom/movable/renderer/roofs) if(roof_plane) roof_plane.alpha = 255 return ..() diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index c35aa91f7d4..18f09f44d3b 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -6,8 +6,6 @@ var/thermite = 0 initial_gas = list("oxygen" = MOLES_O2STANDARD, "nitrogen" = MOLES_N2STANDARD) - var/to_be_destroyed = 0 //Used for fire, if a melting temperature was reached, it will be destroyed - var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to var/dirt = 0 var/unwet_timer // Used to keep track of the unwet timer & delete it on turf change so we don't runtime if the new turf is not simulated. diff --git a/code/modules/effects/particles/native_particles.dm b/code/modules/effects/particles/native_particles.dm index 2b09f151eba..dc84dbe46ed 100644 --- a/code/modules/effects/particles/native_particles.dm +++ b/code/modules/effects/particles/native_particles.dm @@ -1,3 +1,6 @@ +/particles + var/name = "particles" + /particles/cooking_smoke width = 256 height = 256 @@ -28,6 +31,43 @@ icon = 'icons/effects/native_particles.dmi' icon_state = "bar_smoke" +/particles/mist + name = "mist" + icon = 'icons/effects/particles.dmi' + icon_state = list("steam_1" = 1, "steam_2" = 1, "steam_3" = 1) + count = 500 + spawning = 4 + lifespan = 5 SECONDS + fade = 1 SECOND + fadein = 1 SECOND + velocity = generator("box", list(-0.5, -0.25, 0), list(0.5, 0.25, 0), NORMAL_RAND) + position = generator("box", list(-20, -16), list(20, -2), UNIFORM_RAND) + friction = 0.2 + grow = 0.0015 + +/particles/heat + name = "heat" + width = 500 + height = 500 + count = 250 + spawning = 15 + lifespan = 1.85 SECONDS + fade = 1.25 SECONDS + position = generator("box", list(-16, -16), list(16, 0), NORMAL_RAND) + friction = 0.15 + gradient = list(0, COLOR_WHITE, 0.75, COLOR_ORANGE) + color_change = 0.1 + color = 0 + gravity = list(0, 1) + drift = generator("circle", 0.4, NORMAL_RAND) + velocity = generator("circle", 0, 3, NORMAL_RAND) + + +/particles/heat/high + name = "high heat" + count = 600 + spawning = 35 + /obj/effect/map_effect/particle_emitter var/particles/particle_type = /particles/bar_smoke invisibility = 0 @@ -41,3 +81,64 @@ particle_type = /particles/bar_smoke layer = BELOW_TABLE_LAYER alpha = 128 + + +//Spawner object +//Maybe we could pool them in and out + +/obj/particle_emitter + name = "" + anchored = TRUE + mouse_opacity = 0 + appearance_flags = PIXEL_SCALE + var/particle_type = null + + +/obj/particle_emitter/Initialize(mapload, time, _color) + . = ..() + if (particle_type) + particles = GLOB.all_particles[particle_type] + + if (time > 0) + QDEL_IN(src, time) + color = _color + +/obj/particle_emitter/heat + particle_type = "heat" + render_target = HEAT_EFFECT_TARGET + appearance_flags = PIXEL_SCALE | NO_CLIENT_COLOR + + +/obj/particle_emitter/heat/Initialize() + . = ..() + filters += filter(type = "blur", size = 1) + +/obj/particle_emitter/heat/high + particle_type = "high heat" + + +/obj/particle_emitter/mist + particle_type = "mist" + layer = FIRE_LAYER + +/obj/particle_emitter/mist/back + particle_type = "mist_back" + layer = BELOW_OBJ_LAYER + + +/obj/particle_emitter/mist/back/gas + render_target = COLD_EFFECT_BACK_TARGET + +/obj/particle_emitter/mist/back/gas/Initialize(mapload, time, _color) + . = ..() + filters += filter(type="alpha", render_source = COLD_EFFECT_TARGET, flags = MASK_INVERSE) + +//for cold gas effect +/obj/particle_emitter/mist/gas + render_target = COLD_EFFECT_TARGET + var/obj/particle_emitter/mist/back/b = /obj/particle_emitter/mist/back/gas + +/obj/particle_emitter/mist/gas/Initialize(mapload, time, _color) + . = ..() + b = new b(null) + vis_contents += b diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index b6eee65e0c1..67a9ad7e497 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -100,7 +100,7 @@ clear_important_client_contents(client) enable_client_mobs_in_contents(client) - CreateRenderers() + AddDefaultRenderers() update_client_color() add_click_catcher() diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index c1ef191d393..832ba6a640b 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -10,7 +10,7 @@ disconnect_time = world.realtime log_access("Logout: [key_name(src)]") SSstatistics.update_status() - RemoveRenderers() + ClearRenderers() if(client) clear_important_client_contents(client) diff --git a/code/modules/xgm/xgm_gas_data.dm b/code/modules/xgm/xgm_gas_data.dm index 14e06cbcbf5..eb650b4ae61 100644 --- a/code/modules/xgm/xgm_gas_data.dm +++ b/code/modules/xgm/xgm_gas_data.dm @@ -1,4 +1,4 @@ -/var/datum/xgm_gas_data/gas_data +var/global/datum/xgm_gas_data/gas_data /datum/xgm_gas_data //Simple list of all the gas IDs. @@ -9,7 +9,7 @@ var/list/specific_heat = list() //Molar mass of the gas. Used for calculating specific entropy. var/list/molar_mass = list() - //Tile overlays. /obj/effect/gas_overlay, created from references to 'icons/effects/tile_effects.dmi' + //Tile overlays. /obj/gas_overlay, created from references to 'icons/effects/tile_effects.dmi' var/list/tile_overlay = list() //Optional color for tile overlay var/list/tile_overlay_color = list() @@ -36,7 +36,7 @@ var/singleton/xgm_gas/gas = new p //avoid initial() because of potential New() actions if(gas.id in gas_data.gases) - log_world("ERROR: Duplicate gas id `[gas.id]` in `[p]`") + stack_trace("ERROR: Duplicate gas id `[gas.id]` in `[p]`") gas_data.gases += gas.id gas_data.name[gas.id] = gas.name @@ -44,27 +44,62 @@ gas_data.molar_mass[gas.id] = gas.molar_mass if(gas.overlay_limit) gas_data.overlay_limit[gas.id] = gas.overlay_limit - var/obj/effect/gas_overlay/I = new() - if(gas.tile_overlay) - I.icon_state = gas.tile_overlay - if(gas.tile_color) - gas_data.tile_overlay_color[gas.id] = gas.tile_color - I.color = gas.tile_color - gas_data.tile_overlay[gas.id] = I + gas_data.tile_overlay[gas.id] = gas.tile_overlay + gas_data.tile_overlay_color[gas.id] = gas.tile_color gas_data.flags[gas.id] = gas.flags return 1 -/obj/effect/gas_overlay +/obj/gas_overlay name = "gas" - desc = DESC_PARENT + desc = "You shouldn't be clicking this." icon = 'icons/effects/tile_effects.dmi' icon_state = "generic" layer = FIRE_LAYER - appearance_flags = RESET_COLOR - mouse_opacity = MOUSE_OPACITY_TRANSPARENT + appearance_flags = DEFAULT_APPEARANCE_FLAGS | RESET_COLOR + mouse_opacity = 0 + var/gas_id -/obj/effect/gas_overlay/Initialize() +/obj/gas_overlay/proc/update_alpha_animation(new_alpha) + animate(src, alpha = new_alpha) + alpha = new_alpha + animate(src, alpha = 0.8 * new_alpha, time = 10, easing = SINE_EASING | EASE_OUT, loop = -1) + animate(alpha = new_alpha, time = 10, easing = SINE_EASING | EASE_IN, loop = -1) + +/obj/gas_overlay/Initialize(mapload, gas) + . = ..() + gas_id = gas + if(gas_data.tile_overlay[gas_id]) + icon_state = gas_data.tile_overlay[gas_id] + color = gas_data.tile_overlay_color[gas_id] + +/obj/gas_overlay/heat + name = "gas" + desc = "You shouldn't be clicking this." + plane = HEAT_EFFECT_PLANE + gas_id = GAS_HEAT + render_source = HEAT_EFFECT_TARGET + +/obj/gas_overlay/heat/Initialize(mapload, gas) + . = ..() + icon = null + icon_state = null + +/obj/effect/gas_cold_back + render_source = COLD_EFFECT_BACK_TARGET + plane = DEFAULT_PLANE + layer = BELOW_OBJ_LAYER + +/obj/gas_overlay/cold + name = "gas" + desc = "You shouldn't be clicking this." + gas_id = GAS_COLD + render_source = COLD_EFFECT_TARGET + var/obj/effect/gas_cold_back/b = null + +/obj/gas_overlay/cold/Initialize(mapload, gas) . = ..() - animate(src, alpha = 175, time = 10, easing = SINE_EASING | EASE_OUT, loop = -1) - animate(alpha = 255, time = 10, easing = SINE_EASING | EASE_IN, loop = -1) + icon = null + icon_state = null + b = new() + vis_contents += b diff --git a/code/modules/xgm/xgm_gas_mixture.dm b/code/modules/xgm/xgm_gas_mixture.dm index 1a8a2a4e814..2c31d9af1ec 100644 --- a/code/modules/xgm/xgm_gas_mixture.dm +++ b/code/modules/xgm/xgm_gas_mixture.dm @@ -13,7 +13,9 @@ var/group_multiplier = 1 ///List of active tile overlays for this gas_mixture. Updated by check_tile_graphic() - var/list/graphic + var/list/graphic = list() + //Cache of gas overlay objects + var/list/tile_overlay_cache /datum/gas_mixture/New(_volume = CELL_VOLUME, _temperature = 0, _group_multiplier = 1) volume = _volume @@ -353,32 +355,73 @@ zburn(null, force_burn=0, no_check=0) //could probably just call zburn() here with no args but I like being explicit. -///Rechecks the gas_mixture and adjusts the graphic list if needed. -///Two lists can be passed by reference if you need know specifically which graphics were added and removed. +//Rechecks the gas_mixture and adjusts the graphic list if needed. +//Two lists can be passed by reference if you need know specifically which graphics were added and removed. /datum/gas_mixture/proc/check_tile_graphic(list/graphic_add = null, list/graphic_remove = null) + for(var/obj/gas_overlay/O in graphic) + if(istype(O, /obj/gas_overlay/heat)) + continue + if(istype(O, /obj/gas_overlay/cold)) + continue + if(gas[O.gas_id] <= gas_data.overlay_limit[O.gas_id]) + LAZYADD(graphic_remove, O) for(var/g in gas_data.overlay_limit) - if (graphic && graphic[gas_data.tile_overlay[g]]) - //Overlay is already applied for this gas, check if it's still valid. - if(gas[g] <= gas_data.overlay_limit[g]) - LAZYADD(graphic_remove, gas_data.tile_overlay[g]) - else - //Overlay isn't applied for this gas, check if it's valid and needs to be added. - if(gas[g] > gas_data.overlay_limit[g]) - if(!(gas_data.tile_overlay[g] in graphic)) - LAZYADD(graphic_add, gas_data.tile_overlay[g]) - + //Overlay isn't applied for this gas, check if it's valid and needs to be added. + if(gas[g] > gas_data.overlay_limit[g]) + var/tile_overlay = get_tile_overlay(g) + if(!(tile_overlay in graphic)) + LAZYADD(graphic_add, tile_overlay) . = 0 + + var/heat_overlay = get_tile_overlay(GAS_HEAT) + //If it's hot add something + if(temperature >= CARBON_LIFEFORM_FIRE_RESISTANCE) + if(!(heat_overlay in graphic)) + LAZYADD(graphic_add, heat_overlay) + else if (heat_overlay in graphic) + LAZYADD(graphic_remove, heat_overlay) + + var/cold_overlay = get_tile_overlay(GAS_COLD) + if(temperature <= FOGGING_TEMPERATURE && (return_pressure() >= (ONE_ATMOSPHERE / 4))) + if(!(cold_overlay in graphic)) + LAZYADD(graphic_add, cold_overlay) + else if (cold_overlay in graphic) + LAZYADD(graphic_remove, cold_overlay) + //Apply changes - if(graphic_add && LAZYLEN(graphic_add)) - LAZYINITLIST(graphic) - for (var/entry in graphic_add) - graphic[entry] = TRUE // This is an assoc list to make checking it a bit faster. + if(graphic_add && length(graphic_add)) + graphic |= graphic_add . = 1 - if(graphic_add && LAZYLEN(graphic_remove)) + if(graphic_remove && length(graphic_remove)) graphic -= graphic_remove . = 1 - - UNSETEMPTY(graphic) + if(length(graphic)) + var/pressure_mod = clamp(return_pressure() / ONE_ATMOSPHERE, 0, 2) + for(var/obj/gas_overlay/O in graphic) + if(istype(O, /obj/gas_overlay/heat)) //Heat based + var/new_alpha = clamp(max(125, 255 * ((temperature - CARBON_LIFEFORM_FIRE_RESISTANCE) / CARBON_LIFEFORM_FIRE_RESISTANCE * 4)), 125, 255) + if(new_alpha != O.alpha) + O.update_alpha_animation(new_alpha) + continue + if(istype(O, /obj/gas_overlay/cold)) + var/new_alpha = clamp(max(125, 200 * (1 - ((temperature - MAX_FOG_TEMPERATURE) / (FOGGING_TEMPERATURE - MAX_FOG_TEMPERATURE)))), 125, 200) + if(new_alpha != O.alpha) + O.update_alpha_animation(new_alpha) + continue + var/concentration_mod = clamp(gas[O.gas_id] / total_moles, 0.1, 1) + var/new_alpha = min(230, round(pressure_mod * concentration_mod * 180, 5)) + if(new_alpha != O.alpha) + O.update_alpha_animation(new_alpha) + +/datum/gas_mixture/proc/get_tile_overlay(gas_id) + if(!LAZYACCESS(tile_overlay_cache, gas_id)) + if(gas_id == GAS_HEAT) //Not a real gas but functionally same thing + LAZYSET(tile_overlay_cache, gas_id, new/obj/gas_overlay/heat(null, GAS_HEAT)) + else if(gas_id == GAS_COLD) //Not a real gas but functionally same thing + LAZYSET(tile_overlay_cache, gas_id, new/obj/gas_overlay/cold(null, GAS_COLD)) + else + LAZYSET(tile_overlay_cache, gas_id, new/obj/gas_overlay(null, gas_id)) + return tile_overlay_cache[gas_id] ///Simpler version of merge(), adjusts gas amounts directly and doesn't account for temperature or group_multiplier. /datum/gas_mixture/proc/add(datum/gas_mixture/right_side) diff --git a/html/changelogs/fluffyghost-516renderer.yml b/html/changelogs/fluffyghost-516renderer.yml new file mode 100644 index 00000000000..7786dc9e8a6 --- /dev/null +++ b/html/changelogs/fluffyghost-516renderer.yml @@ -0,0 +1,60 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: FluffyGhost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Updated the renderers to work with BYOND 516." + - refactor: "Some update of ZAS to hopefully be more efficient, and cold/hot air effects." + - qol: "Gas effects are now less prominent." diff --git a/icons/effects/particles.dmi b/icons/effects/particles.dmi new file mode 100644 index 0000000000000000000000000000000000000000..06c8b40733e751018a849c37cb6111d00ced9244 GIT binary patch literal 2054 zcmZ`)eK-?p8{gJ^&6wecMnmSzY2+(9R%5;*A7^PQm5-1Rk$e*~vI#|cI~r;#-*1yq zoFbHlmRs_ye}yBS*lC#ot3ht49$V0< z2g}Yn{=RcZ;lT8YX=(558QY>k?qOs-zBQ$#Tx6H-5Rfvcyit{YUXz2^ap93Cchn^v z0FaS$w#O6Wi|0$)L&u%eJFQW(DjD`*6s;e51ve{iXc3$}{ zA$@Xv%=TI+uj~d2Ggig{((IF{)-nGcee0;wpQ^vSmG-c#TO*pgJE?4=px9ZDxyu0W?^BoU} z-`vdI5VQOkeV=7BhLx?bkbC$e&MK8KLP{KZ!6p#F55Vwzc4X7T(+g&?CzE^0XS^7? zUxt{}u3Rg057XyAf=1`zhS}&4S}bGD4{VgfiJX4Lu|i86yv(N+o#RV z=I)HRmvj1ornmOBO!Y7^gHL-Mnx4peeDn^q*9n+Q29BJ`VddivGtb4V0eu zOtbkxubceHeZ|VkPq#`}ZYMmumqZUh`Y zJHKEvnN3|0UV_7KxmT3D8VHen^C8pnScU19p|sD=R>q?xp-5bu!|-2=jk~{YNO}2n zO=w!;UNqG&USDQ2U`?_eOOaQCkm2BogB?3t@9fL1b*&giD8K)g`v{4~f4!Ie+SAt3 z(h|EJt=BLK&#mR{mEUDW^2+21oh$n1l2w?&&dkE2S=K3hT@y<2)UiFqw;Nx5c*G7j z?r&*)I((zlMeDesd&Vi9Ut-5bPBO4IPodsZ7h^CW)J&0*GVcEi|DQ?vUr+e8aT0EG z5)_NlZhTG%#~KuZGJ9#@_nAjiAJWo^@D0RPy9osJ>TDt?`xvEX1 z90%qrJbYC028l~ihUZuOw$o0M>_C}qaJYd(C@EtGN=1+x9}in$)tv-_Yza}JK(BK! z1{L!7n-2ERQm{2^Yl%iEC~jNq0-kn>Xgd*y$F3GNel2DlqxG!`vX@8A2I@~UI!xtH z@UkqHkc~N7aA3FHJB_?He4}r(Mjlo6nWzxB zi(+S-Mm}%dCzGQYEj--Th3}W)C~5vWvwDw|{{ren-w*1nAmyivck@+^quhgPD-V(- zD%GheiQEzgv`3~@;I~}$XV&?FrtA%pO>(6*7d4c(PDs<4vJ;h7WO%Xdq%w10{Ids8 zkSy3w>ZZ6rBt+c=_a`zm;eAp&1p?Jrxn~RyYOCaxiY4K&C>sINIqJwvzo0g%E-F#P{64xrt zZvMRo$SCis?JVx)Q?R}BYmF^Fz2dF1y3~OBVt0F>Av=SJC2xSkfK1(!!=!C*__ay~YG!fdKuvvk9*c;Fzx28*VnR0kB1bJswQIWWr$ zo4Qv1$?9YSNu=7^l#f)lQka}n!wU-3>DzapT{`>x3xS5Eq}cU5;Gj!`7almjh?mqI zm8T;lv{6I)L+q6rNQ*k0#YH7=Fe16oW7L8Pe1~$Ld&2nic`W&f*eB`I zGnc8BKNj9Idr#e|6+N@K>Wy+%UWwNA@08w%=)2y;R&xE(s`=4-OUS-W0HJ<`J}g=6 N0A~kxdxota`7b)Jt)2h? literal 0 HcmV?d00001 diff --git a/icons/effects/tile_effects.dmi b/icons/effects/tile_effects.dmi index dd06df99d70ba65d08e85cd31c390ac77e52d808..3aab22d80d6ebf64f6bd3f845ea0d3cf20baae21 100644 GIT binary patch literal 6727 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 w?85Wx Date: Sat, 8 Mar 2025 22:01:51 +0100 Subject: [PATCH 2/2] dsgf --- code/_onclick/hud/rendering/_renderer.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/_onclick/hud/rendering/_renderer.dm b/code/_onclick/hud/rendering/_renderer.dm index a4b0153dce0..bfb7e768bc5 100644 --- a/code/_onclick/hud/rendering/_renderer.dm +++ b/code/_onclick/hud/rendering/_renderer.dm @@ -60,7 +60,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/renderer) render_target = render_target_name else if (render_target_name) render_target = "*[ckey(name)]" - if (owner.client?.byond_version < 516) + if (owner?.client?.byond_version < 516) screen_loc = "CENTER" relay = new relay.screen_loc = screen_loc @@ -191,7 +191,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/renderer) */ - /// Handles byond internal letterboxing. Avoid touching. +/// Handles byond internal letterboxing. Avoid touching. /atom/movable/renderer/letterbox name = "Letterbox" group = RENDER_GROUP_SCENE