From 923cbe2ea855fd90ba10b7e50cb35c92b33c64a8 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sun, 7 Aug 2022 06:51:22 +0200 Subject: [PATCH] [MIRROR] Radiation pulses will yield to MC for every turf they iterate through. [MDB IGNORE] (#15446) * Radiation pulses will yield to MC for every turf they iterate through. (#68525) * Be less scary. Changes radiation pulses so that they store the turfs they need to irradiate, iterate through them and remove them from the list of turfs to irradiate, then yield to MC if MC got angry, and put the radiation pulse with the remaining turfs to irradiate to the back of the radiation processing list. Radiation pulses pulse information will no longer popleft the processing list. It will delete itself once there are no turfs to process, or if the source is null. Caches the turfs to process to loop through, adds a counter for how many turfs it iterated through, and cuts the turfs to process by the turfs that got iterated. * Radiation pulses will yield to MC for every turf they iterate through. Co-authored-by: Pickle-Coding <58013024+Pickle-Coding@users.noreply.github.com> --- code/__HELPERS/radiation.dm | 2 + code/controllers/subsystem/radiation.dm | 103 +++++++++++++----------- 2 files changed, 59 insertions(+), 46 deletions(-) diff --git a/code/__HELPERS/radiation.dm b/code/__HELPERS/radiation.dm index 345d2f89196..465c60b594c 100644 --- a/code/__HELPERS/radiation.dm +++ b/code/__HELPERS/radiation.dm @@ -35,6 +35,7 @@ pulse_information.threshold = threshold pulse_information.chance = chance pulse_information.minimum_exposure_time = minimum_exposure_time + pulse_information.turfs_to_process = RANGE_TURFS(max_range, source) SSradiation.processing += pulse_information @@ -46,6 +47,7 @@ var/threshold var/chance var/minimum_exposure_time + var/list/turfs_to_process #define MEDIUM_RADIATION_THRESHOLD_RANGE 0.5 #define EXTREME_RADIATION_CHANCE 30 diff --git a/code/controllers/subsystem/radiation.dm b/code/controllers/subsystem/radiation.dm index e6913998a96..b2b3d1926dd 100644 --- a/code/controllers/subsystem/radiation.dm +++ b/code/controllers/subsystem/radiation.dm @@ -10,11 +10,12 @@ SUBSYSTEM_DEF(radiation) /datum/controller/subsystem/radiation/fire(resumed) while (processing.len) - var/datum/radiation_pulse_information/pulse_information = popleft(processing) + var/datum/radiation_pulse_information/pulse_information = processing[1] var/datum/weakref/source_ref = pulse_information.source_ref var/atom/source = source_ref.resolve() if (isnull(source)) + processing.Cut(1, 2) continue pulse(source, pulse_information) @@ -22,71 +23,81 @@ SUBSYSTEM_DEF(radiation) if (MC_TICK_CHECK) return + processing.Cut(1, 2) + /datum/controller/subsystem/radiation/stat_entry(msg) msg = "[msg] | Pulses: [processing.len]" return ..() /datum/controller/subsystem/radiation/proc/pulse(atom/source, datum/radiation_pulse_information/pulse_information) var/list/cached_rad_insulations = list() + var/list/cached_turfs_to_process = pulse_information.turfs_to_process + var/turfs_iterated = 0 + for (var/turf/turf_to_irradiate as anything in cached_turfs_to_process) + turfs_iterated += 1 + for (var/atom/movable/target in turf_to_irradiate) + if (!can_irradiate_basic(target)) + continue - for (var/atom/movable/target in range(pulse_information.max_range, source)) - if (!can_irradiate_basic(target)) - continue + var/current_insulation = 1 - var/current_insulation = 1 + for (var/turf/turf_in_between in get_line(source, target) - get_turf(source)) + var/insulation = cached_rad_insulations[turf_in_between] + if (isnull(insulation)) + insulation = turf_in_between.rad_insulation + for (var/atom/on_turf as anything in turf_in_between.contents) + insulation *= on_turf.rad_insulation + cached_rad_insulations[turf_in_between] = insulation - for (var/turf/turf_in_between in get_line(source, target) - get_turf(source)) - var/insulation = cached_rad_insulations[turf_in_between] - if (isnull(insulation)) - insulation = turf_in_between.rad_insulation - for (var/atom/on_turf as anything in turf_in_between.contents) - insulation *= on_turf.rad_insulation - cached_rad_insulations[turf_in_between] = insulation + current_insulation *= insulation - current_insulation *= insulation + if (current_insulation <= pulse_information.threshold) + break + + SEND_SIGNAL(target, COMSIG_IN_RANGE_OF_IRRADIATION, pulse_information, current_insulation) + + // Check a second time, because of TRAIT_BYPASS_EARLY_IRRADIATED_CHECK + if (HAS_TRAIT(target, TRAIT_IRRADIATED)) + continue if (current_insulation <= pulse_information.threshold) - break + continue - SEND_SIGNAL(target, COMSIG_IN_RANGE_OF_IRRADIATION, pulse_information, current_insulation) + /// Perceived chance of target getting irradiated. + var/perceived_chance + /// Intensity variable which will describe the radiation pulse. + /// It is used by perceived intensity, which diminishes over range. The chance of the target getting irradiated is determined by perceived_intensity. + /// Intensity is calculated so that the chance of getting irradiated at half of the max range is the same as the chance parameter. + var/intensity + /// Diminishes over range. Used by perceived chance, which is the actual chance to get irradiated. + var/perceived_intensity - // Check a second time, because of TRAIT_BYPASS_EARLY_IRRADIATED_CHECK - if (HAS_TRAIT(target, TRAIT_IRRADIATED)) - continue + if(pulse_information.chance < 100) // Prevents log(0) runtime if chance is 100% + intensity = -log(1 - pulse_information.chance / 100) * (1 + pulse_information.max_range / 2) ** 2 + perceived_intensity = intensity * INVERSE((1 + get_dist_euclidian(source, target)) ** 2) // Diminishes over range. + perceived_intensity *= (current_insulation - pulse_information.threshold) * INVERSE(1 - pulse_information.threshold) // Perceived intensity decreases as objects that absorb radiation block its trajectory. + perceived_chance = 100 * (1 - NUM_E ** -perceived_intensity) + else + perceived_chance = 100 - if (current_insulation <= pulse_information.threshold) - continue + var/irradiation_result = SEND_SIGNAL(target, COMSIG_IN_THRESHOLD_OF_IRRADIATION, pulse_information) + if (irradiation_result & CANCEL_IRRADIATION) + continue - /// Perceived chance of target getting irradiated. - var/perceived_chance - /// Intensity variable which will describe the radiation pulse. - /// It is used by perceived intensity, which diminishes over range. The chance of the target getting irradiated is determined by perceived_intensity. - /// Intensity is calculated so that the chance of getting irradiated at half of the max range is the same as the chance parameter. - var/intensity - /// Diminishes over range. Used by perceived chance, which is the actual chance to get irradiated. - var/perceived_intensity + if (pulse_information.minimum_exposure_time && !(irradiation_result & SKIP_MINIMUM_EXPOSURE_TIME_CHECK)) + target.AddComponent(/datum/component/radiation_countdown, pulse_information.minimum_exposure_time) + continue - if(pulse_information.chance < 100) // Prevents log(0) runtime if chance is 100% - intensity = -log(1 - pulse_information.chance / 100) * (1 + pulse_information.max_range / 2) ** 2 - perceived_intensity = intensity * INVERSE((1 + get_dist_euclidian(source, target)) ** 2) // Diminishes over range. - perceived_intensity *= (current_insulation - pulse_information.threshold) * INVERSE(1 - pulse_information.threshold) // Perceived intensity decreases as objects that absorb radiation block its trajectory. - perceived_chance = 100 * (1 - NUM_E ** -perceived_intensity) - else - perceived_chance = 100 + if (!prob(perceived_chance)) + continue - var/irradiation_result = SEND_SIGNAL(target, COMSIG_IN_THRESHOLD_OF_IRRADIATION, pulse_information) - if (irradiation_result & CANCEL_IRRADIATION) - continue + if (irradiate_after_basic_checks(target)) + target.investigate_log("was irradiated by [source].", INVESTIGATE_RADIATION) - if (pulse_information.minimum_exposure_time && !(irradiation_result & SKIP_MINIMUM_EXPOSURE_TIME_CHECK)) - target.AddComponent(/datum/component/radiation_countdown, pulse_information.minimum_exposure_time) - continue + if(MC_TICK_CHECK) + break - if (!prob(perceived_chance)) - continue - - if (irradiate_after_basic_checks(target)) - target.investigate_log("was irradiated by [source].", INVESTIGATE_RADIATION) + cached_turfs_to_process.Cut(1, turfs_iterated + 1) /// Will attempt to irradiate the given target, limited through IC means, such as radiation protected clothing. /datum/controller/subsystem/radiation/proc/irradiate(atom/target)