mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 04:30:44 +01:00
## About The Pull Request Adds modular shield gates and puts them in holographics research (This is the final machine to be added to holographics, if anymore are added they will be put into a brand new adv holographics tech) It can be rotated with screwdriver (to open panel) and wrench It has NO ui (its meant to be used with either a remote signaler or modular shield console in another PR) It takes NO penalty from generating tiles indoors It projects a field until either its max range has been reached or it comes across a closed turf or shield that blocks it. Regeneration rate is still based on how many tiles it projected vs the maximum theoretical range it can project at, meaning relays are still useful. Infact its very inefficient at longer ranges (which is why it's called a gate and not a directional generator, because you will most likely use it like a gate) its screwdrivered in the video thats why the connections are broken.. https://github.com/user-attachments/assets/4536dd5c-a515-43fc-9186-bbd2fc21b703 Makes hulks deal 30 + shield regeneration rate instead of 100+ (remember shields don't have any armor or damage deflection) Has shields block clicks on things under them (mandatory for the shield gate) Shields now react better to explosions and atmos (they used to not block either with barely any interaction) HALVES the bubble shield generator's max radius when set to project tiles in doors (similar to regen) Doubles capacity and regen (if used indoors this is not a large buff because max radius impacts the regen calculation) ## Why It's Good For The Game Allows engineers to use up excess power to further manipulate their environment to produce complicated doorways, walls, and containment fields that are nonharmful but still meaningful as breaching them is an easy fix. Modular shield generators are meant to be progressive content that engineers can mess with throughout an ENTIRE round, giving them a generator subtype that give them a bit more fine control with how to use them seems essential. Alot of people have asked me why the generator is so weak and told me its trash, ive kept it weak because it affects a large area, outside in space thats not a big deal, but inside the station its incredibly powerful to just drop a 300 health bullet sponge wherever you want it by ramping up the radius and blocking someone from entering/exiting a room (this is similar to closing a door behind someone as ai except you're completely surrounding them with that one door.) This is deceptively powerful and by nerfing the radius indoors it's much harder to abuse, which means that shield can now be somewhat stronger without being oppressive. ## Changelog 🆑 add: Modular shield gates which project a shield in a line and does not suffer indoor penalties. balance: Modular shields now better interact with and block atmos and explosions and melee for what they are protecting, hulks are able to take one down eventually no matter what. balance: Modular shields now suffer a severe range penalty when generating indoors but are more potent in their capacity to endure damage. image: modular shield gate sprites /🆑 --------- Co-authored-by: Kapu1178 <75460809+Kapu1178@users.noreply.github.com>
871 lines
30 KiB
Plaintext
871 lines
30 KiB
Plaintext
/obj/machinery/modular_shield_generator
|
|
name = "modular shield generator"
|
|
desc = "A forcefield generator, it seems more stationary than its cousins. It can't handle G-force and will require frequent reboots when built on mobile craft."
|
|
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
|
|
|
|
///Doesn't 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
|
|
|
|
///Determines if we can turn it on or not, no longer recovering when back to max strength
|
|
var/recovering = TRUE
|
|
|
|
///Determines 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
|
|
|
|
///Determines the max radius the shield can support
|
|
var/max_radius = 3
|
|
|
|
///Current radius the shield is set to, minimum 3
|
|
var/radius = 3
|
|
|
|
///Determines 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
|
|
|
|
///This decides if we get nerfed by projecting on internal turfs with floors and stuff
|
|
var/internal_penalty = TRUE
|
|
|
|
///What machine we are for the purpose of updating icon state
|
|
var/icon_type = "gen"
|
|
|
|
///The name modular shield console tgui's see us as
|
|
var/display_name = "Shield Generator"
|
|
|
|
/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 * 20
|
|
|
|
for(var/datum/stock_part/servo/new_servo in component_parts)
|
|
innate_regen += new_servo.tier * 2
|
|
|
|
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)
|
|
. = ..()
|
|
set_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,"[icon_type]_[!(machine_stat & NOPOWER) ? "[recovering ? "recovering_" : "ready_"]" : "no_power_"]open",
|
|
"[icon_type]_[!(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, list/modifiers)
|
|
|
|
if(is_wire_tool(W) && panel_open)
|
|
wires.interact(user)
|
|
return TRUE
|
|
|
|
return ..()
|
|
|
|
/obj/machinery/modular_shield_generator/multitool_act(mob/living/user, obj/item/multitool/multi)
|
|
multi.set_buffer(src)
|
|
balloon_alert(user, "saved to buffer")
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
///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()
|
|
|
|
/obj/machinery/modular_shield_generator/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
|
|
. = ..()
|
|
if(active)
|
|
deactivate_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 || (machine_stat & NOPOWER))//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
|
|
var/color_shield = cached_color_filter || color
|
|
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/open/target_tile in list_of_turfs)
|
|
if(isfloorturf(target_tile))
|
|
continue
|
|
if(locate(/obj/structure/emergency_shield/modular) in target_tile)
|
|
continue
|
|
var/obj/structure/emergency_shield/modular/deploying_shield = new(target_tile, src)
|
|
LAZYADD(deployed_shields, deploying_shield)
|
|
if(color_shield)
|
|
deploying_shield.add_atom_colour(color_shield, FIXED_COLOUR_PRIORITY)
|
|
addtimer(CALLBACK(src, PROC_REF(finish_field)), 2 SECONDS)
|
|
calculate_regeneration()
|
|
return
|
|
|
|
for(var/turf/open/target_tile in list_of_turfs)
|
|
if(locate(/obj/structure/emergency_shield/modular) in target_tile)
|
|
continue
|
|
var/obj/structure/emergency_shield/modular/deploying_shield = new(target_tile, src)
|
|
LAZYADD(deployed_shields, deploying_shield)
|
|
if(color_shield)
|
|
deploying_shield.add_atom_colour(color_shield, FIXED_COLOUR_PRIORITY)
|
|
|
|
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/open/target_tile in circle_range_turfs(src, radius))
|
|
if(isfloorturf(target_tile))
|
|
continue
|
|
if(target_tile in inside_shield)
|
|
continue
|
|
if(locate(/obj/structure/emergency_shield/modular) in target_tile)
|
|
continue
|
|
var/obj/structure/emergency_shield/modular/deploying_shield = new(target_tile, src)
|
|
LAZYADD(deployed_shields, deploying_shield)
|
|
if(color_shield)
|
|
deploying_shield.add_atom_colour(color_shield, FIXED_COLOUR_PRIORITY)
|
|
|
|
addtimer(CALLBACK(src, PROC_REF(finish_field)), 2 SECONDS)
|
|
calculate_regeneration()
|
|
return
|
|
|
|
for(var/turf/open/target_tile in circle_range_turfs(src, radius))
|
|
if(target_tile in inside_shield)
|
|
continue
|
|
if(locate(/obj/structure/emergency_shield/modular) in target_tile)
|
|
continue
|
|
var/obj/structure/emergency_shield/modular/deploying_shield = new(target_tile, src)
|
|
LAZYADD(deployed_shields, deploying_shield)
|
|
if(color_shield)
|
|
deploying_shield.add_atom_colour(color_shield, FIXED_COLOUR_PRIORITY)
|
|
|
|
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.set_density(TRUE)
|
|
current_shield.alpha = 255
|
|
initiating = FALSE
|
|
|
|
/obj/machinery/modular_shield_generator/Destroy()
|
|
QDEL_LIST(deployed_shields)
|
|
for(var/obj/machinery/modular_shield/module/disconnecting in connected_modules)
|
|
disconnecting.shield_generator = null
|
|
disconnecting.update_icon_state()
|
|
return ..()
|
|
|
|
/obj/machinery/modular_shield_generator/update_icon_state()
|
|
|
|
icon_state = ("[icon_type]_[!(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, list/params, datum/tgui/ui, datum/ui_state/state)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
switch(action)
|
|
if ("set_radius")
|
|
if (active)
|
|
return
|
|
var/change_radius = clamp(text2num(params["new_radius"]), 1, max_radius)
|
|
if(change_radius >= 10)
|
|
radius = round(change_radius)//if its over 10 we don't allow decimals
|
|
return
|
|
radius = change_radius
|
|
|
|
if ("toggle_shields")
|
|
toggle_shields()
|
|
|
|
if ("toggle_exterior")
|
|
exterior_only = !exterior_only
|
|
calculate_radius()
|
|
|
|
///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(!exterior_only && internal_penalty)
|
|
max_radius = max(3,max_radius * 0.5)
|
|
|
|
if(radius > max_radius)//the generator can no longer function at this capacity
|
|
deactivate_shields()
|
|
radius = round(max_radius, 1)
|
|
return
|
|
calculate_regeneration()
|
|
|
|
///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 && internal_penalty)
|
|
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 don't 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)
|
|
|
|
/obj/machinery/modular_shield_generator/gate
|
|
name = "modular shield gate"
|
|
desc = "A forcefield generator that can deploy a flat wall, it seems more stationary than its cousins. It can't handle G-force and will require frequent reboots when built on mobile craft."
|
|
icon = 'icons/obj/machines/modular_shield_generator.dmi'
|
|
icon_state = "gate_recovering_closed"
|
|
density = FALSE
|
|
circuit = /obj/item/circuitboard/machine/modular_shield_generator/gate
|
|
internal_penalty = FALSE
|
|
layer = GIB_LAYER
|
|
icon_type = "gate"
|
|
display_name = "Shield Gate"
|
|
|
|
/obj/machinery/modular_shield_generator/gate/ui_interact(mob/user, datum/tgui/ui)
|
|
return
|
|
|
|
/obj/machinery/modular_shield_generator/gate/wrench_act(mob/living/user, obj/item/tool)
|
|
. = ..()
|
|
|
|
if(!default_change_direction_wrench(user, tool))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
///we shield a tile and step forward until we either run out of max radius or hit a closed turf, every turf we shield is a penalty towards regen
|
|
/obj/machinery/modular_shield_generator/gate/activate_shields()
|
|
if(active || (machine_stat & NOPOWER))//bug or did admin call proc on already active shield gen?
|
|
return
|
|
if(max_radius < 0)//what the fuck are admins doing
|
|
calculate_radius()
|
|
active = TRUE
|
|
initiating = TRUE
|
|
var/color_shield = cached_color_filter || color
|
|
var/turf/target_tile = src.loc
|
|
radius = 0
|
|
for(var/i in 1 to round(max_radius, 1))
|
|
if((!isopenturf(target_tile)) || (locate(/obj/structure/emergency_shield/modular) in target_tile))
|
|
addtimer(CALLBACK(src, PROC_REF(finish_field)), 2 SECONDS)
|
|
calculate_regeneration()
|
|
if(radius == 0)//we couldnt even generate a single tile somehow
|
|
deactivate_shields()
|
|
return
|
|
var/obj/structure/emergency_shield/modular/deploying_shield = new(target_tile, src)
|
|
LAZYADD(deployed_shields, deploying_shield)
|
|
if(color_shield)
|
|
deploying_shield.add_atom_colour(color_shield, FIXED_COLOUR_PRIORITY)
|
|
radius += 1
|
|
target_tile = get_step(target_tile,dir)
|
|
addtimer(CALLBACK(src, PROC_REF(finish_field)), 2 SECONDS)
|
|
calculate_regeneration()
|
|
|
|
//if we are active we most definitely have something protecting us
|
|
/obj/machinery/modular_shield_generator/gate/take_damage()
|
|
if(active)
|
|
return
|
|
. = ..()
|
|
|
|
//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/obj/machines/mech_bay.dmi'
|
|
icon_state = "recharge_port"
|
|
density = TRUE
|
|
|
|
///This var is what determines if boosters, such as charger or well, can connect to this module
|
|
var/allow_boosters = TRUE
|
|
|
|
///This var is what determines if we are a booster or a logistic module
|
|
var/is_booster = FALSE
|
|
|
|
///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(src, dir)
|
|
try_connect()
|
|
|
|
/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))
|
|
connected_node.update_icon_state()
|
|
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))
|
|
return FALSE
|
|
|
|
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.update_icon_state()
|
|
connected_node = null
|
|
|
|
connected_turf = get_step(src, dir)
|
|
try_connect()
|
|
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(src, 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!")
|
|
update_icon_state()
|
|
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)
|
|
|
|
//checks if the node allows boosters and if we are a booster
|
|
if(!connected_node.allow_boosters && is_booster)
|
|
connected_node = null
|
|
update_icon_state()
|
|
balloon_alert(user, "cant connect")
|
|
return
|
|
|
|
LAZYOR(connected_node.connected_through_us, (src))
|
|
connected_node.update_icon_state()
|
|
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
|
|
update_icon_state()
|
|
balloon_alert(user, "connected to node")
|
|
return
|
|
update_icon_state()
|
|
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/wrench_act(mob/living/user, obj/item/tool)
|
|
|
|
if(!default_change_direction_wrench(user, tool))
|
|
return FALSE
|
|
|
|
disconnect_connected_through_us()
|
|
|
|
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.update_icon_state()
|
|
connected_node = null
|
|
|
|
connected_turf = get_step(src, dir)
|
|
try_connect()
|
|
return TRUE
|
|
|
|
//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/node/cable
|
|
name = "modular shield cable"
|
|
desc = "An ankle high mess of cables packed as low as possible at the cost of lacking connection components necessary for anything other than nodes and the generator itself."
|
|
icon = 'icons/obj/machines/modular_shield_generator.dmi'
|
|
icon_state = "cable_node_closed_r_b_l"
|
|
active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.1
|
|
circuit = /obj/item/circuitboard/machine/modular_shield_cable
|
|
density = FALSE
|
|
allow_boosters = FALSE
|
|
|
|
/obj/machinery/modular_shield/module/node/cable/update_icon_state()
|
|
. = ..()
|
|
var/turf/right_turf = get_step(src, turn(dir, 270))
|
|
var/obj/machinery/modular_shield/module/node/connected_right = (locate(/obj/machinery/modular_shield/module/node) in right_turf)
|
|
if(!(connected_right in connected_through_us))
|
|
connected_right = null
|
|
var/turf/back_turf = get_step(src, turn(dir, 180))
|
|
var/obj/machinery/modular_shield/module/node/connected_back = (locate(/obj/machinery/modular_shield/module/node) in back_turf)
|
|
if(!(connected_back in connected_through_us))
|
|
connected_back = null
|
|
var/turf/left_turf = get_step(src, turn(dir, 90))
|
|
var/obj/machinery/modular_shield/module/node/connected_left = (locate(/obj/machinery/modular_shield/module/node) in left_turf)
|
|
if(!(connected_left in connected_through_us))
|
|
connected_left = null
|
|
icon_state = "cable_node_[panel_open ? "open" : "closed"]_[connected_right ? "r" : "nr"]_[connected_back ? "b" : "nb"]_[connected_left ? "l" : "nl"]"
|
|
|
|
/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"
|
|
is_booster = TRUE
|
|
|
|
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 * 2
|
|
|
|
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"
|
|
is_booster = TRUE
|
|
|
|
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"
|
|
is_booster = TRUE
|
|
|
|
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 * 20
|
|
|
|
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
|
|
flags_1 = PREVENT_CLICK_UNDER_1
|
|
explosion_block = 2
|
|
resistance_flags = INDESTRUCTIBLE //the shield itself is indestructible or at least should be
|
|
no_damage_feedback = "weakening the generator sustaining it"
|
|
can_atmos_pass = ATMOS_PASS_NO
|
|
|
|
///The shield generator sustaining us
|
|
var/obj/machinery/modular_shield_generator/shield_generator
|
|
|
|
|
|
/obj/structure/emergency_shield/modular/Initialize(mapload, connected_to_generator)
|
|
AddElement(/datum/element/blocks_explosives)
|
|
. = ..()
|
|
if(!connected_to_generator)
|
|
return INITIALIZE_HINT_QDEL
|
|
shield_generator = connected_to_generator
|
|
AddElement(/datum/element/atmos_sensitive, mapload)
|
|
|
|
/obj/structure/emergency_shield/modular/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
|
|
return exposed_temperature > (T0C + 200)
|
|
|
|
//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
|
|
|
|
//Damage from explosions, remember we dont use armor
|
|
/obj/structure/emergency_shield/modular/ex_act(severity)
|
|
if(isnull(shield_generator))
|
|
qdel(src)
|
|
return
|
|
|
|
switch(severity)
|
|
|
|
if(EXPLODE_LIGHT)
|
|
shield_generator.shield_drain(20)
|
|
return
|
|
|
|
if(EXPLODE_HEAVY)
|
|
shield_generator.shield_drain(50)
|
|
return
|
|
|
|
if(EXPLODE_DEVASTATE)
|
|
shield_generator.shield_drain(100)
|
|
|
|
/obj/structure/emergency_shield/modular/hulk_damage()
|
|
if(isnull(shield_generator))
|
|
qdel(src)
|
|
return 0
|
|
shield_generator.shield_drain(30 + shield_generator.current_regeneration)//shield will eventually go down no matter the regen, flat number is how fast the hulk eats at reserves
|
|
return 0
|