diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index f5021385524..2e18aeb1b5c 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -87,3 +87,7 @@ /obj/effect/abstract/marker/intercom name = "intercom range marker" color = COLOR_YELLOW + +/obj/effect/abstract/marker/powernet + name = "powernet run marker" + var/powernet_owner diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 75c3afdc47e..2fd8ca26993 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -956,6 +956,39 @@ ADMIN_VERB(debug_mc_dependencies, R_DEBUG, "Debug MC Dependencies", "Debug MC de var/datum/mc_dependency_ui/data = new /datum/mc_dependency_ui() data.ui_interact(usr) +ADMIN_VERB(show_powernets, R_DEBUG, "Color Powernet Runs", "Colors every node and cable of every powernet in a different color.", ADMIN_CATEGORY_DEBUG) + var/removing = FALSE + for(var/obj/effect/abstract/marker/powernet/marker in GLOB.all_abstract_markers) + qdel(marker) + removing = TRUE + + if(removing) + return + + var/list/colors = GLOB.carp_colors.Copy() + + if(length(colors) < length(SSmachines.powernets)) + message_admins("[SSmachines.powernets.len] powernets exist - [length(colors)] colors available - Some powernets will be the same color!") + + for(var/datum/powernet/net as anything in SSmachines.powernets) + if(!length(colors)) + colors = GLOB.carp_colors.Copy() + + var/selected_color = pick_n_take(colors) + for(var/atom/component as anything in net.nodes + net.cables) + var/turf/component_turf = get_turf(component) + var/existing = FALSE + for(var/obj/effect/abstract/marker/powernet/existing_marker in component_turf) + if(existing_marker.powernet_owner != REF(net)) + continue + existing = TRUE + break + if(existing) + continue + var/obj/effect/abstract/marker/powernet/marker = new(component_turf) + marker.color = selected_color + marker.powernet_owner = REF(net) + ADMIN_VERB(count_instances, R_DEBUG, "Count Atoms/Datums", "Count how many atom or datum instances there are of each type, then output it to a JSON to download.", ADMIN_CATEGORY_DEBUG) var/option = tgui_alert(user, "What type of instances do you wish to count?", "Instance Count", list("Atoms", "Datums")) if(!option) diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index dec4dcf2997..2001f51774a 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -535,13 +535,11 @@ update() if("emergency_lighting") emergency_lights = !emergency_lights - for (var/list/zlevel_turfs as anything in area.get_zlevel_turf_lists()) - for(var/turf/area_turf as anything in zlevel_turfs) - for(var/obj/machinery/light/area_light in area_turf) - if(!initial(area_light.no_low_power)) //If there was an override set on creation, keep that override - area_light.no_low_power = emergency_lights - INVOKE_ASYNC(area_light, TYPE_PROC_REF(/obj/machinery/light/, update), FALSE) - CHECK_TICK + for(var/obj/machinery/light/area_light as anything in get_lights()) + if(!initial(area_light.no_low_power)) //If there was an override set on creation, keep that override + area_light.no_low_power = emergency_lights + INVOKE_ASYNC(area_light, TYPE_PROC_REF(/obj/machinery/light/, update), FALSE) + CHECK_TICK return TRUE /obj/machinery/power/apc/ui_close(mob/user) @@ -549,6 +547,15 @@ if(user == remote_control_user) disconnect_remote_access() +/// Returns a list of lights powered/controlled by src +/obj/machinery/power/apc/proc/get_lights() + var/list/lights = list() + for(var/list/zlevel_turfs as anything in area.get_zlevel_turf_lists()) + for(var/turf/area_turf as anything in zlevel_turfs) + for(var/obj/machinery/light/found_light in area_turf) + lights += found_light + return lights + /** * APC early processing. This gets processed after any other machine on the powernet does. * This adds up the total static power usage for the apc's area, then draw that power usage from the grid or APC cell. @@ -726,12 +733,10 @@ INVOKE_ASYNC(src, PROC_REF(break_lights)) /obj/machinery/power/apc/proc/break_lights() - for (var/list/zlevel_turfs as anything in area.get_zlevel_turf_lists()) - for(var/turf/area_turf as anything in zlevel_turfs) - for(var/obj/machinery/light/breaked_light in area_turf) - breaked_light.on = TRUE - breaked_light.break_light_tube() - stoplag() + for(var/obj/machinery/light/breaked_light as anything in get_lights()) + breaked_light.on = TRUE + breaked_light.break_light_tube() + CHECK_TICK /obj/machinery/power/apc/should_atmos_process(datum/gas_mixture/air, exposed_temperature) return (exposed_temperature > 2000) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 678b0770aea..968db84a535 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -24,6 +24,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list( layer = WIRE_LAYER //Above hidden pipes, GAS_PIPE_HIDDEN_LAYER anchored = TRUE obj_flags = CAN_BE_HIT + max_integrity = 50 var/linked_dirs = 0 //bitflag var/node = FALSE //used for sprites display var/cable_layer = CABLE_LAYER_2 //bitflag @@ -148,6 +149,18 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list( var/obj/item/stack/cable_coil/cable = new(drop_location(), 1) cable.set_cable_color(cable_color) +/obj/structure/cable/atom_destruction(damage_flag) + if(!powernet || damage_flag != BOMB) + return ..() + + powernet.propagate_light_flicker(src) + return ..() + +/obj/structure/cable/run_atom_armor(damage_amount, damage_type, damage_flag, attack_dir, armour_penetration) + if(damage_flag == BOMB && HAS_TRAIT(src, TRAIT_UNDERFLOOR)) + damage_amount *= 0.25 + return ..() + /////////////////////////////////// // General procedures /////////////////////////////////// diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm index 88aa3b7655f..810b01533d6 100644 --- a/code/modules/power/powernet.dm +++ b/code/modules/power/powernet.dm @@ -13,6 +13,9 @@ var/netexcess = 0 // excess power on the powernet (typically avail-load)/////// var/delayedload = 0 // load applied to powernet between power ticks. + /// If a run of propagate_light_flicker is ongoing + VAR_PRIVATE/flickering = FALSE + /datum/powernet/New() SSmachines.powernets += src @@ -96,3 +99,37 @@ // Mostly just a wrapper for sending the COMSIG_POWERNET_CIRCUIT_TRANSMISSION signal, but could be retooled in the future to give it other uses /datum/powernet/proc/data_transmission(list/data, encryption_key, datum/weakref/port) SEND_SIGNAL(src, COMSIG_POWERNET_CIRCUIT_TRANSMISSION, list("data" = data, "enc_key" = encryption_key, "port" = port)) + +/** + * Triggers lights connected to this powernet to flicker a few times + * + * * flicker_source - The center of the flicker. If null the whole powernet will flicker + * * falloff_distance - Only relevant if you passed a source. Areas beyond this distance will be less and less likely to flicker. + */ +/datum/powernet/proc/propagate_light_flicker(atom/flicker_source, falloff_distance = 64) + if(flickering || !length(nodes)) + return + + flickering = TRUE + var/most_flickers = 1 + for(var/obj/machinery/power/terminal/terminal in nodes) + if(!istype(terminal.master, /obj/machinery/power/apc)) + continue + + if(isnull(flicker_source)) + if(!prob(95)) + continue + else + var/flicker_prob = 95 + (3 * (falloff_distance - get_dist(flicker_source, terminal))) + if(!prob(min(95, flicker_prob))) + continue + + var/flicker_count = rand(1, 3) + most_flickers = max(most_flickers, flicker_count) + var/obj/machinery/power/apc/apc = terminal.master + for(var/obj/machinery/light/light as anything in apc.get_lights()) + light.flicker(flicker_count) + CHECK_TICK + + // don't let another flicker propagation until our slowest area is done (with some added leeway) + addtimer(VARSET_CALLBACK(src, flickering, FALSE), most_flickers * 2 SECONDS)