[MIRROR] Modular Shield Generators, Also Adds a new perimeter algorithm to _helpers/math_dm [MDB IGNORE] (#21426)

* Modular Shield Generators, Also Adds a new perimeter algorithm to _helpers/math_dm (#75328)

Disclaimer im mostly making this pr for the experience if anything.
Also anyone can replace the sprites if they want to I`m just making them
so itl be done, idk what a plasteel machine is supposed to look like.

The circuit boards to make these machines are unlocked by the advanced
power manipulation tech

The entire shield

- Has one big healthpool (base of 50)
- Has a configurable radius
- Takes damage from hot gas and emp
- Has regeneration (it gets nerfed by alot of things that I have to talk
about separately)
- When the shield is broken the generator must regenerate at 0.25x speed
before coming online again
- can be configured to either only generate a shield externally (in
space) or both internally and externally at the cost of half the regen
rate
- Regen rate is also reduced based on the ratio of the shield radius and
the max radius that the generator is capable of generating
- Alot more that im too tired to explain at the moment

The base stats of the shield (max health, regen rate, max radius) all
scale with the tier of parts used in the main generator.

4 other machines (3 are finished code-wise as of now) the charger (regen
rate), the relay (max radius) the well (max health) the node (allows for
more connections) can all be connected to the main generator to boost
its core stats based on their part tiers

In the future there is a possibility of specialization / modifications
to the forcefield at the cost to the core stats

* Modular Shield Generators, Also Adds a new perimeter algorithm to _helpers/math_dm

---------

Co-authored-by: moocowswag <62126254+moocowswag@users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-05-25 23:13:30 +01:00
committed by GitHub
co-authored by moocowswag
parent 72743383ca
commit f3d405da28
8 changed files with 965 additions and 8 deletions
+35
View File
@@ -80,6 +80,41 @@
line += locate(current_x_step, current_y_step, starting_z)
return line
/**
* Get a list of turfs in a perimeter given the `center_atom` and `radius`.
* Automatically rounds down decimals and does not accept values less than positive 1 as they dont play well with it.
* Is efficient on large circles but ugly on small ones
* Uses [Jesko`s method to the midpoint circle Algorithm](https://en.wikipedia.org/wiki/Midpoint_circle_algorithm).
*/
/proc/get_perimeter(atom/center, radius)
if(radius < 1)
return
var/rounded_radius = round(radius)
var/x = center.x
var/y = center.y
var/z = center.z
var/t1 = rounded_radius/16
var/dx = rounded_radius
var/dy = 0
var/t2
var/list/perimeter = list()
while(dx >= dy)
perimeter += locate(x + dx, y + dy, z)
perimeter += locate(x - dx, y + dy, z)
perimeter += locate(x + dx, y - dy, z)
perimeter += locate(x - dx, y - dy, z)
perimeter += locate(x + dy, y + dx, z)
perimeter += locate(x - dy, y + dx, z)
perimeter += locate(x + dy, y - dx, z)
perimeter += locate(x - dy, y - dx, z)
dy += 1
t1 += dy
t2 = t1 - dx
if(t2 > 0)
t1 = t2
dx -= 1
return perimeter
///Format a power value in W, kW, MW, or GW.
/proc/display_power(powerused)
if(powerused < 1000) //Less than a kW
+684
View File
@@ -0,0 +1,684 @@
/obj/machinery/modular_shield_generator
name = "Modular Shield Generator"
desc = "A forcefield generator, it seems more stationary than its cousins."
icon = 'icons/obj/machines/modular_shield_generator.dmi'
icon_state = "gen_recovering_closed"
density = TRUE
circuit = /obj/item/circuitboard/machine/modular_shield_generator
processing_flags = START_PROCESSING_ON_INIT
///Doesnt actually control it, just tells us if its running or not, you can control by calling procs activate_shields and deactivate_shields
var/active = FALSE
///If the generator is currently spawning the forcefield in
var/initiating = FALSE
///Determins if we can turn it on or not, no longer recovering when back to max strength
var/recovering = TRUE
///Determins max health of the shield
var/max_strength = 40
///Current health of shield
var/stored_strength = 0 //starts at 0 to prevent rebuild abuse
///Shield Regeneration when at 100% efficiency
var/max_regeneration = 3
///The regeneration that the shield can support
var/current_regeneration
///Determins the max radius the shield can support
var/max_radius = 3
///Current radius the shield is set to, minimum 3
var/radius = 3
///Determins if we only generate a shield on space turfs or not
var/exterior_only = FALSE
///The lazy list of shields that are ours
var/list/deployed_shields
///The lazy list of turfs that are within the shield
var/list/inside_shield
///The lazy list of machines that are connected to and boosting us
var/list/obj/machinery/modular_shield/module/connected_modules
///Regeneration gained from machines connected to us
var/regen_boost = 0
///Max Radius gained from machines connected to us
var/radius_boost = 0
///Max Strength gained from machines connected to us
var/max_strength_boost = 0
///Regeneration gained from our own parts
var/innate_regen = 3
///Max radius gained from our own parts
var/innate_radius = 3
///Max strength gained from our own parts
var/innate_strength = 40
///This is the lazy list of perimeter turfs that we grab when making large shields of 10 or more radius
var/list/list_of_turfs
/obj/machinery/modular_shield_generator/power_change()
. = ..()
if(!(machine_stat & NOPOWER))
begin_processing()
return
deactivate_shields()
end_processing()
/obj/machinery/modular_shield_generator/RefreshParts()
. = ..()
innate_regen = initial(innate_regen)
innate_radius = initial(innate_radius)
innate_strength = initial(innate_strength)
for(var/datum/stock_part/capacitor/new_capacitor in component_parts)
innate_strength += new_capacitor.tier * 10
for(var/datum/stock_part/servo/new_servo in component_parts)
innate_regen += new_servo.tier
for(var/datum/stock_part/micro_laser/new_laser in component_parts)
innate_radius += new_laser.tier * 0.25
calculate_regeneration()
calculate_max_strength()
calculate_radius()
/obj/machinery/modular_shield_generator/Initialize(mapload)
. = ..()
wires = new /datum/wires/modular_shield_generator(src)
if(mapload && active && anchored)
activate_shields()
/datum/wires/modular_shield_generator
proper_name = "Modular shield generator"
randomize = FALSE
holder_type = /obj/machinery/modular_shield_generator
/datum/wires/modular_shield_generator/New(atom/holder)
wires = list(WIRE_HACK)
return ..()
/datum/wires/modular_shield_generator/on_pulse(wire)
var/obj/machinery/modular_shield_generator/shield_gen = holder
switch(wire)
if(WIRE_HACK)
shield_gen.toggle_shields()
return ..()
///qdels the forcefield and calls calculate regen to update the regen value accordingly
/obj/machinery/modular_shield_generator/proc/deactivate_shields()
active = FALSE
QDEL_LIST(deployed_shields)
deployed_shields = null
LAZYNULL(list_of_turfs)
LAZYNULL(inside_shield)
calculate_regeneration()
/obj/machinery/modular_shield_generator/screwdriver_act(mob/living/user, obj/item/tool)
. = ..()
if(default_deconstruction_screwdriver(user,"gen_[!(machine_stat & NOPOWER) ? "[recovering ? "recovering_" : "ready_"]" : "no_power_"]open",
"gen_[!(machine_stat & NOPOWER) ? "[recovering ? "recovering_" : "ready_"]" : "no_power_"]closed", tool))
return TRUE
/obj/machinery/modular_shield_generator/crowbar_act(mob/living/user, obj/item/tool)
. = ..()
if(default_deconstruction_crowbar(tool))
return TRUE
/obj/machinery/modular_shield_generator/attackby(obj/item/W, mob/user, params)
if(is_wire_tool(W) && panel_open)
wires.interact(user)
return TRUE
return ..()
///toggles the forcefield on and off
/obj/machinery/modular_shield_generator/proc/toggle_shields()
if(initiating)
return
if(active)
deactivate_shields()
return
if (recovering)
return
activate_shields()
///generates the forcefield based on the given radius and calls calculate_regen to update the regen value accordingly
/obj/machinery/modular_shield_generator/proc/activate_shields()
if(active)//bug or did admin call proc on already active shield gen?
return
if(radius < 0)//what the fuck are admins doing
radius = initial(radius)
active = TRUE
initiating = TRUE
if(radius >= 10) //the shield is large so we are going to use the midpoint formula and clamp it to the lowest full number in order to save processing power
LAZYADD(inside_shield, circle_range_turfs(src, radius - 1))//in the future we might want to apply an effect to turfs inside the shield
LAZYADD(list_of_turfs, get_perimeter(src, radius))
if(exterior_only)
for(var/turf/target_tile as anything in list_of_turfs)
if(isspaceturf(target_tile) && !(target_tile in inside_shield) && !(locate(/obj/structure/emergency_shield/modular) in target_tile))
var/obj/structure/emergency_shield/modular/deploying_shield = new(target_tile)
deploying_shield.shield_generator = src
LAZYADD(deployed_shields, deploying_shield)
addtimer(CALLBACK(src, PROC_REF(finish_field)), 2 SECONDS)
calculate_regeneration()
return
for(var/turf/target_tile as anything in list_of_turfs)
if(isopenturf(target_tile) && !(target_tile in inside_shield) && !(locate(/obj/structure/emergency_shield/modular) in target_tile))
var/obj/structure/emergency_shield/modular/deploying_shield = new(target_tile)
deploying_shield.shield_generator = src
LAZYADD(deployed_shields, deploying_shield)
addtimer(CALLBACK(src, PROC_REF(finish_field)), 2 SECONDS)
calculate_regeneration()
return
//this code only runs on radius less than 10 and gives us a more accurate circle that is more compatible with decimal values
LAZYADD(inside_shield, circle_range_turfs(src, radius - 1))//in the future we might want to apply an effect to the turfs inside the shield
if(exterior_only)
for(var/turf/target_tile as anything in circle_range_turfs(src, radius))
if(isspaceturf(target_tile) && !(target_tile in inside_shield) && !(locate(/obj/structure/emergency_shield/modular) in target_tile))
var/obj/structure/emergency_shield/modular/deploying_shield = new(target_tile)
deploying_shield.shield_generator = src
LAZYADD(deployed_shields, deploying_shield)
addtimer(CALLBACK(src, PROC_REF(finish_field)), 2 SECONDS)
calculate_regeneration()
return
for(var/turf/target_tile as anything in circle_range_turfs(src, radius))
if(isopenturf(target_tile) && !(target_tile in inside_shield) && !(locate(/obj/structure/emergency_shield/modular) in target_tile))
var/obj/structure/emergency_shield/modular/deploying_shield = new(target_tile)
deploying_shield.shield_generator = src
LAZYADD(deployed_shields, deploying_shield)
addtimer(CALLBACK(src, PROC_REF(finish_field)), 2 SECONDS)
calculate_regeneration()
///After giving people a grace period to react to we up the alpha value and make the forcefield dense
/obj/machinery/modular_shield_generator/proc/finish_field()
for(var/obj/structure/emergency_shield/modular/current_shield in deployed_shields)
current_shield.density = TRUE
current_shield.alpha = 255
initiating = FALSE
/obj/machinery/modular_shield_generator/Destroy()
QDEL_LIST(deployed_shields)
return ..()
/obj/machinery/modular_shield_generator/update_icon_state()
icon_state = ("gen_[!(machine_stat & NOPOWER) ? "[recovering ? "recovering_" : "ready_"]" : "no_power_"][(panel_open)?"open" : "closed"]")
return ..()
//ui stuff
/obj/machinery/modular_shield_generator/ui_interact(mob/user, datum/tgui/ui)
. = ..()
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ModularShieldGen")
ui.open()
/obj/machinery/modular_shield_generator/ui_data(mob/user)
var/list/data = list()
data["max_radius"] = max_radius
data["current_radius"] = radius
data["max_strength"] = max_strength
data["max_regeneration"] = max_regeneration
data["current_regeneration"] = current_regeneration
data["current_strength"] = stored_strength
data["active"] = active
data["recovering"] = recovering
data["exterior_only"] = exterior_only
data["initiating_field"] = initiating
return data
/obj/machinery/modular_shield_generator/ui_act(action, params)
. = ..()
if(.)
return
switch(action)
if ("set_radius")
if (active)
return
var/change_radius = max(1,(text2num(params["new_radius"])))
if(change_radius >= 10)
radius = round(change_radius)//if its over 10 we dont allow decimals
return
radius = change_radius
if ("toggle_shields")
toggle_shields()
if ("toggle_exterior")
exterior_only = !exterior_only
///calculations for the stats supplied by the network of machines that boost us
/obj/machinery/modular_shield_generator/proc/calculate_boost()
regen_boost = initial(regen_boost)
for (var/obj/machinery/modular_shield/module/charger/new_charger in connected_modules)
regen_boost += new_charger.charge_boost
calculate_regeneration()
max_strength_boost = initial(max_strength_boost)
for (var/obj/machinery/modular_shield/module/well/new_well in connected_modules)
max_strength_boost += new_well.strength_boost
calculate_max_strength()
radius_boost = initial(radius_boost)
for (var/obj/machinery/modular_shield/module/relay/new_relay in connected_modules)
radius_boost += new_relay.range_boost
calculate_radius()
///Calculates the max radius the shield generator can support, modifiers go here
/obj/machinery/modular_shield_generator/proc/calculate_radius()
max_radius = innate_radius + radius_boost
if(radius > max_radius)//the generator can no longer function at this capacity
deactivate_shields()
radius = max_radius
///Calculates the max strength or health of the forcefield, modifiers go here
/obj/machinery/modular_shield_generator/proc/calculate_max_strength()
max_strength = innate_strength + max_strength_boost
begin_processing()
///Calculates the regeneration based on the status of the generator and boosts from network, modifiers go here
/obj/machinery/modular_shield_generator/proc/calculate_regeneration()
max_regeneration = innate_regen + regen_boost
if(!active)
if(recovering)
current_regeneration = max_regeneration * 0.25
return
current_regeneration = max_regeneration
return
//we lose more than half the regeneration rate when generating a shield that is near the max
//radius that we can handle but if we generate a shield with a very small fraction
//of the max radius we can support we get a very small bonus multiplier
current_regeneration = (max_regeneration / (0.5 + (radius * 2)/max_radius))
if(!exterior_only)
current_regeneration *= 0.5
///Reduces the strength of the shield based on the given integer
/obj/machinery/modular_shield_generator/proc/shield_drain(damage_amount)
stored_strength -= damage_amount
begin_processing()
if (stored_strength < 5)
recovering = TRUE
deactivate_shields()
stored_strength = 0
update_icon_state()
/obj/machinery/modular_shield_generator/process(seconds_per_tick)
stored_strength = min((stored_strength + (current_regeneration * seconds_per_tick)),max_strength)
if(stored_strength == max_strength)
if (recovering)
recovering = FALSE
calculate_regeneration()
update_icon_state()
end_processing() //we dont care about continuing to update the alpha, we want to show history of damage to show its unstable
if (active)
var/random_num = rand(1,deployed_shields.len)
var/obj/structure/emergency_shield/modular/random_shield = deployed_shields[random_num]
random_shield.alpha = max(255 * (stored_strength/max_strength), 40)
//Start of other machines
///The general code used for machines that want to connect to the network
/obj/machinery/modular_shield/module
name = "Modular Shield Debugger" //Filler name and sprite for testing
desc = "This is filler for testing you shouldn`t see this."
icon = 'icons/mecha/mech_bay.dmi'
icon_state = "recharge_port"
density = TRUE
///The shield generator we are connected to if we find one or a node provides us one
var/obj/machinery/modular_shield_generator/shield_generator
///The node we are connected to if we find one
var/obj/machinery/modular_shield/module/node/connected_node
///This is the turf that we are facing and able to search for connections through
var/turf/connected_turf
/obj/machinery/modular_shield/module/Initialize(mapload)
. = ..()
connected_turf = get_step(loc, dir)
/obj/machinery/modular_shield/module/Destroy()
if(shield_generator)
LAZYREMOVE(shield_generator.connected_modules, (src))
shield_generator.calculate_boost()
if(connected_node)
LAZYREMOVE(connected_node.connected_through_us, (src))
return ..()
/obj/machinery/modular_shield/module/examine(mob/user)
. = ..()
if(isnull(shield_generator) && isnull(connected_node))
. += "It can be loosened and rotated with a screwdriver and wrench. It can be connected to a node or generator with a multitool."
return
. += "It can be loosed and rotated with a screwdriver and wrench, rotating it will sever its connection."
/obj/machinery/modular_shield/module/screwdriver_act(mob/living/user, obj/item/tool)
. = ..()
panel_open = !(panel_open)
tool.play_tool_sound(src, 50)
update_icon_state()
if(panel_open)
balloon_alert(user, "hatch opened")
return TRUE
balloon_alert(user, "hatch closed")
return TRUE
/obj/machinery/modular_shield/module/multitool_act(mob/living/user, obj/item/tool)
. = ..()
//rather than automatically checking for connections its probably alot less
//expensive to just make the players manually multi tool sync each part
try_connect(user)
return TRUE
/obj/machinery/modular_shield/module/wrench_act(mob/living/user, obj/item/tool)
. = ..()
if(default_change_direction_wrench(user, tool))
if(shield_generator)
LAZYREMOVE(shield_generator.connected_modules, (src))
shield_generator.calculate_boost()
shield_generator = null
update_icon_state()
if(connected_node)
LAZYREMOVE(connected_node.connected_through_us, (src))
connected_node = null
connected_turf = get_step(loc, dir)
return TRUE
/obj/machinery/modular_shield/module/crowbar_act(mob/living/user, obj/item/tool)
. = ..()
if(default_deconstruction_crowbar(tool))
return TRUE
/obj/machinery/modular_shield/module/setDir(new_dir)
. = ..()
connected_turf = get_step(loc, dir)
///checks for a valid machine in front of us and connects to it
/obj/machinery/modular_shield/module/proc/try_connect(user)
if(shield_generator || connected_node)
balloon_alert(user, "already connected to something!")
return
shield_generator = (locate(/obj/machinery/modular_shield_generator) in connected_turf)
if(shield_generator)
LAZYOR(shield_generator.connected_modules, (src))
balloon_alert(user, "connected to generator")
update_icon_state()
shield_generator.calculate_boost()
return
connected_node = (locate(/obj/machinery/modular_shield/module/node) in connected_turf)
if(connected_node)
LAZYOR(connected_node.connected_through_us, (src))
shield_generator = connected_node.shield_generator
if(shield_generator)
LAZYOR(shield_generator.connected_modules, (src))
balloon_alert(user, "connected to generator")
update_icon_state()
shield_generator.calculate_boost()
return
balloon_alert(user, "connected to node")
return
balloon_alert(user, "no connection!")
/obj/machinery/modular_shield/module/node
name = "Modular Shield Node"
desc = "A waist high mess of humming pipes and wires that extend the modular shield network."
icon = 'icons/obj/machines/modular_shield_generator.dmi'
icon_state = "node_off_closed"
active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.5
circuit = /obj/item/circuitboard/machine/modular_shield_node
///The lazy list of machines that are connected to us and want connection to a generator
var/list/connected_through_us
/obj/machinery/modular_shield/module/node/update_icon_state()
. = ..()
if(isnull(shield_generator) || (machine_stat & NOPOWER))
icon_state = "node_off_[panel_open ? "open" : "closed"]"
return
icon_state = "node_on_[panel_open ? "open" : "closed"]"
/obj/machinery/modular_shield/module/node/setDir(new_dir)
. = ..()
disconnect_connected_through_us()
if(isnull(shield_generator))
return
LAZYREMOVE(shield_generator.connected_modules, (src))
shield_generator.calculate_boost()
shield_generator = null
update_icon_state()
//after trying to connect to a machine infront of us, we will try to link anything connected to us to a generator
/obj/machinery/modular_shield/module/node/try_connect(user)
. = ..()
if(isnull(shield_generator))
return
connect_connected_through_us()
shield_generator.calculate_boost()
/obj/machinery/modular_shield/module/node/Destroy()
. = ..()
disconnect_connected_through_us()
for(var/obj/machinery/modular_shield/module/connected in connected_through_us)
connected.connected_node = null
if(shield_generator)
shield_generator.calculate_boost()
///If we are connected to a shield generator this proc will connect anything connected to us to that generator
/obj/machinery/modular_shield/module/node/proc/connect_connected_through_us()
if(shield_generator)
for(var/obj/machinery/modular_shield/module/connected in connected_through_us)
LAZYOR(shield_generator.connected_modules, connected)
connected.shield_generator = shield_generator
if(istype(connected, /obj/machinery/modular_shield/module/node))
var/obj/machinery/modular_shield/module/node/connected_node = connected
connected_node.connect_connected_through_us()
connected.update_icon_state()
///This proc disconnects modules connected through us from the shield generator in the event that we lose connection
/obj/machinery/modular_shield/module/node/proc/disconnect_connected_through_us()
for(var/obj/machinery/modular_shield/module/connected in connected_through_us)
LAZYREMOVE(shield_generator.connected_modules, connected)
if(istype(connected, /obj/machinery/modular_shield/module/node))
var/obj/machinery/modular_shield/module/node/connected_node = connected
connected_node.disconnect_connected_through_us()
connected.shield_generator = null
connected.update_icon_state()
/obj/machinery/modular_shield/module/charger
name = "Modular Shield Charger"
desc = "A machine that somehow fabricates hardlight using electrons."
icon = 'icons/obj/machines/modular_shield_generator.dmi'
icon_state = "charger_off_closed"
circuit = /obj/item/circuitboard/machine/modular_shield_charger
///Amount of regeneration this machine grants the connected generator
var/charge_boost = 0
/obj/machinery/modular_shield/module/charger/update_icon_state()
. = ..()
if(isnull(shield_generator) || (machine_stat & NOPOWER))
icon_state = "charger_off_[panel_open ? "open" : "closed"]"
return
icon_state = "charger_on_[panel_open ? "open" : "closed"]"
/obj/machinery/modular_shield/module/charger/RefreshParts()
. = ..()
charge_boost = initial(charge_boost)
for(var/datum/stock_part/servo/new_servo in component_parts)
charge_boost += new_servo.tier
if(shield_generator)
shield_generator.calculate_boost()
/obj/machinery/modular_shield/module/relay
name = "Modular Shield Relay"
desc = "It helps the shield generator project farther out."
icon = 'icons/obj/machines/modular_shield_generator.dmi'
icon_state = "relay_off_closed"
circuit = /obj/item/circuitboard/machine/modular_shield_relay
///Amount of max range this machine grants the connected generator
var/range_boost = 0
/obj/machinery/modular_shield/module/relay/update_icon_state()
. = ..()
if(isnull(shield_generator) || (machine_stat & NOPOWER))
icon_state = "relay_off_[panel_open ? "open" : "closed"]"
return
icon_state = "relay_on_[panel_open ? "open" : "closed"]"
/obj/machinery/modular_shield/module/relay/RefreshParts()
. = ..()
range_boost = initial(range_boost)
for(var/datum/stock_part/micro_laser/new_laser in component_parts)
range_boost += new_laser.tier * 0.25
if(shield_generator)
shield_generator.calculate_boost()
/obj/machinery/modular_shield/module/well
name = "Modular Shield Well"
desc = "A device used to hold more hardlight for the modular shield generator."
icon = 'icons/obj/machines/modular_shield_generator.dmi'
icon_state = "well_off_closed"
circuit = /obj/item/circuitboard/machine/modular_shield_well
///Amount of max strength this machine grants the connected generator
var/strength_boost = 0
/obj/machinery/modular_shield/module/well/RefreshParts()
. = ..()
strength_boost = initial(strength_boost)
for(var/datum/stock_part/capacitor/new_capacitor in component_parts)
strength_boost += new_capacitor.tier * 10
if(shield_generator)
shield_generator.calculate_boost()
/obj/machinery/modular_shield/module/well/update_icon_state()
. = ..()
if(isnull(shield_generator) || (machine_stat & NOPOWER))
icon_state = "well_off_[panel_open ? "open" : "closed"]"
return
icon_state = "well_on_[panel_open ? "open" : "closed"]"
//The shield itself
/obj/structure/emergency_shield/modular
name = "Modular energy shield"
desc = "An energy shield with varying configurations."
color = "#00ffff"
density = FALSE
alpha = 100
resistance_flags = INDESTRUCTIBLE //the shield itself is indestructible or atleast should be
///The shield generator sustaining us
var/obj/machinery/modular_shield_generator/shield_generator
/obj/structure/emergency_shield/modular/Initialize(mapload)
. = ..()
AddElement(/datum/element/atmos_sensitive, mapload)
/obj/structure/emergency_shield/modular/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
return exposed_temperature > (T0C + 400) //starts taking damage from high temps at the same temperature that nonreinforced glass does
//Damage from atmos
/obj/structure/emergency_shield/modular/atmos_expose(datum/gas_mixture/air, exposed_temperature)
if(isnull(shield_generator))
qdel(src)
return
shield_generator.shield_drain(round(air.return_volume() / 400))//400 integer determines how much damage the shield takes from hot atmos (higher value = less damage)
//Damage from direct attacks
/obj/structure/emergency_shield/modular/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
if(damage_type == BRUTE || damage_type == BURN)
if(isnull(shield_generator))
qdel(src)
return
shield_generator.shield_drain(damage_amount)//can add or subtract a flat value to buff or nerf crowd damage
//Damage from emp
/obj/structure/emergency_shield/modular/emp_act(severity)
if(isnull(shield_generator))
qdel(src)
return
shield_generator.shield_drain(15 / severity) //Light is 2 heavy is 1, note emp is usually a large aoe, tweak the number if not enough damage
@@ -82,7 +82,8 @@
/obj/item/stack/cable_coil = 1,
/datum/stock_part/filter = 1,
/datum/stock_part/crystal = 1,
/datum/stock_part/micro_laser = 2)
/datum/stock_part/micro_laser = 2,
)
/obj/item/circuitboard/machine/telecomms/bus
name = "Bus Mainframe"
@@ -91,7 +92,8 @@
req_components = list(
/datum/stock_part/servo = 2,
/obj/item/stack/cable_coil = 1,
/datum/stock_part/filter = 1)
/datum/stock_part/filter = 1,
)
/obj/item/circuitboard/machine/telecomms/hub
name = "Hub Mainframe"
@@ -100,7 +102,8 @@
req_components = list(
/datum/stock_part/servo = 2,
/obj/item/stack/cable_coil = 2,
/datum/stock_part/filter = 2)
/datum/stock_part/filter = 2,
)
/obj/item/circuitboard/machine/telecomms/message_server
name = "Messaging Server"
@@ -109,7 +112,8 @@
req_components = list(
/datum/stock_part/servo = 2,
/obj/item/stack/cable_coil = 1,
/datum/stock_part/filter = 3)
/datum/stock_part/filter = 3,
)
/obj/item/circuitboard/machine/telecomms/processor
name = "Processor Unit"
@@ -121,7 +125,8 @@
/datum/stock_part/treatment = 2,
/datum/stock_part/analyzer = 1,
/obj/item/stack/cable_coil = 2,
/datum/stock_part/amplifier = 1)
/datum/stock_part/amplifier = 1,
)
/obj/item/circuitboard/machine/telecomms/receiver
name = "Subspace Receiver"
@@ -131,7 +136,8 @@
/datum/stock_part/ansible = 1,
/datum/stock_part/filter = 1,
/datum/stock_part/servo = 2,
/datum/stock_part/micro_laser = 1)
/datum/stock_part/micro_laser = 1,
)
/obj/item/circuitboard/machine/telecomms/relay
name = "Relay Mainframe"
@@ -140,7 +146,8 @@
req_components = list(
/datum/stock_part/servo = 2,
/obj/item/stack/cable_coil = 2,
/datum/stock_part/filter = 2)
/datum/stock_part/filter = 2,
)
/obj/item/circuitboard/machine/telecomms/server
name = "Telecommunication Server"
@@ -149,7 +156,8 @@
req_components = list(
/datum/stock_part/servo = 2,
/obj/item/stack/cable_coil = 1,
/datum/stock_part/filter = 1)
/datum/stock_part/filter = 1,
)
/obj/item/circuitboard/machine/tesla_coil
name = "Tesla Controller"
@@ -159,6 +167,53 @@
req_components = list(/datum/stock_part/capacitor = 1)
needs_anchored = FALSE
/obj/item/circuitboard/machine/modular_shield_generator
name = "Modular Shield Generator"
greyscale_colors = CIRCUIT_COLOR_ENGINEERING
build_path = /obj/machinery/modular_shield_generator
req_components = list(
/datum/stock_part/servo = 1,
/datum/stock_part/micro_laser = 1,
/datum/stock_part/capacitor = 1,
/obj/item/stack/sheet/plasteel = 3,
)
/obj/item/circuitboard/machine/modular_shield_node
name = "Modular Shield Node"
greyscale_colors = CIRCUIT_COLOR_ENGINEERING
build_path = /obj/machinery/modular_shield/module/node
req_components = list(
/obj/item/stack/cable_coil = 15,
/obj/item/stack/sheet/plasteel = 2,
)
/obj/item/circuitboard/machine/modular_shield_well
name = "Modular Shield Well"
greyscale_colors = CIRCUIT_COLOR_ENGINEERING
build_path = /obj/machinery/modular_shield/module/well
req_components = list(
/datum/stock_part/capacitor = 3,
/obj/item/stack/sheet/plasteel = 2,
)
/obj/item/circuitboard/machine/modular_shield_relay
name = "Modular Shield Relay"
greyscale_colors = CIRCUIT_COLOR_ENGINEERING
build_path = /obj/machinery/modular_shield/module/relay
req_components = list(
/datum/stock_part/micro_laser = 3,
/obj/item/stack/sheet/plasteel = 2,
)
/obj/item/circuitboard/machine/modular_shield_charger
name = "Modular Shield Charger"
greyscale_colors = CIRCUIT_COLOR_ENGINEERING
build_path = /obj/machinery/modular_shield/module/charger
req_components = list(
/datum/stock_part/servo = 3,
/obj/item/stack/sheet/plasteel = 2,
)
/obj/item/circuitboard/machine/cell_charger
name = "Cell Charger"
greyscale_colors = CIRCUIT_COLOR_ENGINEERING
@@ -167,6 +167,56 @@
)
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE
/datum/design/board/modular_shield_generator
name = "Modular Shield Generator Board"
desc = "The circuit board for a modular shield generator."
id = "modular_shield_generator"
build_path = /obj/item/circuitboard/machine/modular_shield_generator
category = list(
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ENGINEERING
)
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
/datum/design/board/modular_shield_node
name = "Modular Shield Node Board"
desc = "The circuit board for a modular shield node."
id = "modular_shield_node"
build_path = /obj/item/circuitboard/machine/modular_shield_node
category = list(
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ENGINEERING
)
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
/datum/design/board/modular_shield_relay
name = "Modular Shield Relay Board"
desc = "The circuit board for a modular shield relay."
id = "modular_shield_relay"
build_path = /obj/item/circuitboard/machine/modular_shield_relay
category = list(
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ENGINEERING
)
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
/datum/design/board/modular_shield_charger
name = "Modular Shield Charger Board"
desc = "The circuit board for a modular shield charger."
id = "modular_shield_charger"
build_path = /obj/item/circuitboard/machine/modular_shield_charger
category = list(
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ENGINEERING
)
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
/datum/design/board/modular_shield_well
name = "Modular Shield Well Board"
desc = "The circuit board for a modular shield well."
id = "modular_shield_well"
build_path = /obj/item/circuitboard/machine/modular_shield_well
category = list(
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ENGINEERING
)
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
/datum/design/board/teleconsole
name = "Teleporter Console Board"
desc = "Allows for the construction of circuit boards used to build a teleporter control console."
@@ -708,6 +708,11 @@
"turbine_compressor",
"turbine_rotor",
"turbine_stator",
"modular_shield_generator",
"modular_shield_node",
"modular_shield_relay",
"modular_shield_charger",
"modular_shield_well",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500)
discount_experiments = list(/datum/experiment/scanning/points/machinery_pinpoint_scan/tier2_capacitors = 2500)
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

