mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
262 lines
8.8 KiB
Plaintext
262 lines
8.8 KiB
Plaintext
// Flags indicating what parts of the fluid the subsystem processes.
|
|
/// Indicates that a fluid subsystem processes fluid spreading.
|
|
#define SS_PROCESSES_SPREADING (1<<0)
|
|
/// Indicates that a fluid subsystem processes fluid effects.
|
|
#define SS_PROCESSES_EFFECTS (1<<1)
|
|
|
|
/**
|
|
* # Fluid Subsystem
|
|
*
|
|
* A subsystem that processes the propagation and effects of a particular fluid.
|
|
*
|
|
* Both fluid spread and effect processing are handled through a carousel system.
|
|
* Fluids being spread and fluids being processed are organized into buckets.
|
|
* Each fresh (non-resumed) fire one bucket of each is selected to be processed.
|
|
* These selected buckets are then fully processed.
|
|
* The next fresh fire selects the next bucket in each set for processing.
|
|
* If this would walk off the end of a carousel list we wrap back to the first element.
|
|
* This effectively makes each set a circular list, hence a carousel.
|
|
*/
|
|
SUBSYSTEM_DEF(fluids)
|
|
name = "Fluid"
|
|
wait = 0 // Will be autoset to whatever makes the most sense given the spread and effect waits.
|
|
flags = SS_BACKGROUND|SS_KEEP_TIMING
|
|
runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME
|
|
|
|
// Fluid spread processing:
|
|
/// The amount of time (in deciseconds) before a fluid node is created and when it spreads.
|
|
var/spread_wait = 1 SECONDS
|
|
/// The number of buckets in the spread carousel.
|
|
var/num_spread_buckets
|
|
/// The set of buckets containing fluid nodes to spread.
|
|
var/list/spread_carousel
|
|
/// The index of the spread carousel bucket currently being processed.
|
|
var/spread_bucket_index
|
|
/// The set of fluid nodes we are currently processing spreading for.
|
|
var/list/currently_spreading
|
|
/// Whether the subsystem has resumed spreading fluid.
|
|
var/resumed_spreading
|
|
|
|
// Fluid effect processing:
|
|
/// The amount of time (in deciseconds) between effect processing ticks for each fluid node.
|
|
var/effect_wait = 1 SECONDS
|
|
/// The number of buckets in the effect carousel.
|
|
var/num_effect_buckets
|
|
/// The set of buckets containing fluid nodes to process effects for.
|
|
var/list/effect_carousel
|
|
/// The index of the currently processing bucket on the effect carousel.
|
|
var/effect_bucket_index
|
|
/// The set of fluid nodes we are currently processing effects for.
|
|
var/list/currently_processing
|
|
/// Whether the subsystem has resumed processing fluid effects.
|
|
var/resumed_effect_processing
|
|
|
|
/datum/controller/subsystem/fluids/Initialize()
|
|
initialize_waits()
|
|
initialize_spread_carousel()
|
|
initialize_effect_carousel()
|
|
return SS_INIT_SUCCESS
|
|
|
|
/**
|
|
* Initializes the subsystem waits.
|
|
*
|
|
* Ensures that the subsystem's fire wait evenly splits the spread and effect waits.
|
|
*/
|
|
/datum/controller/subsystem/fluids/proc/initialize_waits()
|
|
if (spread_wait <= 0)
|
|
WARNING("[src] has the invalid spread wait [spread_wait].")
|
|
spread_wait = 1 SECONDS
|
|
if (effect_wait <= 0)
|
|
WARNING("[src] has the invalid effect wait [effect_wait].")
|
|
spread_wait = 1 SECONDS
|
|
|
|
// Sets the overall wait of the subsystem to evenly divide both the effect and spread waits.
|
|
var/max_wait = Gcd(spread_wait, effect_wait)
|
|
if (max_wait < wait || wait <= 0)
|
|
wait = max_wait
|
|
else
|
|
// If the wait of the subsystem overall is set to a valid value make the actual wait of the subsystem evenly divide that as well.
|
|
// Makes effect bubbling possible with identical spread and effect waits.
|
|
wait = Gcd(wait, max_wait)
|
|
|
|
|
|
/**
|
|
* Initializes the carousel used to process fluid spreading.
|
|
*
|
|
* Synchronizes the spread delta time with the actual target spread tick rate.
|
|
* Builds the carousel buckets used to queue spreads.
|
|
*/
|
|
/datum/controller/subsystem/fluids/proc/initialize_spread_carousel()
|
|
// Make absolutely certain that the spread wait is in sync with the target spread tick rate.
|
|
num_spread_buckets = round(spread_wait / wait)
|
|
spread_wait = wait * num_spread_buckets
|
|
|
|
spread_carousel = list()
|
|
spread_carousel.len = num_spread_buckets
|
|
for(var/i in 1 to num_spread_buckets)
|
|
spread_carousel[i] = list()
|
|
currently_spreading = list()
|
|
spread_bucket_index = 1
|
|
|
|
/**
|
|
* Initializes the carousel used to process fluid effects.
|
|
*
|
|
* Synchronizes the spread delta time with the actual target spread tick rate.
|
|
* Builds the carousel buckets used to bubble processing.
|
|
*/
|
|
/datum/controller/subsystem/fluids/proc/initialize_effect_carousel()
|
|
// Make absolutely certain that the effect wait is in sync with the target effect tick rate.
|
|
num_effect_buckets = round(effect_wait / wait)
|
|
effect_wait = wait * num_effect_buckets
|
|
|
|
effect_carousel = list()
|
|
effect_carousel.len = num_effect_buckets
|
|
for(var/i in 1 to num_effect_buckets)
|
|
effect_carousel[i] = list()
|
|
currently_processing = list()
|
|
effect_bucket_index = 1
|
|
|
|
|
|
/datum/controller/subsystem/fluids/fire(resumed)
|
|
var/delta_time
|
|
var/cached_bucket_index
|
|
var/list/obj/effect/particle_effect/fluid/currentrun
|
|
MC_SPLIT_TICK_INIT(2)
|
|
|
|
MC_SPLIT_TICK // Start processing fluid spread:
|
|
if(!resumed_spreading)
|
|
spread_bucket_index = WRAP_UP(spread_bucket_index, num_spread_buckets)
|
|
currently_spreading = spread_carousel[spread_bucket_index]
|
|
spread_carousel[spread_bucket_index] = list() // Reset the bucket so we don't process an _entire station's worth of foam_ spreading every 2 ticks when the foam flood event happens.
|
|
resumed_spreading = TRUE
|
|
|
|
delta_time = spread_wait / (1 SECONDS)
|
|
currentrun = currently_spreading
|
|
while(currentrun.len)
|
|
var/obj/effect/particle_effect/fluid/to_spread = currentrun[currentrun.len]
|
|
currentrun.len--
|
|
|
|
if(!QDELETED(to_spread))
|
|
to_spread.spread(delta_time)
|
|
to_spread.spread_bucket = null
|
|
|
|
if (MC_TICK_CHECK)
|
|
break
|
|
|
|
if(!currentrun.len)
|
|
resumed_spreading = FALSE
|
|
|
|
MC_SPLIT_TICK // Start processing fluid effects:
|
|
if(!resumed_effect_processing)
|
|
effect_bucket_index = WRAP_UP(effect_bucket_index, num_effect_buckets)
|
|
var/list/tmp_list = effect_carousel[effect_bucket_index]
|
|
currently_processing = tmp_list.Copy()
|
|
resumed_effect_processing = TRUE
|
|
|
|
delta_time = effect_wait / (1 SECONDS)
|
|
cached_bucket_index = effect_bucket_index
|
|
currentrun = currently_processing
|
|
while(currentrun.len)
|
|
var/obj/effect/particle_effect/fluid/to_process = currentrun[currentrun.len]
|
|
currentrun.len--
|
|
|
|
if (QDELETED(to_process) || to_process.process(delta_time) == PROCESS_KILL)
|
|
effect_carousel[cached_bucket_index] -= to_process
|
|
to_process.effect_bucket = null
|
|
to_process.datum_flags &= ~DF_ISPROCESSING
|
|
|
|
if (MC_TICK_CHECK)
|
|
break
|
|
|
|
if(!currentrun.len)
|
|
resumed_effect_processing = FALSE
|
|
|
|
|
|
/**
|
|
* Queues a fluid node to spread later after one full carousel rotation.
|
|
*
|
|
* Arguments:
|
|
* - [node][/obj/effect/particle_effect/fluid]: The node to queue to spread.
|
|
*/
|
|
/datum/controller/subsystem/fluids/proc/queue_spread(obj/effect/particle_effect/fluid/node)
|
|
if (node.spread_bucket)
|
|
return
|
|
|
|
spread_carousel[spread_bucket_index] += node
|
|
node.spread_bucket = spread_bucket_index
|
|
|
|
/**
|
|
* Cancels a queued spread of a fluid node.
|
|
*
|
|
* Arguments:
|
|
* - [node][/obj/effect/particle_effect/fluid]: The node to cancel the spread of.
|
|
*/
|
|
/datum/controller/subsystem/fluids/proc/cancel_spread(obj/effect/particle_effect/fluid/node)
|
|
if(!node.spread_bucket)
|
|
return
|
|
|
|
var/bucket_index = node.spread_bucket
|
|
spread_carousel[bucket_index] -= node
|
|
if (bucket_index == spread_bucket_index)
|
|
currently_spreading -= node
|
|
|
|
node.spread_bucket = null
|
|
|
|
/**
|
|
* Starts processing the effects of a fluid node.
|
|
*
|
|
* The fluid node will next process after one full bucket rotation.
|
|
*
|
|
* Arguments:
|
|
* - [node][/obj/effect/particle_effect/fluid]: The node to start processing.
|
|
*/
|
|
/datum/controller/subsystem/fluids/proc/start_processing(obj/effect/particle_effect/fluid/node)
|
|
if (node.datum_flags & DF_ISPROCESSING || node.effect_bucket)
|
|
return
|
|
|
|
// Edit this value to make all fluids process effects (at the same time|offset by when they started processing| -> offset by a random amount <- )
|
|
var/bucket_index = rand(1, num_effect_buckets)
|
|
effect_carousel[bucket_index] += node
|
|
node.effect_bucket = bucket_index
|
|
node.datum_flags |= DF_ISPROCESSING
|
|
|
|
/**
|
|
* Stops processing the effects of a fluid node.
|
|
*
|
|
* Arguments:
|
|
* - [node][/obj/effect/particle_effect/fluid]: The node to stop processing.
|
|
*/
|
|
/datum/controller/subsystem/fluids/proc/stop_processing(obj/effect/particle_effect/fluid/node)
|
|
if(!(node.datum_flags & DF_ISPROCESSING))
|
|
return
|
|
|
|
var/bucket_index = node.effect_bucket
|
|
if(!bucket_index)
|
|
return
|
|
|
|
effect_carousel[bucket_index] -= node
|
|
if (bucket_index == effect_bucket_index)
|
|
currently_processing -= node
|
|
|
|
node.effect_bucket = null
|
|
node.datum_flags &= ~DF_ISPROCESSING
|
|
|
|
#undef SS_PROCESSES_SPREADING
|
|
#undef SS_PROCESSES_EFFECTS
|
|
|
|
|
|
// Subtypes:
|
|
|
|
/// The subsystem responsible for processing smoke propagation and effects.
|
|
FLUID_SUBSYSTEM_DEF(smoke)
|
|
name = "Smoke"
|
|
spread_wait = 0.1 SECONDS
|
|
effect_wait = 2.0 SECONDS
|
|
|
|
/// The subsystem responsible for processing foam propagation and effects.
|
|
FLUID_SUBSYSTEM_DEF(foam)
|
|
name = "Foam"
|
|
wait = 0.1 SECONDS // Makes effect bubbling work with foam.
|
|
spread_wait = 0.2 SECONDS
|
|
effect_wait = 0.2 SECONDS
|