mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-23 04:51:32 +01:00
Engineering spriting (detailing & port), portable shield balance, bugfixes (#21862)
EXTREMELY MINOR MISCELLANEOUS CHANGES TEEHEE changes: - imageadd: "Adds +bolted, +welded, +lights overlays to several large machines for easier visual identification of whether or not clicking on that emitter will kill you or not, etc." - imageadd: "Modifies the base of the Shield Wall Generator sprite to better match that of the Emergency Shield Projector (and so they can use the same overlays mentioned above)." - imageadd: "Tweaks the Emitter's directional sprites slightly so that the base doesn't seem to change shape quite so drastically when rotated." - imageadd: "Ports very pretty space heater sprites made by Wallemations and vinylspiders from /tg/." - imageadd: "Adds unique sprites for Old and Heavy-Duty power cells." - balance: "Increases power draw and range of Emergency Shield Projectors." - balance: "Increases power draw of Shield Wall Generators." - balance: "Greatly reduces time for debugger to fix APCs corrupted by electrical storms." - balance: "Increases multi-z shield capacitor reserve charge and maximum throughput, so that high-strength shields can actually be run (at high power draw)." - balance: "Tweaks the INDRA power output formula to scale better with increasing temperature." - balance: "Slight adjustments to space heater efficiency formula with a friendly handwave to entropy." - balance: "Old power cells have a 5% chance to be defective and have slightly lower maxcharge than standard cells." - qol: "Adds extended examine hints to engineering objects." - qol: "Extends list of object types which INDRA core field will interact peacefully with." - qol: "Improved space heater UX (chat msgs changed to balloon alerts, audible feedback, etc.)" - code_imp: "Updates many code comments to use DMdocs." - code_imp: "Consolidates various shield generation machine sprites in scattered across multiple files into a single shield generator machines sprite file." - bugfix: "Fixes Emergency Shield Projector hard del issue." - bugfix: "Emergency Shield Projector now shuts down as intended if the area's APC gets completely drained." - bugfix: "Firing the gyrotron into the INDRA while no reactants are present will no longer generate heat." - bugfix: "Fixes INDRA runtime." - bugfix: "Fixes Power Monitoring app not displaying grid sensors when run from a modular computer held in-hand." Bolted/welded down Emitter: <img width="130" height="101" alt="Screenshot 2026-02-13 123842" src="https://github.com/user-attachments/assets/8357b5ea-77e6-46f7-b4a0-724aaa141cef" /> Modified shieldwall sprites (with old ones for comparison) <img width="667" height="103" alt="Screenshot 2026-02-13 111422" src="https://github.com/user-attachments/assets/2b1e849e-f955-49cb-b094-0bef098a754f" /> Shields actually useful for damage control now (though they'll blow through APC charge if you go as crazy as this): <img width="804" height="891" alt="Screenshot 2026-02-13 124245" src="https://github.com/user-attachments/assets/39268b42-5abe-4a3b-ba8a-a18bdc63873e" /> ### Asset Licenses The following assets that **have not** been created by myself are included in this PR: | Path | Original Author | License | | --- | --- | --- | | icons/obj/atmos.dmi (all "sheater*") | [Wallemations, VinylSpiders (/tg/station #93800)](https://github.com/tgstation/tgstation/pull/93800) | CC-BY-SA | --------- Signed-off-by: Batrachophreno <Batrochophreno@gmail.com> Co-authored-by: SleepyGemmy <99297919+SleepyGemmy@users.noreply.github.com>
This commit is contained in:
co-authored by
SleepyGemmy
parent
adeaaaee4a
commit
0c342878e5
@@ -114,9 +114,9 @@
|
||||
|
||||
/singleton/cargo_item/shieldgenerator
|
||||
category = "security"
|
||||
name = "Shield Generator"
|
||||
name = "Shield Wall Generator"
|
||||
supplier = "nanotrasen"
|
||||
description = "A shield generator."
|
||||
description = "A shield wall generator."
|
||||
price = 550
|
||||
items = list(
|
||||
/obj/machinery/shieldwallgen
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
if(!T) // Safety check
|
||||
return
|
||||
for(var/obj/machinery/power/sensor/S in SSmachinery.all_sensors)
|
||||
if(AreConnectedZLevels(S.z, computer.z) || (S.long_range))
|
||||
if(AreConnectedZLevels(S.z, T.z) || (S.long_range))
|
||||
if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen!
|
||||
warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z")
|
||||
else
|
||||
|
||||
@@ -22,8 +22,10 @@
|
||||
|
||||
var/tmp/list/climbers
|
||||
|
||||
// An override of turf/Enter() to make it so that magboots allow you to stop
|
||||
// falling off the damned rock.
|
||||
/**
|
||||
* An override of turf/Enter() to make it so that magboots allow you to stop
|
||||
* falling off the damned rock.
|
||||
*/
|
||||
/turf/simulated/open/Enter(mob/living/carbon/human/mover, atom/oldloc)
|
||||
if (istype(mover) && isturf(oldloc))
|
||||
if (mover.Check_Shoegrip(FALSE) && mover.can_fall(below, src))
|
||||
@@ -74,10 +76,11 @@
|
||||
return catwalk
|
||||
return src
|
||||
|
||||
|
||||
// Add a falling atom by default. Even if it's not an atom that can actually fall.
|
||||
// SSfalling will check this on its own and remove if necessary. This is saner, as it
|
||||
// centralizes control to SSfalling.
|
||||
/**
|
||||
* Add a falling atom by default. Even if it's not an atom that can actually fall.
|
||||
* SSfalling will check this on its own and remove if necessary. This is saner, as it
|
||||
* centralizes control to SSfalling.
|
||||
*/
|
||||
/turf/simulated/open/Entered(atom/movable/mover)
|
||||
..()
|
||||
if (is_hole)
|
||||
|
||||
@@ -763,20 +763,21 @@ ABSTRACT_TYPE(/obj/machinery/power/apc)
|
||||
else if (istype(attacking_item, /obj/item/debugger))
|
||||
if(emagged || hacker || infected)
|
||||
to_chat(user, SPAN_WARNING("There is a software error with the device. Attempting to fix..."))
|
||||
if(attacking_item.use_tool(src, user, 50, volume = 50))
|
||||
if(attacking_item.use_tool(src, user, 1 SECONDS, volume = 50))
|
||||
to_chat(user, SPAN_NOTICE("Problem diagnosed, searching for solution..."))
|
||||
if(attacking_item.use_tool(src, user, 150, volume = 50))
|
||||
if(attacking_item.use_tool(src, user, 3 SECONDS, volume = 50))
|
||||
to_chat(user, SPAN_NOTICE("Solution found. Applying fixes..."))
|
||||
if(attacking_item.use_tool(src, user, 300, volume = 50))
|
||||
if(attacking_item.use_tool(src, user, 8 SECONDS, volume = 50))
|
||||
if(prob(15))
|
||||
to_chat(user, SPAN_WARNING("Error while applying fixes. Please try again."))
|
||||
return
|
||||
to_chat(user, SPAN_NOTICE("Applied default software. Restarting APC..."))
|
||||
if(attacking_item.use_tool(src, user, 50, volume = 50))
|
||||
if(attacking_item.use_tool(src, user, 3 SECONDS, volume = 50))
|
||||
to_chat(user, SPAN_NOTICE("APC Reset. Fixes applied."))
|
||||
if(hacker)
|
||||
hacker.hacked_apcs -= src
|
||||
hacker = null
|
||||
ClearOverlays() // Manually clear overlays first.
|
||||
update_icon()
|
||||
if(emagged)
|
||||
emagged = FALSE
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#define FUSION_REACTANT_CAP 10000
|
||||
#define FUSION_WARNING_DELAY 20
|
||||
#define FUSION_BLACKBODY_MULTIPLIER 350
|
||||
#define FUSION_INTEGRITY_RATE_LIMIT 0.11
|
||||
#define FUSION_INTEGRITY_RATE_LIMIT 0.07
|
||||
#define FUSION_TICK_MAX_TEMP_CHANGE 0.3
|
||||
|
||||
/obj/effect/fusion_em_field
|
||||
@@ -63,7 +63,9 @@
|
||||
/obj/structure/cable,
|
||||
/obj/machinery/atmospherics,
|
||||
/obj/machinery/air_sensor,
|
||||
/obj/machinery/camera
|
||||
/obj/machinery/camera,
|
||||
/obj/item/tape,
|
||||
/obj/machinery/shield
|
||||
)
|
||||
|
||||
var/light_min_range = 2
|
||||
@@ -104,8 +106,8 @@
|
||||
var/pause_rupture = FALSE
|
||||
|
||||
var/power_log_base = 1.35
|
||||
var/power_multiplier = 3.5
|
||||
var/power_power = 2.9
|
||||
var/power_multiplier = 3.7
|
||||
var/power_power = 3.05
|
||||
|
||||
/obj/effect/fusion_em_field/proc/UpdateVisuals()
|
||||
//Take the particle system and edit it
|
||||
@@ -214,7 +216,10 @@
|
||||
|
||||
field_strength_power_multiplier = max((owned_core.field_strength ** 1.2) / 100, 1)
|
||||
// Dump power to our powernet.
|
||||
power_output = ((log(power_log_base, plasma_temperature) * power_multiplier) ** power_power) * field_strength_power_multiplier
|
||||
if(plasma_temperature > 0)
|
||||
power_output = ((log(power_log_base, plasma_temperature) * power_multiplier) ** power_power) * field_strength_power_multiplier
|
||||
else
|
||||
power_output = 0
|
||||
output_archive_5 = output_archive_4
|
||||
output_archive_4 = output_archive_3
|
||||
output_archive_3 = output_archive_2
|
||||
@@ -436,6 +441,10 @@
|
||||
change_size(calc_size)
|
||||
|
||||
/obj/effect/fusion_em_field/proc/AddEnergy(a_energy, a_plasma_temperature)
|
||||
// If there are no reactants, there's nothing to heat. Ignore.
|
||||
if(!length(reactants))
|
||||
return
|
||||
|
||||
// Boost gyro effects at low temperatures for faster startup
|
||||
if(plasma_temperature <= 5000)
|
||||
a_energy = a_energy * 32
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/machinery/containment_field
|
||||
name = "containment field"
|
||||
desc = "An energy field."
|
||||
icon = 'icons/obj/machinery/field_generator.dmi'
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "contain_f"
|
||||
anchored = 1
|
||||
density = 0
|
||||
|
||||
@@ -95,6 +95,13 @@
|
||||
if(active && powernet && POWER_AVAIL(src))
|
||||
AddOverlays(emissive_appearance(icon, "[icon_state]_lights"))
|
||||
AddOverlays("[icon_state]_lights")
|
||||
if(anchored)
|
||||
AddOverlays("+bolts")
|
||||
if(state == 2)
|
||||
AddOverlays("+welding")
|
||||
var/image/lights_image = image(icon, null, "+lights")
|
||||
lights_image.plane = ABOVE_LIGHTING_PLANE
|
||||
AddOverlays(lights_image)
|
||||
|
||||
/obj/machinery/power/emitter/attack_hand(mob/user)
|
||||
add_fingerprint(user)
|
||||
|
||||
@@ -13,7 +13,7 @@ field_generator power level display
|
||||
/obj/machinery/field_generator
|
||||
name = "field generator"
|
||||
desc = "A large thermal battery that projects a high amount of energy when powered."
|
||||
icon = 'icons/obj/machinery/field_generator.dmi'
|
||||
icon = 'icons/obj/machinery/shielding.dmi'
|
||||
icon_state = "field_gen"
|
||||
anchored = 0
|
||||
density = 1
|
||||
|
||||
@@ -1,3 +1,255 @@
|
||||
/obj/machinery/shieldgen
|
||||
name = "emergency shield projector"
|
||||
desc = "Used to seal minor hull breaches."
|
||||
icon = 'icons/obj/machinery/shielding.dmi'
|
||||
icon_state = "shieldoff"
|
||||
density = TRUE
|
||||
opacity = TRUE
|
||||
anchored = FALSE
|
||||
req_access = list(ACCESS_ENGINE)
|
||||
var/health = 100
|
||||
var/active = FALSE
|
||||
/// Malfunction causes parts of the shield to slowly dissipate
|
||||
var/malfunction = FALSE
|
||||
var/list/deployed_shields = list()
|
||||
var/list/regenerating = list()
|
||||
/// Range at which it can project shields.
|
||||
var/range = 4
|
||||
panel_open = FALSE
|
||||
var/locked = FALSE
|
||||
/// Periodically recheck if we need to rebuild a shield.
|
||||
var/check_delay = 60
|
||||
use_power = POWER_USE_OFF
|
||||
idle_power_usage = 250
|
||||
|
||||
/obj/machinery/shieldgen/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "This machine's primary function is to project energy shields calibrated for atmospheric containment; these shields keep the air in and the vacuum out."
|
||||
. += "If activated while within <b>[range]</b> tiles of a 'space' turf, an 'open space' turf, or an otherwise 'airless' turf, it will automatically project shields there, making it extremely useful for containing hull breaches."
|
||||
. += "It will also project energy shields onto any engineering tape within range that has been toggled as a 'shield marker' using a multitool."
|
||||
. += "ALT-click the [src] to lock or unlock it (if you have the appropriate ID access)."
|
||||
|
||||
/obj/machinery/shieldgen/Destroy()
|
||||
collapse_shields()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/shieldgen/proc/shields_up()
|
||||
if(active) return FALSE //If it's already turned on, how did this get called?
|
||||
|
||||
src.active = TRUE
|
||||
update_icon()
|
||||
|
||||
create_shields()
|
||||
|
||||
var/shield_power_usage
|
||||
for(var/obj/machinery/shield/shield_tile in deployed_shields)
|
||||
shield_power_usage += shield_tile.shield_idle_power
|
||||
|
||||
change_power_consumption(shield_power_usage, POWER_USE_IDLE)
|
||||
update_use_power(POWER_USE_IDLE)
|
||||
|
||||
/obj/machinery/shieldgen/proc/shields_down()
|
||||
if(!active) return FALSE //If it's already off, how did this get called?
|
||||
|
||||
src.active = FALSE
|
||||
update_icon()
|
||||
|
||||
collapse_shields()
|
||||
|
||||
update_use_power(POWER_USE_OFF)
|
||||
|
||||
/obj/machinery/shieldgen/proc/create_shields()
|
||||
for(var/T in RANGE_TURFS(range, src))
|
||||
var/turf/target_tile = T
|
||||
if(locate(/obj/machinery/shield) in target_tile)
|
||||
continue
|
||||
var/obj/item/tape/engineering/E = locate() in target_tile
|
||||
if(E?.shield_marker)
|
||||
deploy_shield(target_tile)
|
||||
else if(istype(target_tile,/turf/space) || istype(target_tile,/turf/simulated/open) || istype(target_tile,/turf/simulated/floor/exoplanet/asteroid/ash) || istype(target_tile,/turf/simulated/floor/airless))
|
||||
if(malfunction && prob(33) || !malfunction)
|
||||
deploy_shield(target_tile)
|
||||
|
||||
/obj/machinery/shieldgen/proc/deploy_shield(var/turf/T)
|
||||
var/obj/machinery/shield/shield_tile = new /obj/machinery/shield(T)
|
||||
deployed_shields += shield_tile
|
||||
use_power_oneoff(shield_tile.shield_generate_power)
|
||||
|
||||
/obj/machinery/shieldgen/proc/collapse_shields()
|
||||
for(var/obj/machinery/shield/shield_tile in deployed_shields)
|
||||
deployed_shields -= shield_tile
|
||||
if(!QDELETED(shield_tile))
|
||||
qdel(shield_tile)
|
||||
change_power_consumption(250, POWER_USE_IDLE)
|
||||
update_use_power(POWER_USE_IDLE)
|
||||
|
||||
/obj/machinery/shieldgen/power_change()
|
||||
..()
|
||||
if(!active) return
|
||||
if(stat & NOPOWER)
|
||||
collapse_shields()
|
||||
else
|
||||
create_shields()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/shieldgen/process()
|
||||
if(stat & NOPOWER)
|
||||
if(active)
|
||||
visible_message(SPAN_WARNING("\The [src] shuts down due to a lack of power."), SPAN_NOTICE("You hear a heavy droning fade out."))
|
||||
active = FALSE
|
||||
collapse_shields()
|
||||
return
|
||||
|
||||
if(malfunction)
|
||||
if(deployed_shields.len && prob(5))
|
||||
qdel(pick(deployed_shields))
|
||||
else
|
||||
if (check_delay <= 0)
|
||||
create_shields()
|
||||
|
||||
var/new_power_usage = 0
|
||||
for(var/obj/machinery/shield/shield_tile in deployed_shields)
|
||||
new_power_usage += shield_tile.shield_idle_power
|
||||
|
||||
if (new_power_usage != idle_power_usage)
|
||||
change_power_consumption(new_power_usage, POWER_USE_IDLE)
|
||||
use_power_oneoff(0)
|
||||
|
||||
check_delay = 30
|
||||
else
|
||||
check_delay--
|
||||
|
||||
/obj/machinery/shieldgen/proc/checkhp()
|
||||
if(health <= 30)
|
||||
src.malfunction = TRUE
|
||||
if(health <= 0)
|
||||
spawn(0)
|
||||
explosion(get_turf(src.loc), 0, 0, 1, 0, 0, 0)
|
||||
qdel(src)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
/obj/machinery/shieldgen/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
src.health -= 75
|
||||
src.checkhp()
|
||||
if(2.0)
|
||||
src.health -= 30
|
||||
if (prob(15))
|
||||
src.malfunction = 1
|
||||
src.checkhp()
|
||||
if(3.0)
|
||||
src.health -= 10
|
||||
src.checkhp()
|
||||
return
|
||||
|
||||
/obj/machinery/shieldgen/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
switch(severity)
|
||||
if(EMP_HEAVY)
|
||||
src.health /= 2 //cut health in half
|
||||
malfunction = TRUE
|
||||
locked = pick(0,1)
|
||||
if(EMP_LIGHT)
|
||||
if(prob(50))
|
||||
src.health *= 0.3 //chop off a third of the health
|
||||
malfunction = TRUE
|
||||
checkhp()
|
||||
|
||||
/obj/machinery/shieldgen/attack_hand(mob/user)
|
||||
if(locked)
|
||||
to_chat(user, SPAN_WARNING("The machine is locked!"))
|
||||
return
|
||||
if(panel_open)
|
||||
to_chat(user, SPAN_WARNING("The panel must be closed before operating this machine."))
|
||||
return
|
||||
|
||||
if (src.active)
|
||||
user.visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] [user] deactivates the shield generator."), \
|
||||
SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] You deactivate the shield generator."), \
|
||||
"You hear heavy droning fade out.")
|
||||
src.shields_down()
|
||||
else
|
||||
if(anchored)
|
||||
user.visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] [user] activate the shield generator."), \
|
||||
SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] You activate the shield generator."), \
|
||||
"You hear heavy droning.")
|
||||
src.shields_up()
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("The device must first be secured to the floor."))
|
||||
return
|
||||
|
||||
/obj/machinery/shieldgen/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!malfunction)
|
||||
malfunction = TRUE
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/shieldgen/attackby(obj/item/attacking_item, mob/user)
|
||||
if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
update_icon()
|
||||
attacking_item.play_tool_sound(get_turf(src), 50)
|
||||
if(panel_open)
|
||||
to_chat(user, SPAN_NOTICE("You close the panel."))
|
||||
panel_open = FALSE
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("You open the panel and expose the wiring."))
|
||||
panel_open = TRUE
|
||||
|
||||
else if(attacking_item.tool_behaviour == TOOL_CABLECOIL && malfunction && panel_open)
|
||||
var/obj/item/stack/cable_coil/coil = attacking_item
|
||||
to_chat(user, SPAN_NOTICE("You begin to replace the wires."))
|
||||
//if(do_after(user, min(60, round( ((maxhealth/health)*10)+(malfunction*10) ))) //Take longer to repair heavier damage
|
||||
if(attacking_item.use_tool(src, user, 30, volume = 50))
|
||||
if (coil.use(1))
|
||||
health = initial(health)
|
||||
malfunction = FALSE
|
||||
to_chat(user, SPAN_NOTICE("You repair the [src]!"))
|
||||
update_icon()
|
||||
|
||||
else if(attacking_item.tool_behaviour == TOOL_WRENCH)
|
||||
if(locked)
|
||||
playsound(src, 'sound/machines/terminal/terminal_error.ogg', 25, FALSE)
|
||||
balloon_alert(user, "locked!")
|
||||
return
|
||||
if(attacking_item.use_tool(src, user, 1 SECONDS, volume = 50))
|
||||
anchored = !anchored
|
||||
add_fingerprint(user)
|
||||
var/others_msg = anchored ? "<b>[user]</b> secures the external reinforcing bolts to the floor." : "<b>[user]</b> unsecures the external reinforcing bolts."
|
||||
var/self_msg = anchored ? "You secure the external reinforcing bolts to the floor." : "You unsecure the external reinforcing bolts."
|
||||
user.visible_message(others_msg, SPAN_NOTICE(self_msg), SPAN_NOTICE("You hear a ratcheting noise."))
|
||||
update_icon()
|
||||
return
|
||||
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/shieldgen/AltClick(mob/user)
|
||||
if(Adjacent(user))
|
||||
add_fingerprint(user)
|
||||
if(allowed(user))
|
||||
locked = !locked
|
||||
if(locked)
|
||||
playsound(src, 'sound/machines/terminal/terminal_button03.ogg', 35, FALSE)
|
||||
else
|
||||
playsound(src, 'sound/machines/terminal/terminal_button01.ogg', 35, FALSE)
|
||||
balloon_alert(user, locked ? "locked" : "unlocked")
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("Access denied."))
|
||||
playsound(src, 'sound/machines/terminal/terminal_error.ogg', 25, FALSE)
|
||||
balloon_alert(user, "access denied!")
|
||||
|
||||
/obj/machinery/shieldgen/update_icon()
|
||||
ClearOverlays()
|
||||
if(anchored)
|
||||
AddOverlays("+bolts")
|
||||
if(active && !(stat & NOPOWER))
|
||||
src.icon_state = malfunction ? "shieldonbr":"shieldon"
|
||||
else
|
||||
src.icon_state = malfunction ? "shieldoffbr":"shieldoff"
|
||||
|
||||
/obj/machinery/shield
|
||||
name = "emergency energy shield"
|
||||
desc = "An energy shield used to contain hull breaches."
|
||||
@@ -8,9 +260,12 @@
|
||||
anchored = TRUE
|
||||
unacidable = TRUE
|
||||
atmos_canpass = CANPASS_NEVER
|
||||
var/health = 75 //The shield can only take so much beating (prevents perma-prisons)
|
||||
var/shield_generate_power = 2500 //how much power we use when regenerating
|
||||
var/shield_idle_power = 500 //how much power we use when just being sustained.
|
||||
/// The shield can only take so much beating (prevents perma-prisons)
|
||||
var/health = 75
|
||||
/// How much power we use when first creating the shield
|
||||
var/shield_generate_power = 75 KILO WATTS
|
||||
/// How much power we use when just being sustained.
|
||||
var/shield_idle_power = 30 KILO WATTS
|
||||
|
||||
/obj/machinery/shield/malfai
|
||||
name = "emergency forcefield"
|
||||
@@ -90,8 +345,12 @@
|
||||
|
||||
health -= hitting_projectile.get_structure_damage()
|
||||
check_failure()
|
||||
opacity = 1
|
||||
spawn(20) if(src) opacity = FALSE
|
||||
opacity = TRUE
|
||||
addtimer(CALLBACK(src, PROC_REF(update_opacity), FALSE), 2 SECONDS)
|
||||
|
||||
/obj/machinery/shield/proc/update_opacity(var/new_opacity)
|
||||
if(src)
|
||||
opacity = new_opacity
|
||||
|
||||
/obj/machinery/shield/ex_act(severity)
|
||||
switch(severity)
|
||||
@@ -117,7 +376,6 @@
|
||||
if(prob(50))
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/machinery/shield/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
//Let everyone know we've been hit!
|
||||
visible_message(SPAN_NOTICE("<B>\[src] was hit by [hitting_atom].</B>"))
|
||||
@@ -139,247 +397,7 @@
|
||||
|
||||
//The shield becomes dense to absorb the blow.. purely asthetic.
|
||||
opacity = TRUE
|
||||
spawn(20) if(src) opacity = FALSE
|
||||
addtimer(CALLBACK(src, PROC_REF(update_opacity), FALSE), 2 SECONDS)
|
||||
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/machinery/shieldgen
|
||||
name = "emergency shield projector"
|
||||
desc = "Used to seal minor hull breaches."
|
||||
icon = 'icons/obj/machinery/shielding.dmi'
|
||||
icon_state = "shieldoff"
|
||||
density = TRUE
|
||||
opacity = FALSE
|
||||
anchored = FALSE
|
||||
req_access = list(ACCESS_ENGINE)
|
||||
var/health = 100
|
||||
var/active = FALSE
|
||||
// Malfunction causes parts of the shield to slowly dissapate
|
||||
var/malfunction = FALSE
|
||||
var/list/deployed_shields = list()
|
||||
var/list/regenerating = list()
|
||||
panel_open = FALSE
|
||||
var/locked = FALSE
|
||||
var/check_delay = 60 //periodically recheck if we need to rebuild a shield
|
||||
use_power = POWER_USE_OFF
|
||||
idle_power_usage = 0
|
||||
|
||||
/obj/machinery/shieldgen/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "ALT-click the [src] to lock or unlock it (if you have the appropriate ID access)."
|
||||
|
||||
/obj/machinery/shieldgen/Destroy()
|
||||
collapse_shields()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/shieldgen/proc/shields_up()
|
||||
if(active) return FALSE //If it's already turned on, how did this get called?
|
||||
|
||||
src.active = 1
|
||||
update_icon()
|
||||
|
||||
create_shields()
|
||||
|
||||
var/shield_power_usage
|
||||
for(var/obj/machinery/shield/shield_tile in deployed_shields)
|
||||
shield_power_usage += shield_tile.shield_idle_power
|
||||
|
||||
change_power_consumption(shield_power_usage, POWER_USE_IDLE)
|
||||
update_use_power(POWER_USE_IDLE)
|
||||
|
||||
/obj/machinery/shieldgen/proc/shields_down()
|
||||
if(!active) return FALSE //If it's already off, how did this get called?
|
||||
|
||||
src.active = FALSE
|
||||
update_icon()
|
||||
|
||||
collapse_shields()
|
||||
|
||||
update_use_power(POWER_USE_OFF)
|
||||
|
||||
/obj/machinery/shieldgen/proc/create_shields()
|
||||
for(var/T in RANGE_TURFS(2, src))
|
||||
var/turf/target_tile = T
|
||||
if(locate(/obj/machinery/shield) in target_tile)
|
||||
continue
|
||||
var/obj/item/tape/engineering/E = locate() in target_tile
|
||||
if(E?.shield_marker)
|
||||
deploy_shield(target_tile)
|
||||
else if(istype(target_tile,/turf/space) || istype(target_tile,/turf/simulated/open) || istype(target_tile,/turf/simulated/floor/exoplanet/asteroid/ash) || istype(target_tile,/turf/simulated/floor/airless))
|
||||
if(malfunction && prob(33) || !malfunction)
|
||||
deploy_shield(target_tile)
|
||||
|
||||
/obj/machinery/shieldgen/proc/deploy_shield(var/turf/T)
|
||||
var/obj/machinery/shield/S = new /obj/machinery/shield(T)
|
||||
deployed_shields += S
|
||||
use_power_oneoff(S.shield_generate_power)
|
||||
|
||||
/obj/machinery/shieldgen/proc/collapse_shields()
|
||||
for(var/obj/machinery/shield/shield_tile in deployed_shields)
|
||||
qdel(shield_tile)
|
||||
|
||||
/obj/machinery/shieldgen/power_change()
|
||||
..()
|
||||
if(!active) return
|
||||
if (stat & NOPOWER)
|
||||
collapse_shields()
|
||||
else
|
||||
create_shields()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/shieldgen/process()
|
||||
if (!active || (stat & NOPOWER))
|
||||
return
|
||||
|
||||
if(malfunction)
|
||||
if(deployed_shields.len && prob(5))
|
||||
qdel(pick(deployed_shields))
|
||||
else
|
||||
if (check_delay <= 0)
|
||||
create_shields()
|
||||
|
||||
var/new_power_usage = 0
|
||||
for(var/obj/machinery/shield/shield_tile in deployed_shields)
|
||||
new_power_usage += shield_tile.shield_idle_power
|
||||
|
||||
if (new_power_usage != idle_power_usage)
|
||||
change_power_consumption(new_power_usage, POWER_USE_IDLE)
|
||||
use_power_oneoff(0)
|
||||
|
||||
check_delay = 60
|
||||
else
|
||||
check_delay--
|
||||
|
||||
/obj/machinery/shieldgen/proc/checkhp()
|
||||
if(health <= 30)
|
||||
src.malfunction = 1
|
||||
if(health <= 0)
|
||||
spawn(0)
|
||||
explosion(get_turf(src.loc), 0, 0, 1, 0, 0, 0)
|
||||
qdel(src)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
/obj/machinery/shieldgen/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
src.health -= 75
|
||||
src.checkhp()
|
||||
if(2.0)
|
||||
src.health -= 30
|
||||
if (prob(15))
|
||||
src.malfunction = 1
|
||||
src.checkhp()
|
||||
if(3.0)
|
||||
src.health -= 10
|
||||
src.checkhp()
|
||||
return
|
||||
|
||||
/obj/machinery/shieldgen/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
switch(severity)
|
||||
if(EMP_HEAVY)
|
||||
src.health /= 2 //cut health in half
|
||||
malfunction = TRUE
|
||||
locked = pick(0,1)
|
||||
if(EMP_LIGHT)
|
||||
if(prob(50))
|
||||
src.health *= 0.3 //chop off a third of the health
|
||||
malfunction = TRUE
|
||||
checkhp()
|
||||
|
||||
/obj/machinery/shieldgen/attack_hand(mob/user)
|
||||
if(locked)
|
||||
to_chat(user, SPAN_WARNING("The machine is locked!"))
|
||||
return
|
||||
if(panel_open)
|
||||
to_chat(user, SPAN_WARNING("The panel must be closed before operating this machine."))
|
||||
return
|
||||
|
||||
if (src.active)
|
||||
user.visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] [user] deactivates the shield generator."), \
|
||||
SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] You deactivate the shield generator."), \
|
||||
"You hear heavy droning fade out.")
|
||||
src.shields_down()
|
||||
else
|
||||
if(anchored)
|
||||
user.visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] [user] activate the shield generator."), \
|
||||
SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] You activate the shield generator."), \
|
||||
"You hear heavy droning.")
|
||||
src.shields_up()
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("The device must first be secured to the floor."))
|
||||
return
|
||||
|
||||
/obj/machinery/shieldgen/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!malfunction)
|
||||
malfunction = TRUE
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/machinery/shieldgen/attackby(obj/item/attacking_item, mob/user)
|
||||
if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
attacking_item.play_tool_sound(get_turf(src), 50)
|
||||
if(panel_open)
|
||||
to_chat(user, SPAN_NOTICE("You close the panel."))
|
||||
panel_open = FALSE
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("You open the panel and expose the wiring."))
|
||||
panel_open = TRUE
|
||||
|
||||
else if(attacking_item.tool_behaviour == TOOL_CABLECOIL && malfunction && panel_open)
|
||||
var/obj/item/stack/cable_coil/coil = attacking_item
|
||||
to_chat(user, SPAN_NOTICE("You begin to replace the wires."))
|
||||
//if(do_after(user, min(60, round( ((maxhealth/health)*10)+(malfunction*10) ))) //Take longer to repair heavier damage
|
||||
if(attacking_item.use_tool(src, user, 30, volume = 50))
|
||||
if (coil.use(1))
|
||||
health = initial(health)
|
||||
malfunction = FALSE
|
||||
to_chat(user, SPAN_NOTICE("You repair the [src]!"))
|
||||
update_icon()
|
||||
|
||||
else if(attacking_item.tool_behaviour == TOOL_WRENCH)
|
||||
if(locked)
|
||||
to_chat(user, "The bolts are covered, unlocking this would retract the covers.")
|
||||
return
|
||||
if(anchored)
|
||||
attacking_item.play_tool_sound(get_turf(src), 100)
|
||||
to_chat(user, SPAN_NOTICE("You unsecure the [src] from the floor!"))
|
||||
if(active)
|
||||
to_chat(user, SPAN_NOTICE("The [src] shuts off!"))
|
||||
src.shields_down()
|
||||
anchored = FALSE
|
||||
else
|
||||
if(istype(get_turf(src), /turf/space)) return //No wrenching these in space!
|
||||
attacking_item.play_tool_sound(get_turf(src), 100)
|
||||
to_chat(user, SPAN_NOTICE("You secure the [src] to the floor!"))
|
||||
anchored = TRUE
|
||||
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/shieldgen/AltClick(mob/user)
|
||||
if(Adjacent(user))
|
||||
add_fingerprint(user)
|
||||
if(allowed(user))
|
||||
locked = !locked
|
||||
if(locked)
|
||||
playsound(src, 'sound/machines/terminal/terminal_button03.ogg', 35, FALSE)
|
||||
else
|
||||
playsound(src, 'sound/machines/terminal/terminal_button01.ogg', 35, FALSE)
|
||||
balloon_alert(user, locked ? "locked" : "unlocked")
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("Access denied."))
|
||||
playsound(src, 'sound/machines/terminal/terminal_error.ogg', 25, FALSE)
|
||||
balloon_alert(user, "access denied!")
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/shieldgen/update_icon()
|
||||
if(active && !(stat & NOPOWER))
|
||||
src.icon_state = malfunction ? "shieldonbr":"shieldon"
|
||||
else
|
||||
src.icon_state = malfunction ? "shieldoffbr":"shieldoff"
|
||||
return
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/obj/effect/energy_field
|
||||
name = "energy shield"
|
||||
desc = "A strong field of energy, capable of blocking anything as long as it's active."
|
||||
icon = 'icons/obj/machinery/shielding.dmi'
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "shield_normal"
|
||||
alpha = 0
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
var/stored_charge = 0
|
||||
var/last_stored_charge = 0
|
||||
var/time_since_fail = 100
|
||||
var/max_charge = 8e6 //8 MJ
|
||||
var/max_charge_rate = 400000 //400 kW
|
||||
var/max_charge = 2e8 //200 MJ
|
||||
var/max_charge_rate = 9000000 //9 MW
|
||||
var/locked = FALSE
|
||||
|
||||
var/charge_rate = 100000 //100 kW
|
||||
var/charge_rate = 100000 //100 kW
|
||||
var/obj/machinery/shield_gen/owned_gen
|
||||
|
||||
/obj/machinery/shield_capacitor/Initialize()
|
||||
@@ -138,5 +138,6 @@
|
||||
else
|
||||
..()
|
||||
|
||||
/// Horizon-specific non-variant, for now.
|
||||
/obj/machinery/shield_capacitor/multiz
|
||||
max_charge_rate = 1250000
|
||||
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
#define POWER_ACTIVE 2
|
||||
|
||||
/obj/machinery/shieldwallgen
|
||||
name = "shield generator"
|
||||
name = "shield wall generator"
|
||||
desc = "A portable shield generator, capable of casting a shield to another powered generator in range."
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "Shield_Gen"
|
||||
icon = 'icons/obj/machinery/shielding.dmi'
|
||||
icon_state = "shieldwalloff"
|
||||
anchored = FALSE
|
||||
density = TRUE
|
||||
req_access = list(ACCESS_ENGINE_EQUIP)
|
||||
|
||||
/// Range at which it can pair with another shield wall generator (must be this many spaces BETWEEN THEM at maximum)
|
||||
var/range = 9
|
||||
var/power_state = FALSE
|
||||
var/is_powered = FALSE
|
||||
var/wrenched = FALSE
|
||||
var/locked = TRUE
|
||||
var/storedpower = 0
|
||||
obj_flags = OBJ_FLAG_CONDUCTABLE
|
||||
@@ -21,36 +21,40 @@
|
||||
//There have to be at least two posts, so these are effectively doubled
|
||||
|
||||
///How much power is drawn from powernet. Increase this to allow the generator to sustain longer shields, at the cost of more power draw.
|
||||
var/power_draw = 30 KILO WATTS
|
||||
var/max_stored_power = 50 KILO WATTS
|
||||
var/power_draw = 200 KILO WATTS
|
||||
var/max_stored_power = 1000 KILO WATTS
|
||||
/// Draws directly from power net. Does not use APC power.
|
||||
use_power = POWER_USE_OFF
|
||||
|
||||
/obj/machinery/shieldwallgen/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "A shield wall generator can pair with another from up to <b>[range]</b> tiles away (maximum wall length of <b>[range - 1]</b>)."
|
||||
. += "ALT-click the [src] to lock or unlock it (if you have the appropriate ID access)."
|
||||
|
||||
/obj/machinery/shieldwallgen/active
|
||||
power_state = POWER_STARTING
|
||||
is_powered = TRUE
|
||||
wrenched = TRUE
|
||||
anchored = TRUE
|
||||
locked = FALSE
|
||||
icon_state = "Shield_Gen +a"
|
||||
icon_state = "shieldwallon"
|
||||
storedpower = 9000000
|
||||
|
||||
/obj/machinery/shieldwallgen/update_icon()
|
||||
ClearOverlays()
|
||||
if(power_state >= POWER_STARTING)
|
||||
icon_state = "Shield_Gen +a"
|
||||
icon_state = "shieldwallon"
|
||||
else
|
||||
icon_state = "Shield_Gen"
|
||||
icon_state = "shieldwalloff"
|
||||
if(anchored)
|
||||
AddOverlays("+bolts")
|
||||
|
||||
/obj/machinery/shieldwallgen/attack_hand(mob/user)
|
||||
if(!wrenched)
|
||||
if(!anchored)
|
||||
to_chat(user, SPAN_WARNING("The shield generator needs to be firmly secured to the floor first."))
|
||||
return TRUE
|
||||
if(locked && !issilicon(user))
|
||||
to_chat(user, SPAN_WARNING("The controls are locked!"))
|
||||
playsound(src, 'sound/machines/terminal/terminal_error.ogg', 25, FALSE)
|
||||
balloon_alert(user, "locked!")
|
||||
return TRUE
|
||||
if(!is_powered)
|
||||
to_chat(user, SPAN_WARNING("The shield generator needs to be powered by wire underneath."))
|
||||
@@ -105,7 +109,7 @@
|
||||
storedpower = clamp(storedpower, 0, max_stored_power)
|
||||
|
||||
if(power_state == POWER_STARTING)
|
||||
if(!wrenched)
|
||||
if(!anchored)
|
||||
power_state = POWER_INACTIVE
|
||||
return
|
||||
addtimer(CALLBACK(src, PROC_REF(setup_field), 1), 1)
|
||||
@@ -133,7 +137,7 @@
|
||||
|
||||
oNSEW = REVERSE_DIR(NSEW)
|
||||
|
||||
for(var/dist = 0, dist <= 9, dist++) // checks out to 8 tiles away for another generator
|
||||
for(var/dist = 0, dist <= range, dist++) // checks out to 8 tiles away for another generator
|
||||
T = get_step(T2, NSEW)
|
||||
T2 = T
|
||||
steps += 1
|
||||
@@ -162,15 +166,14 @@
|
||||
if(power_state)
|
||||
to_chat(user, SPAN_WARNING("You cannot unsecure \the [src] while it's active."))
|
||||
return
|
||||
|
||||
wrenched = !wrenched
|
||||
anchored = wrenched
|
||||
attacking_item.play_tool_sound(get_turf(src), 75)
|
||||
add_fingerprint(user)
|
||||
var/others_msg = wrenched ? "<b>[user]</b> secures the external reinforcing bolts to the floor." : "<b>[user]</b> unsecures the external reinforcing bolts."
|
||||
var/self_msg = wrenched ? "You secure the external reinforcing bolts to the floor." : "You unsecure the external reinforcing bolts."
|
||||
user.visible_message(others_msg, SPAN_NOTICE(self_msg), SPAN_NOTICE("You hear a ratcheting noise."))
|
||||
return
|
||||
if(attacking_item.use_tool(src, user, 1 SECONDS, volume = 50))
|
||||
anchored = !anchored
|
||||
add_fingerprint(user)
|
||||
var/others_msg = anchored ? "<b>[user]</b> secures the external reinforcing bolts to the floor." : "<b>[user]</b> unsecures the external reinforcing bolts."
|
||||
var/self_msg = anchored ? "You secure the external reinforcing bolts to the floor." : "You unsecure the external reinforcing bolts."
|
||||
user.visible_message(others_msg, SPAN_NOTICE(self_msg), SPAN_NOTICE("You hear a ratcheting noise."))
|
||||
update_icon()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/shieldwallgen/AltClick(mob/user)
|
||||
@@ -184,7 +187,6 @@
|
||||
playsound(src, 'sound/machines/terminal/terminal_button01.ogg', 35, FALSE)
|
||||
balloon_alert(user, locked ? "locked" : "unlocked")
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("Access denied."))
|
||||
playsound(src, 'sound/machines/terminal/terminal_error.ogg', 25, FALSE)
|
||||
balloon_alert(user, "access denied!")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user