+1
View File
@@ -1645,6 +1645,7 @@
#include "code\game\machinery\mechlaunchpad.dm"
#include "code\game\machinery\medical_kiosk.dm"
#include "code\game\machinery\medipen_refiller.dm"
#include "code\game\machinery\modular_shield.dm"
#include "code\game\machinery\navbeacon.dm"
#include "code\game\machinery\PDApainter.dm"
#include "code\game\machinery\prisongate.dm"
@@ -0,0 +1,127 @@
import { useBackend } from '../backend';
import { Window } from '../layouts';
import { Stack, Section, ProgressBar, Button, NumberInput, LabeledList } from '../components';
import { BooleanLike } from 'common/react';
type ModularShieldGenData = {
max_strength: number;
current_strength: number;
max_regeneration: number;
current_regeneration: number;
max_radius: number;
current_radius: number;
active: BooleanLike;
recovering: BooleanLike;
exterior_only: BooleanLike;
initiating_field: BooleanLike;
};
export const ModularShieldGen = (props, context) => {
const { topLevel } = props;
const { act, data } = useBackend<ModularShieldGenData>(context);
const {
max_strength,
max_regeneration,
current_regeneration,
max_radius,
current_radius,
current_strength,
active,
exterior_only,
recovering,
initiating_field,
} = data;
return (
<Window title="Modular Shield Generator" width={690} height={225}>
<Window.Content>
<Stack fill>
<Stack.Item grow={2}>
<Section
title="Shield Strength"
color={recovering ? 'red' : 'white'}>
<ProgressBar
title="Shield Strength"
value={current_strength}
maxValue={max_strength}
ranges={{
'good': [max_strength * 0.75, max_strength],
'average': [max_strength * 0.25, max_strength * 0.75],
'bad': [0, max_strength * 0.25],
}}>
{current_strength}/{max_strength}
</ProgressBar>
</Section>
<Section title="Regeneration and Radius">
<ProgressBar
title="Regeneration rate"
value={current_regeneration}
maxValue={max_regeneration}
ranges={{
'good': [max_regeneration * 0.75, max_regeneration],
'average': [max_regeneration * 0.25, max_regeneration * 0.75],
'bad': [0, max_regeneration * 0.25],
}}>
Regeneration {current_regeneration}/{max_regeneration}
</ProgressBar>
<Section>
<ProgressBar
title="Shield radius"
value={current_radius}
maxValue={max_radius}
ranges={{
'good': [max_radius * 0.75, max_radius],
'average': [max_radius * 0.25, max_radius * 0.75],
'bad': [0, max_radius * 0.25],
}}>
Radius {current_radius}/{max_radius}
</ProgressBar>
</Section>
</Section>
</Stack.Item>
<Stack.Item grow>
<Section title="Settings">
<LabeledList>
<LabeledList.Item label="Set Radius">
<NumberInput
disabled={active}
fluid
value={current_radius}
minValue={3}
maxValue={max_radius}
onChange={(e, value) =>
act('set_radius', {
new_radius: value,
})
}
/>
</LabeledList.Item>
<LabeledList.Item label="Limitations">
<Button
disabled={active}
onClick={() => act('toggle_exterior')}>
{exterior_only ? 'External only' : 'Internal & External'}
</Button>
</LabeledList.Item>
</LabeledList>
</Section>
<Section>
<LabeledList>
<LabeledList.Item label="Toggle Power">
<Button
bold={1}
disabled={recovering || initiating_field}
selected={active}
content={active ? 'On' : 'Off'}
icon="power-off"
onClick={() => act('toggle_shields')}
/>
</LabeledList.Item>
</LabeledList>
</Section>
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);
};