516 Renderer update (#20579)

Updated the renderers to work with BYOND 516.
Some update of ZAS to hopefully be more efficient, and cold/hot air
effects.
Gas effects are now less prominent.

Ported from Bay
This commit is contained in:
Fluffy
2025-03-22 12:20:21 +01:00
committed by GitHub
parent 2e59f1903e
commit 08b82baea4
18 changed files with 514 additions and 112 deletions
+7
View File
@@ -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.
+8 -6
View File
@@ -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()
+5
View File
@@ -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"
+5
View File
@@ -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.
+7
View File
@@ -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, \
+191 -61
View File
@@ -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,52 +93,104 @@ 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
/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
for (var/atom/movable/renderer/zrenderer as anything in GLOB.zmimic_renderers)
if (zrenderer.relay)
my_client.screen += zrenderer.relay
my_client.screen += zrenderer
/// 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.
/atom/movable/renderer/letterbox
name = "Letterbox"
@@ -134,58 +198,50 @@ INITIALIZE_IMMEDIATE(/atom/movable/renderer)
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
+2
View File
@@ -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)
@@ -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"
+6 -5
View File
@@ -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 ..()
-2
View File
@@ -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.
@@ -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
+1 -1
View File
@@ -100,7 +100,7 @@
clear_important_client_contents(client)
enable_client_mobs_in_contents(client)
CreateRenderers()
AddDefaultRenderers()
update_client_color()
add_click_catcher()
+1 -1
View File
@@ -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)
+52 -17
View File
@@ -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)
. = ..()
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)
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)
. = ..()
icon = null
icon_state = null
b = new()
vis_contents += b
+62 -19
View File
@@ -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
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)
UNSETEMPTY(graphic)
/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)
@@ -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."
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB