diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 91d558b7d96..2bab99b6fb0 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -201,9 +201,9 @@ #define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_DATABASE 16 #define FIRE_PRIORITY_WET_FLOORS 20 -#define FIRE_PRIORITY_FLUIDS 20 #define FIRE_PRIORITY_AIR 20 #define FIRE_PRIORITY_NPC 20 +#define FIRE_PRIORITY_ASSETS 20 #define FIRE_PRIORITY_HYPERSPACE_DRIFT 20 #define FIRE_PRIORITY_NPC_MOVEMENT 21 #define FIRE_PRIORITY_NPC_ACTIONS 22 @@ -219,8 +219,8 @@ #define FIRE_PRIORITY_DEFAULT 50 #define FIRE_PRIORITY_PARALLAX 65 #define FIRE_PRIORITY_INSTRUMENTS 80 +#define FIRE_PRIORITY_FLUIDS 80 #define FIRE_PRIORITY_MOBS 100 -#define FIRE_PRIORITY_ASSETS 105 #define FIRE_PRIORITY_TGUI 110 #define FIRE_PRIORITY_TICKER 200 #define FIRE_PRIORITY_STATPANEL 390 diff --git a/code/__HELPERS/reagents.dm b/code/__HELPERS/reagents.dm index 60598a51515..d557db3173a 100644 --- a/code/__HELPERS/reagents.dm +++ b/code/__HELPERS/reagents.dm @@ -70,13 +70,13 @@ GLOB.chemical_reactions_list_reactant_index[rid] -= R //see build_chemical_reactions_list in holder.dm for explanations -/proc/add_chemical_reaction(datum/chemical_reaction/R) - if(!GLOB.chemical_reactions_list_reactant_index || !R.required_reagents || !R.required_reagents.len) +/proc/add_chemical_reaction(datum/chemical_reaction/add) + if(!GLOB.chemical_reactions_list_reactant_index || !add.required_reagents || !add.required_reagents.len) return - var/primary_reagent = R.required_reagents[1] - if(!GLOB.chemical_reactions_list_reactant_index[primary_reagent]) - GLOB.chemical_reactions_list_reactant_index[primary_reagent] = list() - GLOB.chemical_reactions_list_reactant_index[primary_reagent] += R + var/rand_reagent = pick(add.required_reagents) + if(!GLOB.chemical_reactions_list_reactant_index[rand_reagent]) + GLOB.chemical_reactions_list_reactant_index[rand_reagent] = list() + GLOB.chemical_reactions_list_reactant_index[rand_reagent] += add //Creates foam from the reagent. Metaltype is for metal foam, notification is what to show people in textbox /datum/reagents/proc/create_foam(foamtype, foam_volume, result_type = null, notification = null, log = FALSE) diff --git a/code/controllers/subsystem/fluids.dm b/code/controllers/subsystem/fluids.dm index 821c1f6cb2c..6b68ae71722 100644 --- a/code/controllers/subsystem/fluids.dm +++ b/code/controllers/subsystem/fluids.dm @@ -20,8 +20,9 @@ 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 + flags = SS_KEEP_TIMING runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + priority = FIRE_PRIORITY_FLUIDS // Fluid spread processing: /// The amount of time (in deciseconds) before a fluid node is created and when it spreads. @@ -34,8 +35,6 @@ SUBSYSTEM_DEF(fluids) 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. @@ -48,8 +47,6 @@ SUBSYSTEM_DEF(fluids) 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() @@ -121,14 +118,15 @@ SUBSYSTEM_DEF(fluids) var/seconds_per_tick var/cached_bucket_index var/list/obj/effect/particle_effect/fluid/currentrun + // Ok so like I get the lighting style splittick but why are we doing this churn thing + // It seems like a bad idea for processing to get out of step with spreading MC_SPLIT_TICK_INIT(2) - MC_SPLIT_TICK // Start processing fluid spread: - if(!resumed_spreading) + MC_SPLIT_TICK // Start processing fluid spread (we take a lot of cpu for ourselves, spreading is more important after all) + if(!resumed) 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 seconds_per_tick = spread_wait / (1 SECONDS) currentrun = currently_spreading @@ -143,15 +141,11 @@ SUBSYSTEM_DEF(fluids) if (MC_TICK_CHECK) break - if(!currentrun.len) - resumed_spreading = FALSE - MC_SPLIT_TICK // Start processing fluid effects: - if(!resumed_effect_processing) + if(!resumed) 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 seconds_per_tick = effect_wait / (1 SECONDS) cached_bucket_index = effect_bucket_index @@ -168,10 +162,6 @@ SUBSYSTEM_DEF(fluids) if (MC_TICK_CHECK) break - if(!currentrun.len) - resumed_effect_processing = FALSE - - /** * Queues a fluid node to spread later after one full carousel rotation. * diff --git a/code/datums/elements/atmos_sensitive.dm b/code/datums/elements/atmos_sensitive.dm index dabcc808d2a..4bc66246659 100644 --- a/code/datums/elements/atmos_sensitive.dm +++ b/code/datums/elements/atmos_sensitive.dm @@ -4,13 +4,13 @@ //Don't put it on things that tend to clump into one spot, you will cause lag spikes. /datum/element/atmos_sensitive element_flags = ELEMENT_DETACH_ON_HOST_DESTROY - var/static/list/pass_on = list(COMSIG_TURF_EXPOSE = /atom/proc/check_atmos_process) /datum/element/atmos_sensitive/Attach(datum/target, mapload) if(!isatom(target)) //How return ELEMENT_INCOMPATIBLE var/atom/to_track = target - to_track.AddElement(/datum/element/connect_loc, pass_on) + if(to_track.loc) + to_track.RegisterSignal(to_track.loc, COMSIG_TURF_EXPOSE, TYPE_PROC_REF(/atom, check_atmos_process)) RegisterSignal(to_track, COMSIG_MOVABLE_MOVED, PROC_REF(react_to_move)) if(!mapload && isopenturf(to_track.loc)) @@ -18,21 +18,24 @@ return ..() -/datum/element/atmos_sensitive/Detach(datum/source) - var/atom/us = source - us.RemoveElement(/datum/element/connect_loc, pass_on) +/datum/element/atmos_sensitive/Detach(atom/source) + if(source.loc) + UnregisterSignal(source.loc, COMSIG_TURF_EXPOSE) UnregisterSignal(source, COMSIG_MOVABLE_MOVED) - if(us.flags_1 & ATMOS_IS_PROCESSING_1) - us.atmos_end() - SSair.atom_process -= us - us.flags_1 &= ~ATMOS_IS_PROCESSING_1 + if(source.flags_1 & ATMOS_IS_PROCESSING_1) + source.atmos_end() + SSair.atom_process -= source + source.flags_1 &= ~ATMOS_IS_PROCESSING_1 return ..() -/datum/element/atmos_sensitive/proc/react_to_move(datum/source, atom/movable/oldloc, direction, forced) +/datum/element/atmos_sensitive/proc/react_to_move(atom/source, atom/movable/oldloc, direction, forced) SIGNAL_HANDLER - var/atom/atom_source = source - atom_source.atmos_conditions_changed() //Make sure you're properly registered + if(oldloc) + source.UnregisterSignal(oldloc, COMSIG_TURF_EXPOSE) + if(source.loc) + source.RegisterSignal(source.loc, COMSIG_TURF_EXPOSE, TYPE_PROC_REF(/atom, check_atmos_process)) + source.atmos_conditions_changed() //Make sure you're properly registered /atom/proc/check_atmos_process(datum/source, datum/gas_mixture/air, exposed_temperature) SIGNAL_HANDLER diff --git a/code/datums/elements/forced_gravity.dm b/code/datums/elements/forced_gravity.dm index 2b0d020b120..b81900e1e33 100644 --- a/code/datums/elements/forced_gravity.dm +++ b/code/datums/elements/forced_gravity.dm @@ -11,6 +11,10 @@ if(!isatom(target)) return ELEMENT_INCOMPATIBLE + var/our_ref = REF(src) + if(HAS_TRAIT_FROM(target, TRAIT_FORCED_GRAVITY, our_ref)) + return + src.gravity = gravity src.ignore_turf_gravity = ignore_turf_gravity @@ -18,7 +22,7 @@ if(isturf(target)) RegisterSignal(target, COMSIG_TURF_HAS_GRAVITY, PROC_REF(turf_gravity_check), override = can_override) ////TODO : SKYRAT EDIT - TEMP CI FIX - ADD_TRAIT(target, TRAIT_FORCED_GRAVITY, REF(src)) + ADD_TRAIT(target, TRAIT_FORCED_GRAVITY, our_ref) /datum/element/forced_gravity/Detach(datum/source) . = ..() @@ -37,5 +41,4 @@ /datum/element/forced_gravity/proc/turf_gravity_check(datum/source, atom/checker, list/gravs) SIGNAL_HANDLER - - return gravity_check(null, source, gravs) + gravity_check(null, source, gravs) diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index 9499558fcff..71ede0c55a3 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -16,6 +16,16 @@ ///The amount of reagent this decal holds, if decal_reagent is defined var/reagent_amount = 0 +/// Creates a cleanable decal on a turf +/// Use this if your decal is one of one, and thus we should not spawn it if it's there already +/// Returns either the existing cleanable, the one we created, or null if we can't spawn on that turf +/turf/proc/spawn_unique_cleanable(obj/effect/decal/cleanable/cleanable_type) + // There is no need to spam unique cleanables, they don't stack and it just chews cpu + var/obj/effect/decal/cleanable/existing = locate(cleanable_type) in src + if(existing) + return existing + return new cleanable_type(src) + /obj/effect/decal/cleanable/Initialize(mapload, list/datum/disease/diseases) . = ..() if (random_icon_states && (icon_state == initial(icon_state)) && length(random_icon_states) > 0) diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm index bf69a585b39..1c74766ac69 100644 --- a/code/game/objects/effects/decals/decal.dm +++ b/code/game/objects/effects/decals/decal.dm @@ -3,8 +3,6 @@ plane = FLOOR_PLANE anchored = TRUE resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF - ///Boolean on whether this decal can be placed inside of groundless turfs/walls. If FALSE, will runtime and delete if it happens. - var/turf_loc_check = TRUE /obj/effect/decal/Initialize(mapload) . = ..() diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm index 80f393e97db..914b19e6a88 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm @@ -137,7 +137,11 @@ if(!istype(location)) return FALSE - for(var/turf/spread_turf as anything in location.reachableAdjacentTurfs(no_id = TRUE)) + for(var/iter_dir in GLOB.cardinals) + var/turf/spread_turf = get_step(src, iter_dir) + if(spread_turf?.density || spread_turf.LinkBlockedWithAccess(spread_turf, no_id = TRUE)) + continue + var/obj/effect/particle_effect/fluid/foam/foundfoam = locate() in spread_turf //Don't spread foam where there's already foam! if(foundfoam) continue diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 8a709ff4dfc..a0e8d240452 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -38,7 +38,7 @@ //For chemical reactions list lookup list - creates a bit list of info passed to the UI. This is saved to reduce lag from new windows opening, since it's a lot of data. //Prevent these reactions from appearing in lookup tables (UI code) - var/list/blacklist = (/datum/chemical_reaction/randomized) + var/list/blacklist = typecacheof(/datum/chemical_reaction/randomized) if(GLOB.chemical_reactions_list_reactant_index) return @@ -50,60 +50,86 @@ GLOB.chemical_reactions_results_lookup_list = list() //UI glob GLOB.chemical_reactions_list_product_index = list() //product to reaction list + var/list/datum/chemical_reaction/reactions = list() for(var/path in paths) - var/datum/chemical_reaction/D = new path() - var/list/reaction_ids = list() + var/datum/chemical_reaction/reaction = new path() + reactions += reaction + + // Ok so we're gonna do a thingTM here + // I want to distribute all our reactions such that each reagent id links to as few as possible + // I get the feeling there's a canonical way of doing this, but I don't know it + // So instead, we're gonna wing it + var/list/reagent_to_react_count = list() + for(var/datum/chemical_reaction/reaction as anything in reactions) + for(var/reagent_id as anything in reaction.required_reagents) + reagent_to_react_count[reagent_id] += 1 + + var/list/reaction_lookup = GLOB.chemical_reactions_list_reactant_index + // Create filters based on a random reagent id in the required reagents list - this is used to speed up handle_reactions() + // Basically, we only really need to care about ONE reagent, at least when initially filtering, since any others are ignorable + // Doing this separately because it relies on the loop above, and this is easier to parse + for(var/datum/chemical_reaction/reaction as anything in reactions) + var/preferred_id = null + for(var/reagent_id as anything in reaction.required_reagents) + if(!preferred_id) + preferred_id = reagent_id + continue + // If we would have less then they would, take it + if(length(reaction_lookup[reagent_id]) < length(reaction_lookup[preferred_id])) + preferred_id = reagent_id + continue + // If they potentially have more then us, we take it + if(reagent_to_react_count[reagent_id] < reagent_to_react_count[preferred_id]) + preferred_id = reagent_id + continue + + if(!reaction_lookup[preferred_id]) + reaction_lookup[preferred_id] = list() + reaction_lookup[preferred_id] += reaction + + for(var/datum/chemical_reaction/reaction as anything in reactions) var/list/product_ids = list() var/list/reagents = list() var/list/product_names = list() - var/bitflags = D.reaction_tags + var/bitflags = reaction.reaction_tags - if(!D.required_reagents || !D.required_reagents.len) //Skip impossible reactions + if(!reaction.required_reagents || !reaction.required_reagents.len) //Skip impossible reactions continue - GLOB.chemical_reactions_list[path] = D + GLOB.chemical_reactions_list[reaction.type] = reaction - for(var/reaction in D.required_reagents) - reaction_ids += reaction - var/datum/reagent/reagent = find_reagent_object_from_type(reaction) + for(var/reagent_path in reaction.required_reagents) + var/datum/reagent/reagent = find_reagent_object_from_type(reagent_path) if(!istype(reagent)) - stack_trace("Invalid reagent found in [D] required_reagents: [reaction]") + stack_trace("Invalid reagent found in [reaction] required_reagents: [reagent_path]") continue reagents += list(list("name" = reagent.name, "id" = reagent.type)) - for(var/product in D.results) + for(var/product in reaction.results) var/datum/reagent/reagent = find_reagent_object_from_type(product) if(!istype(reagent)) - stack_trace("Invalid reagent found in [D] results: [product]") + stack_trace("Invalid reagent found in [reaction] results: [product]") continue product_names += reagent.name product_ids += product var/product_name if(!length(product_names)) - var/list/names = splittext("[D.type]", "/") + var/list/names = splittext("[reaction.type]", "/") product_name = names[names.len] else product_name = product_names[1] - // Create filters based on each reagent id in the required reagents list - this is specifically for finding reactions from product(reagent) ids/typepaths. - for(var/id in product_ids) - if(is_type_in_list(D.type, blacklist)) - continue - if(!GLOB.chemical_reactions_list_product_index[id]) - GLOB.chemical_reactions_list_product_index[id] = list() - GLOB.chemical_reactions_list_product_index[id] += D + if(!is_type_in_typecache(reaction.type, blacklist)) + //Master list of ALL reactions that is used in the UI lookup table. This is expensive to make, and we don't want to lag the server by creating it on UI request, so it's cached to send to UIs instantly. + GLOB.chemical_reactions_results_lookup_list += list(list("name" = product_name, "id" = reaction.type, "bitflags" = bitflags, "reactants" = reagents)) - //Master list of ALL reactions that is used in the UI lookup table. This is expensive to make, and we don't want to lag the server by creating it on UI request, so it's cached to send to UIs instantly. - if(!(is_type_in_list(D.type, blacklist))) - GLOB.chemical_reactions_results_lookup_list += list(list("name" = product_name, "id" = D.type, "bitflags" = bitflags, "reactants" = reagents)) + // Create filters based on each reagent id in the required reagents list - this is specifically for finding reactions from product(reagent) ids/typepaths. + for(var/id in product_ids) + if(!GLOB.chemical_reactions_list_product_index[id]) + GLOB.chemical_reactions_list_product_index[id] = list() + GLOB.chemical_reactions_list_product_index[id] += reaction - // Create filters based on each reagent id in the required reagents list - this is used to speed up handle_reactions() - for(var/id in reaction_ids) - if(!GLOB.chemical_reactions_list_reactant_index[id]) - GLOB.chemical_reactions_list_reactant_index[id] = list() - GLOB.chemical_reactions_list_reactant_index[id] += D - break // Don't bother adding ourselves to other reagent ids, it is redundant ///////////////////////////////Main reagents code///////////////////////////////////////////// @@ -644,10 +670,8 @@ // pass over previous ongoing reactions before handle_reactions is called transfer_reactions(target_holder) - src.update_total() target_holder.update_total() target_holder.handle_reactions() - src.handle_reactions() return amount @@ -922,70 +946,65 @@ var/list/cached_reactions = GLOB.chemical_reactions_list_reactant_index var/datum/cached_my_atom = my_atom LAZYNULL(failed_but_capable_reactions) + LAZYNULL(previous_reagent_list) . = 0 var/list/possible_reactions = list() for(var/datum/reagent/reagent as anything in cached_reagents) - for(var/datum/chemical_reaction/reaction as anything in cached_reactions[reagent.type]) // Was a big list but now it should be smaller since we filtered it with our reagent id - if(!reaction) - continue + LAZYADD(previous_reagent_list, reagent.type) + // I am SO sorry + reaction_loop: + for(var/datum/chemical_reaction/reaction as anything in cached_reactions[reagent.type]) // Was a big list but now it should be smaller since we filtered it with our reagent id + if(!reaction) + continue - if(!reaction.required_reagents)//Don't bring in empty ones - continue - var/list/cached_required_reagents = reaction.required_reagents - var/total_required_reagents = cached_required_reagents.len - var/total_matching_reagents = 0 - var/list/cached_required_catalysts = reaction.required_catalysts - var/total_required_catalysts = cached_required_catalysts.len - var/total_matching_catalysts= 0 - var/matching_container = FALSE - var/matching_other = FALSE - var/required_temp = reaction.required_temp - var/is_cold_recipe = reaction.is_cold_recipe - var/meets_temp_requirement = FALSE - var/meets_ph_requirement = FALSE - var/granularity = 1 - if(!(reaction.reaction_flags & REACTION_INSTANT)) - granularity = CHEMICAL_VOLUME_MINIMUM + if(!reaction.required_reagents)//Don't bring in empty ones + continue - for(var/req_reagent in cached_required_reagents) - if(!has_reagent(req_reagent, (cached_required_reagents[req_reagent]*granularity))) - break - total_matching_reagents++ - for(var/_catalyst in cached_required_catalysts) - if(!has_reagent(_catalyst, (cached_required_catalysts[_catalyst]*granularity))) - break - total_matching_catalysts++ - if(cached_my_atom) - if(reaction.required_container_accepts_subtypes) - matching_container = !reaction.required_container || istype(cached_my_atom, reaction.required_container) - else - matching_container = !reaction.required_container || cached_my_atom.type == reaction.required_container + var/granularity = 1 + if(!(reaction.reaction_flags & REACTION_INSTANT)) + granularity = CHEMICAL_VOLUME_MINIMUM - if(isliving(cached_my_atom) && !reaction.mob_react) //Makes it so certain chemical reactions don't occur in mobs - matching_container = FALSE + var/list/cached_required_reagents = reaction.required_reagents + for(var/req_reagent in cached_required_reagents) + if(!has_reagent(req_reagent, (cached_required_reagents[req_reagent]*granularity))) + continue reaction_loop - matching_other = reaction.required_other ? reaction.pre_reaction_other_checks(src) : TRUE + var/list/cached_required_catalysts = reaction.required_catalysts + for(var/_catalyst in cached_required_catalysts) + if(!has_reagent(_catalyst, (cached_required_catalysts[_catalyst]*granularity))) + continue reaction_loop - else - if(!reaction.required_container) - matching_container = TRUE - if(!reaction.required_other) - matching_other = TRUE + if(cached_my_atom) + if(reaction.required_container) + if(reaction.required_container_accepts_subtypes && !istype(cached_my_atom, reaction.required_container)) + continue + else if(cached_my_atom.type != reaction.required_container) + continue - if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp)) - meets_temp_requirement = TRUE + if(isliving(cached_my_atom) && !reaction.mob_react) //Makes it so certain chemical reactions don't occur in mobs + continue - if(((ph >= (reaction.optimal_ph_min - reaction.determin_ph_range)) && (ph <= (reaction.optimal_ph_max + reaction.determin_ph_range)))) - meets_ph_requirement = TRUE + else if(reaction.required_container) + continue - if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other) - if(meets_temp_requirement && meets_ph_requirement) - possible_reactions += reaction - else + if(reaction.required_other && !reaction.pre_reaction_other_checks(src)) + continue + + // At this point, we've passed all the hard restrictions and entered into just the soft ones + // So we're gonna start tracking reactions that COULD be completed on continue, instead of just exiting + var/required_temp = reaction.required_temp + var/is_cold_recipe = reaction.is_cold_recipe + if(required_temp != 0 && (is_cold_recipe && chem_temp > required_temp) || (!is_cold_recipe && chem_temp < required_temp)) LAZYADD(failed_but_capable_reactions, reaction) + continue + + if(ph < reaction.optimal_ph_min - reaction.determin_ph_range && ph > reaction.optimal_ph_max + reaction.determin_ph_range) + LAZYADD(failed_but_capable_reactions, reaction) + continue + + possible_reactions += reaction - update_previous_reagent_list() //This is the point where we have all the possible reactions from a reagent/catalyst point of view, so we set up the reaction list for(var/datum/chemical_reaction/selected_reaction as anything in possible_reactions) if((selected_reaction.reaction_flags & REACTION_INSTANT) || (flags & REAGENT_HOLDER_INSTANT_REACT)) //If we have instant reactions, we process them here @@ -1197,11 +1216,6 @@ return TRUE return FALSE -/datum/reagents/proc/update_previous_reagent_list() - LAZYNULL(previous_reagent_list) - for(var/datum/reagent/reagent as anything in reagent_list) - LAZYADD(previous_reagent_list, reagent.type) - ///Old reaction mechanics, edited to work on one only ///This is changed from the old - purity of the reagents will affect yield /datum/reagents/proc/instant_react(datum/chemical_reaction/selected_reaction) @@ -1275,6 +1289,7 @@ /datum/reagents/proc/update_total() var/list/cached_reagents = reagent_list . = 0 // This is a relatively hot proc. + var/total_ph = 0 // I know I know, I'm sorry for(var/datum/reagent/reagent as anything in cached_reagents) if((reagent.volume < 0.05) && !is_reacting) del_reagent(reagent.type) @@ -1282,8 +1297,15 @@ del_reagent(reagent.type) else . += reagent.volume + total_ph += (reagent.ph * reagent.volume) total_volume = . - recalculate_sum_ph() + + if(!.) // No volume, default to the base + ph = CHEMICAL_NORMAL_PH + return . + //Keep limited // should really be defines + ph = clamp(total_ph/total_volume, 0, 14) + /** * Applies the relevant expose_ proc for every reagent in this holder @@ -1301,12 +1323,11 @@ if(isnull(A)) return null - var/list/cached_reagents = reagent_list - if(!cached_reagents.len) + if(!reagent_list.len) return null var/list/reagents = list() - for(var/datum/reagent/reagent as anything in cached_reagents) + for(var/datum/reagent/reagent as anything in reagent_list) reagents[reagent] = reagent.volume * volume_modifier return A.expose_reagents(reagents, src, methods, volume_modifier, show_message) @@ -1554,19 +1575,6 @@ return FALSE reagent.ph = clamp(reagent.ph + value, lower_limit, upper_limit) -/* -* Updates the reagents datum pH based off the volume weighted sum of the reagent_list's reagent pH -*/ -/datum/reagents/proc/recalculate_sum_ph() - if(!reagent_list || !total_volume) //Ensure that this is true - ph = CHEMICAL_NORMAL_PH - return - var/total_ph = 0 - for(var/datum/reagent/reagent as anything in reagent_list) - total_ph += (reagent.ph * reagent.volume) - //Keep limited - ph = clamp(total_ph/total_volume, 0, 14) - /** * Outputs a log-friendly list of reagents based on an external reagent list. * diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 3460331eabd..57383fc35a1 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -444,8 +444,7 @@ . = ..() if(!istype(exposed_turf) || (reac_volume < 1)) return - - new/obj/effect/decal/cleanable/food/salt(exposed_turf) + exposed_turf.spawn_unique_cleanable(/obj/effect/decal/cleanable/food/salt) /datum/reagent/consumable/blackpepper name = "Black Pepper" @@ -615,10 +614,9 @@ if(isspaceturf(exposed_turf)) return - var/obj/effect/decal/cleanable/food/flour/reagentdecal = new(exposed_turf) - reagentdecal = locate() in exposed_turf //Might have merged with flour already there. - if(reagentdecal) - reagentdecal.reagents.add_reagent(/datum/reagent/consumable/flour, reac_volume) + var/obj/effect/decal/cleanable/food/flour/flour_decal = exposed_turf.spawn_unique_cleanable(/obj/effect/decal/cleanable/food/flour) + if(flour_decal) + flour_decal.reagents.add_reagent(/datum/reagent/consumable/flour, reac_volume) /datum/reagent/consumable/cherryjelly name = "Cherry Jelly" diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index e8a32b70f6f..c0e4b7aa1e6 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -937,9 +937,7 @@ if(isspaceturf(exposed_turf)) return - var/obj/effect/decal/cleanable/dirt/dirt_decal = (locate() in exposed_turf.contents) - if(!dirt_decal) - dirt_decal = new(exposed_turf) + exposed_turf.spawn_unique_cleanable(/obj/effect/decal/cleanable/dirt) /datum/reagent/chlorine name = "Chlorine" @@ -1105,9 +1103,7 @@ if((reac_volume < 3) || isspaceturf(exposed_turf)) return - var/obj/effect/decal/cleanable/greenglow/glow = locate() in exposed_turf.contents - if(!glow) - glow = new(exposed_turf) + var/obj/effect/decal/cleanable/greenglow/glow = exposed_turf.spawn_unique_cleanable(/obj/effect/decal/cleanable/greenglow) if(!QDELETED(glow)) glow.reagents.add_reagent(type, reac_volume) @@ -1209,7 +1205,9 @@ if((reac_volume < 5)) return - new /obj/effect/decal/cleanable/fuel_pool(exposed_turf, round(reac_volume / 5)) + var/obj/effect/decal/cleanable/fuel_pool/pool = exposed_turf.spawn_unique_cleanable(/obj/effect/decal/cleanable/fuel_pool) + if(pool) + pool.burn_amount = max(min(round(reac_volume / 5), 10), 1) /datum/reagent/space_cleaner name = "Space Cleaner" @@ -2368,7 +2366,7 @@ . = ..() if(!istype(exposed_turf)) return - new glitter_type(exposed_turf) + exposed_turf.spawn_unique_cleanable(glitter_type) /datum/reagent/glitter/pink name = "Pink Glitter" @@ -2629,7 +2627,7 @@ /datum/reagent/gravitum/expose_obj(obj/exposed_obj, volume) . = ..() exposed_obj.AddElement(/datum/element/forced_gravity, 0) - addtimer(CALLBACK(exposed_obj, PROC_REF(_RemoveElement), list(/datum/element/forced_gravity, 0)), volume * time_multiplier) + addtimer(CALLBACK(exposed_obj, PROC_REF(_RemoveElement), list(/datum/element/forced_gravity, 0)), volume * time_multiplier, TIMER_UNIQUE|TIMER_OVERRIDE) /datum/reagent/gravitum/on_mob_metabolize(mob/living/affected_mob) affected_mob.AddElement(/datum/element/forced_gravity, 0) //0 is the gravity, and in this case weightless @@ -2806,9 +2804,10 @@ if((reac_volume <= 10)) // Makes sure people don't duplicate ants. return - var/obj/effect/decal/cleanable/ants/pests = locate() in exposed_turf.contents + var/obj/effect/decal/cleanable/ants/pests = exposed_turf.spawn_unique_cleanable(/obj/effect/decal/cleanable/ants) if(!pests) - pests = new(exposed_turf) + return + var/spilled_ants = (round(reac_volume,1) - 5) // To account for ant decals giving 3-5 ants on initialize. pests.reagents.add_reagent(/datum/reagent/ants, spilled_ants) pests.update_ant_damage() diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index cb26095badc..a1f10c9afe6 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -17,7 +17,7 @@ var/required_container_accepts_subtypes = FALSE /// If required_container_accepts_subtypes is FALSE, the exact type of what container this reaction can take place in. Otherwise, what type including subtypes are acceptable. var/atom/required_container - /// an integer required for the reaction to happen + /// Set this to true to call pre_reaction_other_checks() on react and do some more interesting reaction logic var/required_other = FALSE ///Determines if a chemical reaction can occur inside a mob