/obj/structure/emergency_shield name = "emergency energy shield" desc = "An energy shield used to contain hull breaches." icon = 'icons/effects/effects.dmi' icon_state = "shield-old" density = TRUE move_resist = INFINITY opacity = 0 anchored = TRUE resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF max_integrity = 200 //The shield can only take so much beating (prevents perma-prisons) CanAtmosPass = ATMOS_PASS_DENSITY /obj/structure/emergency_shield/Initialize() . = ..() setDir(pick(GLOB.cardinals)) air_update_turf(1) /obj/structure/emergency_shield/Move() var/turf/T = loc . = ..() move_update_air(T) /obj/structure/emergency_shield/emp_act(severity) . = ..() if (. & EMP_PROTECT_SELF) return switch(severity) if(1) qdel(src) if(2) take_damage(50, BRUTE, "energy", 0) /obj/structure/emergency_shield/play_attack_sound(damage, damage_type = BRUTE, damage_flag = 0) switch(damage_type) if(BURN) playsound(loc, 'sound/effects/empulse.ogg', 75, 1) if(BRUTE) playsound(loc, 'sound/effects/empulse.ogg', 75, 1) /obj/structure/emergency_shield/take_damage(damage, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) . = ..() if(.) //damage was dealt new /obj/effect/temp_visual/impact_effect/ion(loc) /obj/structure/emergency_shield/sanguine name = "sanguine barrier" desc = "A potent shield summoned by cultists to defend their rites." icon_state = "shield-red" max_integrity = 60 /obj/structure/emergency_shield/sanguine/emp_act(severity) return /obj/structure/emergency_shield/invoker name = "Invoker's Shield" desc = "A weak shield summoned by cultists to protect them while they carry out delicate rituals." color = "#FF0000" max_integrity = 20 mouse_opacity = MOUSE_OPACITY_TRANSPARENT layer = ABOVE_MOB_LAYER /obj/structure/emergency_shield/invoker/emp_act(severity) return /obj/machinery/shieldgen name = "anti-breach shielding projector" desc = "Used to seal minor hull breaches." icon = 'icons/obj/objects.dmi' icon_state = "shieldoff" density = TRUE opacity = 0 anchored = FALSE pressure_resistance = 2*ONE_ATMOSPHERE req_access = list(ACCESS_ENGINE) max_integrity = 100 var/active = FALSE var/list/deployed_shields var/locked = FALSE var/shield_range = 4 /obj/machinery/shieldgen/Initialize(mapload) . = ..() deployed_shields = list() if(mapload && active && anchored) shields_up() /obj/machinery/shieldgen/Destroy() QDEL_LIST(deployed_shields) return ..() /obj/machinery/shieldgen/proc/shields_up() active = TRUE update_icon() move_resist = INFINITY for(var/turf/target_tile in range(shield_range, src)) if(isspaceturf(target_tile) && !(locate(/obj/structure/emergency_shield) in target_tile)) if(!(stat & BROKEN) || prob(33)) deployed_shields += new /obj/structure/emergency_shield(target_tile) /obj/machinery/shieldgen/proc/shields_down() active = FALSE move_resist = initial(move_resist) update_icon() QDEL_LIST(deployed_shields) /obj/machinery/shieldgen/process() if((stat & BROKEN) && active) if(deployed_shields.len && prob(5)) qdel(pick(deployed_shields)) /obj/machinery/shieldgen/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) if(!(stat && BROKEN)) stat |= BROKEN locked = pick(0,1) update_icon() /obj/machinery/shieldgen/interact(mob/user) . = ..() if(.) return if(locked && !hasSiliconAccessInArea(user)) to_chat(user, "The machine is locked, you are unable to use it!") return if(panel_open) to_chat(user, "The panel must be closed before operating this machine!") return if (active) user.visible_message("[user] deactivated \the [src].", \ "You deactivate \the [src].", \ "You hear heavy droning fade out.") shields_down() else if(anchored) user.visible_message("[user] activated \the [src].", \ "You activate \the [src].", \ "You hear heavy droning.") shields_up() else to_chat(user, "The device must first be secured to the floor!") return /obj/machinery/shieldgen/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/screwdriver)) W.play_tool_sound(src, 100) panel_open = !panel_open if(panel_open) to_chat(user, "You open the panel and expose the wiring.") else to_chat(user, "You close the panel.") else if(istype(W, /obj/item/stack/cable_coil) && (stat & BROKEN) && panel_open) var/obj/item/stack/cable_coil/coil = W if (coil.get_amount() < 1) to_chat(user, "You need one length of cable to repair [src]!") return to_chat(user, "You begin to replace the wires...") if(do_after(user, 30, target = src)) if(coil.get_amount() < 1) return coil.use(1) obj_integrity = max_integrity stat &= ~BROKEN to_chat(user, "You repair \the [src].") update_icon() else if(istype(W, /obj/item/wrench)) if(locked) to_chat(user, "The bolts are covered! Unlocking this would retract the covers.") return if(!anchored && !isinspace()) W.play_tool_sound(src, 100) to_chat(user, "You secure \the [src] to the floor!") setAnchored(TRUE) else if(anchored) W.play_tool_sound(src, 100) to_chat(user, "You unsecure \the [src] from the floor!") if(active) to_chat(user, "\The [src] shuts off!") shields_down() setAnchored(FALSE) else if(W.GetID()) if(allowed(user) && !(obj_flags & EMAGGED)) locked = !locked to_chat(user, "You [locked ? "lock" : "unlock"] the controls.") else if(obj_flags & EMAGGED) to_chat(user, "Error, access controller damaged!") else to_chat(user, "Access denied.") else return ..() /obj/machinery/shieldgen/emag_act(mob/user) . = ..() if(obj_flags & EMAGGED) to_chat(user, "The access controller is damaged!") return obj_flags |= EMAGGED locked = FALSE playsound(src, "sparks", 100, 1) to_chat(user, "You short out the access controller.") return TRUE /obj/machinery/shieldgen/update_icon() if(active) icon_state = (stat & BROKEN) ? "shieldonbr":"shieldon" else icon_state = (stat & BROKEN) ? "shieldoffbr":"shieldoff" #define ACTIVE_SETUPFIELDS 1 #define ACTIVE_HASFIELDS 2 /obj/machinery/shieldwallgen name = "shield wall generator" desc = "A shield generator." icon = 'icons/obj/stationobjs.dmi' icon_state = "Shield_Gen" anchored = FALSE density = TRUE req_access = list(ACCESS_TELEPORTER) flags_1 = CONDUCT_1 use_power = NO_POWER_USE max_integrity = 300 var/active = FALSE var/power = 0 var/maximum_stored_power = 500 var/locked = TRUE var/shield_range = 8 var/obj/structure/cable/attached // the attached cable /obj/machinery/shieldwallgen/xenobiologyaccess //use in xenobiology containment name = "xenobiology shield wall generator" desc = "A shield generator meant for use in xenobiology." icon_state = "Shield_Gen" req_access = list(ACCESS_XENOBIOLOGY) /obj/machinery/shieldwallgen/Destroy() for(var/d in GLOB.cardinals) cleanup_field(d) return ..() /obj/machinery/shieldwallgen/proc/power() if(!anchored) power = 0 return var/turf/T = get_turf(src) var/obj/structure/cable/C = T.get_cable_node() var/datum/powernet/PN if(C) PN = C.powernet //find the powernet of the connected cable if(!PN) return var/surplus = max(PN.avail - PN.load, 0) var/avail_power = min(rand(50,200), surplus) if(avail_power) power += avail_power PN.load += avail_power //uses powernet power. /obj/machinery/shieldwallgen/process() power() use_stored_power(50) /obj/machinery/shieldwallgen/proc/use_stored_power(amount) power = CLAMP(power - amount, 0, maximum_stored_power) update_activity() /obj/machinery/shieldwallgen/proc/update_activity() if(active) icon_state = "Shield_Gen +a" if(active == ACTIVE_SETUPFIELDS) var/fields = 0 for(var/d in GLOB.cardinals) if(setup_field(d)) fields++ if(fields) active = ACTIVE_HASFIELDS if(!power) visible_message("The [src.name] shuts down due to lack of power!", \ "You hear heavy droning fade out.") icon_state = "Shield_Gen" active = FALSE for(var/d in GLOB.cardinals) cleanup_field(d) else icon_state = "Shield_Gen" for(var/d in GLOB.cardinals) cleanup_field(d) /obj/machinery/shieldwallgen/proc/setup_field(direction) if(!direction) return var/turf/T = loc var/obj/machinery/shieldwallgen/G var/steps = 0 var/opposite_direction = turn(direction, 180) for(var/i in 1 to shield_range) //checks out to 8 tiles away for another generator T = get_step(T, direction) G = (locate(/obj/machinery/shieldwallgen) in T) if(G) if(!G.active) return G.cleanup_field(opposite_direction) break else steps++ if(!G || !steps) //no shield gen or no tiles between us and the gen return for(var/i in 1 to steps) //creates each field tile T = get_step(T, opposite_direction) new/obj/machinery/shieldwall(T, src, G) return TRUE /obj/machinery/shieldwallgen/proc/cleanup_field(direction) var/obj/machinery/shieldwall/F var/obj/machinery/shieldwallgen/G var/turf/T = loc for(var/i in 1 to shield_range) T = get_step(T, direction) G = (locate(/obj/machinery/shieldwallgen) in T) if(G && !G.active) break F = (locate(/obj/machinery/shieldwall) in T) if(F && (F.gen_primary == src || F.gen_secondary == src)) //it's ours, kill it. qdel(F) /obj/machinery/shieldwallgen/can_be_unfasten_wrench(mob/user, silent) if(active) if(!silent) to_chat(user, "Turn off the shield generator first!") return FAILED_UNFASTEN return ..() /obj/machinery/shieldwallgen/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/wrench)) default_unfasten_wrench(user, W, 0) else if(W.GetID()) if(allowed(user) && !(obj_flags & EMAGGED)) locked = !locked to_chat(user, "You [src.locked ? "lock" : "unlock"] the controls.") else if(obj_flags & EMAGGED) to_chat(user, "Error, access controller damaged!") else to_chat(user, "Access denied.") else add_fingerprint(user) return ..() /obj/machinery/shieldwallgen/interact(mob/user) . = ..() if(.) return if(!anchored) to_chat(user, "\The [src] needs to be firmly secured to the floor first!") return if(locked && !hasSiliconAccessInArea(user)) to_chat(user, "The controls are locked!") return if(!power) to_chat(user, "\The [src] needs to be powered by a wire!") return if(active) user.visible_message("[user] turned \the [src] off.", \ "You turn off \the [src].", \ "You hear heavy droning fade out.") active = FALSE update_activity() else user.visible_message("[user] turned \the [src] on.", \ "You turn on \the [src].", \ "You hear heavy droning.") active = ACTIVE_SETUPFIELDS update_activity() add_fingerprint(user) /obj/machinery/shieldwallgen/emag_act(mob/user) . = ..() if(obj_flags & EMAGGED) to_chat(user, "The access controller is damaged!") return obj_flags |= EMAGGED locked = FALSE playsound(src, "sparks", 100, 1) to_chat(user, "You short out the access controller.") return TRUE //////////////Containment Field START /obj/machinery/shieldwall name = "shield wall" desc = "An energy shield." icon = 'icons/effects/effects.dmi' icon_state = "shieldwall" density = TRUE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF light_range = 3 var/needs_power = FALSE var/obj/machinery/shieldwallgen/gen_primary var/obj/machinery/shieldwallgen/gen_secondary /obj/machinery/shieldwall/Initialize(mapload, obj/machinery/shieldwallgen/first_gen, obj/machinery/shieldwallgen/second_gen) . = ..() gen_primary = first_gen gen_secondary = second_gen if(gen_primary && gen_secondary) needs_power = TRUE setDir(get_dir(gen_primary, gen_secondary)) for(var/mob/living/L in get_turf(src)) visible_message("\The [src] is suddenly occupying the same space as \the [L]!") L.gib() /obj/machinery/shieldwall/Destroy() gen_primary = null gen_secondary = null return ..() /obj/machinery/shieldwall/process() if(needs_power) if(!gen_primary || !gen_primary.active || !gen_secondary || !gen_secondary.active) qdel(src) return drain_power(10) /obj/machinery/shieldwall/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) switch(damage_type) if(BURN) playsound(loc, 'sound/effects/empulse.ogg', 75, 1) if(BRUTE) playsound(loc, 'sound/effects/empulse.ogg', 75, 1) //the shield wall is immune to damage but it drains the stored power of the generators. /obj/machinery/shieldwall/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) . = ..() if(damage_type == BRUTE || damage_type == BURN) drain_power(damage_amount) /obj/machinery/shieldwall/proc/drain_power(drain_amount) if(needs_power && gen_primary) gen_primary.use_stored_power(drain_amount*0.5) if(gen_secondary) //using power may cause us to be destroyed gen_secondary.use_stored_power(drain_amount*0.5) /obj/machinery/shieldwall/CanPass(atom/movable/mover, turf/target) if(istype(mover) && (mover.pass_flags & PASSGLASS)) return prob(20) else if(istype(mover, /obj/item/projectile)) return prob(10) else return !density