diff --git a/_maps/map_files/Galactica/Galactica2.dmm b/_maps/map_files/Galactica/Galactica2.dmm index 671564e3edb..a94c783bad5 100644 --- a/_maps/map_files/Galactica/Galactica2.dmm +++ b/_maps/map_files/Galactica/Galactica2.dmm @@ -8596,9 +8596,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/machinery/atmospherics/components/binary/valve/digital/on/layer4{ - dir = 8; - name = "To Fueltank" +/obj/machinery/atmospherics/components/binary/volume_pump/layer4{ + dir = 4; + name = "Nucleium Tank To FTL" }, /turf/open/floor/durasteel/techfloor_grid, /area/engine/engineering/reactor_core) @@ -38352,9 +38352,9 @@ /obj/machinery/atmospherics/pipe/simple/orange/visible/layer2{ dir = 4 }, -/obj/machinery/atmospherics/components/binary/valve/digital/on/layer4{ - dir = 8; - name = "To Fueltank" +/obj/machinery/atmospherics/components/binary/volume_pump/layer4{ + name = "Nucleium Tank Out"; + dir = 8 }, /turf/open/floor/durasteel/techfloor_grid, /area/engine/engineering/reactor_core) diff --git a/code/controllers/subsystem/explosion.dm b/code/controllers/subsystem/explosion.dm index 88560ae1d4f..f038003535e 100644 --- a/code/controllers/subsystem/explosion.dm +++ b/code/controllers/subsystem/explosion.dm @@ -415,6 +415,8 @@ SUBSYSTEM_DEF(explosions) var/turf/T = locate(epicenter.x, epicenter.y, affecting_z) if(!T) continue + if(devastation_range - z_reduction <= 0 && heavy_impact_range - z_reduction <= 0 && light_impact_range - z_reduction <= 0) //NSV13 - explosions still relaying with 0-0-0 can cause REALLY weird behavior. + continue SSexplosions.explode(T, max(devastation_range - z_reduction, 0), max(heavy_impact_range - z_reduction, 0), diff --git a/nsv13/code/__DEFINES/overmap.dm b/nsv13/code/__DEFINES/overmap.dm index beb76f66c13..8bb8ce50961 100644 --- a/nsv13/code/__DEFINES/overmap.dm +++ b/nsv13/code/__DEFINES/overmap.dm @@ -113,3 +113,9 @@ GLOBAL_LIST_INIT(overmap_impact_sounds, list('nsv13/sound/effects/ship/freespace #define MASS_LARGE 7 //20-40 Players - Medium Capital Ships #define MASS_TITAN 150 //40+ Players - Large Capital Ships #define MASS_IMMOBILE 200 //Things that should not be moving. See: stations + +//Fun tools +#define SHIELD_NOEFFECT 0 //!Shield failed to absorb hit. +#define SHIELD_ABSORB 1 //!Shield absorbed hit. +#define SHIELD_FORCE_DEFLECT 2 //!Shield absorbed hit and is redirecting projectile with slightly turned vector. +#define SHIELD_FORCE_REFLECT 3 //!Shield absorbed hit and is redirecting projectile in reverse direction. diff --git a/nsv13/code/datums/holocall.dm b/nsv13/code/datums/holocall.dm index 9f7b712eab5..8b6d7711b09 100644 --- a/nsv13/code/datums/holocall.dm +++ b/nsv13/code/datums/holocall.dm @@ -26,7 +26,7 @@ DELAY 20 PRESET /datum/preset_holoimage/corgi NAME Burst Data - LANGUAGE /datum/language/eal + LANGUAGE /datum/language/machine SAY START NTINTEL METADATA SAY RECORDED 12-17-0000 SAY SECURITY CLASS UNCLASSIFIED @@ -320,7 +320,7 @@ DELAY 50 SAY If you need to shut down the reactor, lower the nucleium injection rate slowly. You can cycle coolant in an emergency for a quick cooling boost. DELAY 50 - SAY The reaction can be terminated when the reactor core is under 100 Celsius. Ensure cooling is adequate to achieve this. + SAY The reaction can be terminated when the reactor core is under 200 Celsius. Ensure cooling is adequate to achieve this. DELAY 50 SAY Finally. If your minimum input power ever starts to converge on the maximum, you are heading towards an emission. Rectify this immediately, or shut down the reactor safely. DELAY 50 @@ -328,7 +328,7 @@ DELAY 50 SAY Do your duty. This tape should be destroyed after use. Shield technology does not exist. Glory to Nanotrasen. NAME Burst Data - LANGUAGE /datum/language/eal + LANGUAGE /datum/language/machine DELAY 20 SAY START METADATA SAY RECORDED 5-25-0000 diff --git a/nsv13/code/modules/overmap/pdsr.dm b/nsv13/code/modules/overmap/pdsr.dm index 36ee7c4b56f..6c52dcb62d7 100644 --- a/nsv13/code/modules/overmap/pdsr.dm +++ b/nsv13/code/modules/overmap/pdsr.dm @@ -9,8 +9,11 @@ #define REACTOR_STATE_SHUTTING_DOWN 4 #define REACTOR_STATE_EMISSION 5 +#define DENSITY_LOW 0 //! Deflects only heavy hits. +#define DENSITY_HIGH 1 //! Deflects all hits. + /obj/machinery/atmospherics/components/trinary/defence_screen_reactor - name = "mk I Prototype Defence Screen Reactor" + name = "mk II Prototype Defence Screen Reactor" desc = "A highly experimental, unstable and highly illegal nucleium driven reactor for the generation of defensive screens." icon = 'nsv13/icons/obj/machinery/pdsr.dmi' icon_state = "idle" @@ -46,10 +49,20 @@ var/last_coolant_time = 0 //Last time we called to flush coolant var/flushing_coolant = 0 //Are we currently flushing coolant var/emission_tracker = 0 //Used to track emission timers + ///Time when our reactor was last shutdown. + var/powerdown_time = 0 + ///If this is already detonating + var/detonating = FALSE //!Shield Vars - var/list/shield = list("integrity" = 0, "max_integrity" = 0, "stability" = 0) + var/list/shield = list("integrity" = 0, "max_integrity" = 0, "stability" = 0, "density" = DENSITY_HIGH) var/power_input = 0 //How much power is currently allocated + ///Did we get enough power last power tick? + var/power_demand_met = FALSE + ///How much power did we use during the power tick? + var/last_power_use = 0 + ///How much power was in the grid during power tick? + var/last_avail_power = 0 var/screen_regen = 50 //Allocation to regenerate the !shields var/screen_hardening = 50 //Allocation to strengthen the !shields var/min_power_input = 0 //Minimum power required to sustain !shield integrity @@ -95,17 +108,28 @@ /obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/try_use_power(amount) var/turf/T = get_turf(src) C = T.get_cable_node() - if(C?.surplus() > amount) + if(C?.surplus() >= amount) C.powernet.load += amount + last_power_use = amount + power_demand_met = TRUE + last_avail_power = C?.surplus() return TRUE + power_demand_met = FALSE + last_power_use = 0 + last_avail_power = C?.surplus() return FALSE -/obj/machinery/atmospherics/components/trinary/defence_screen_reactor/process() +/obj/machinery/atmospherics/components/trinary/defence_screen_reactor/process_atmos() update_parents() - if(next_slowprocess < world.time) + if(next_slowprocess <= world.time) slowprocess() next_slowprocess = world.time + 1 SECONDS +/obj/machinery/atmospherics/components/trinary/defence_screen_reactor/process() + if(state == REACTOR_STATE_IDLE) + return + try_use_power(power_input) + /obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/slowprocess() var/datum/gas_mixture/nucleium_input = airs[2] var/datum/gas_mixture/coolant_input = airs[1] @@ -124,31 +148,32 @@ return current_uptime ++ - reaction_containment += 5 + reaction_containment += 20 // ~5 seconds as opposed to 20 for core start. if(reaction_containment >= 100) reaction_containment = 100 if(reaction_injection_rate < 2.5) say("Error: Unable to initialise reaction, insufficient nucleium injection.") - reaction_containment = 0 - current_uptime = 0 - state = REACTOR_STATE_IDLE + handle_shutdown() return if(nuc_in < reaction_injection_rate) say("Error: Unable to initialise reaction, insufficient nucleium available.") - reaction_containment = 0 - current_uptime = 0 - state = REACTOR_STATE_IDLE + handle_shutdown() + return + if(!power_demand_met) + say("Error: Power allocation exceeding grid capacity. Failed to initiate reaction.") + handle_shutdown() return - var/errors = rand(20, 200) + var/errors = rand(20, 199) say("Initiating Reaction - Injecting Nucleium.") say("Reaction Initialized - [errors] runtimes supressed.") reaction_temperature = 100 //Flash start to 100 + shield["stability"] = 50 //begin at 50 during startup. state = REACTOR_STATE_RUNNING if(state == REACTOR_STATE_RUNNING) - if(nuc_in >= reaction_injection_rate) //If we are running in nominal conditions... + if(nuc_in >= reaction_injection_rate && reaction_injection_rate >= 2.5) //If we are running in nominal conditions... nucleium_input.adjust_moles(GAS_NUCLEIUM, -reaction_injection_rate) //Handle reaction rate adjustments here var/target_reaction_rate = ((0.5 + (1e-03 * (reaction_injection_rate ** 2))) + (current_uptime / 2000)) * 16 @@ -157,7 +182,7 @@ reaction_temperature += reaction_rate * 0.35 //Function goes handle_polarity(TRUE) - else if(nuc_in < reaction_injection_rate) //If we are running without sufficient nucleium... + else //If we are running without sufficient nucleium... if(nuc_in <= 0) //...and none at all var/target_reaction_rate = 0 var/delta_reaction_rate = target_reaction_rate - reaction_rate @@ -176,7 +201,7 @@ handle_polarity(TRUE) if(reaction_rate > 5) //TEMP USE FUNCTIONS - reaction_energy_output = (reaction_rate + (reaction_injection_rate / 2)) * (2 - (current_uptime / 20000)) //FUNCTIONS + reaction_energy_output = (reaction_rate + (min(nuc_in, reaction_injection_rate) / 2)) * (2 - (current_uptime / 20000)) //FUNCTIONS radiation_pulse(src, reaction_energy_output) else @@ -205,21 +230,21 @@ state = REACTOR_STATE_SHUTTING_DOWN else say("Error: Reaction Prematurely Terminated - Inspect all systems for damage.") - state = REACTOR_STATE_IDLE + var/list/overload_candidate = list() + for(var/obj/machinery/defence_screen_relay/DSR in GLOB.machines) + if(DSR.powered() && DSR.overloaded == FALSE) + overload_candidate += DSR for(var/I = 0, I < 3, I++) //Overload Three Relays - var/list/overload_candidate = list() - for(var/obj/machinery/defence_screen_relay/DSR in GLOB.machines) - if(DSR.powered() && DSR.overloaded == FALSE) - overload_candidate += DSR - if(overload_candidate.len > 0) - var/obj/machinery/defence_screen_relay/DSRC = pick(overload_candidate) - DSRC.overload() + if(overload_candidate.len > 0) + var/obj/machinery/defence_screen_relay/DSRC = pick_n_take(overload_candidate) + DSRC.overload() depower_shield() OM.take_quadrant_hit(rand(100, 200), "forward_port") OM.take_quadrant_hit(rand(100, 200), "forward_starboard") OM.take_quadrant_hit(rand(100, 200), "aft_port") OM.take_quadrant_hit(rand(100, 200), "aft_starboard") + state = REACTOR_STATE_SHUTTING_DOWN handle_screens() handle_temperature() @@ -283,22 +308,23 @@ //////Reactor Procs////// /obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/handle_containment() //We manage poweruse and containment here - if(try_use_power(power_input)) - if(power_input > max_power_input && power_input <= 1.25 * max_power_input) //Overloading Containment - Rapid Rise + if(power_demand_met) + if(last_power_use > max_power_input && last_power_use <= 1.25 * max_power_input) //Overloading Containment - Rapid Rise var/overloading_containment = reaction_containment if(overloading_containment < 25) overloading_containment = 25 var/overloading_function = ((382 * NUM_E **(0.0764 * overloading_containment)) / ((50 + NUM_E ** (0.0764 * overloading_containment)) ** 2)) * 14 - reaction_containment += overloading_function * (power_input / max_power_input) + reaction_containment += overloading_function * (last_power_use / max_power_input) current_uptime ++ //Overloading has a cost - else if(power_input >= min_power_input && power_input <= max_power_input) //Nominal Containment - Maintain Containment + else if(last_power_use >= min_power_input && last_power_use <= max_power_input) //Nominal Containment - Maintain Containment var/containment_function = ((382 * NUM_E **(0.0764 * reaction_containment)) / ((50 + NUM_E ** (0.0764 * reaction_containment)) ** 2)) * 10 - reaction_containment += containment_function * (power_input / max_power_input) + reaction_containment += containment_function * (last_power_use / max_power_input) - else if(power_input < min_power_input && power_input >= 0.75 * min_power_input) //Insufficient Power for Containment - Slow Loss + else if(last_power_use < min_power_input && last_power_use >= 0.75 * min_power_input) //Insufficient Power for Containment - Slow Loss var/loss_function = ((382 * NUM_E **(0.0764 * reaction_containment)) / ((50 + NUM_E ** (0.0764 * reaction_containment)) ** 2)) * 4 - reaction_containment += loss_function * (power_input / max_power_input) + reaction_containment += loss_function * (last_power_use / max_power_input) + if(reaction_containment > 100) reaction_containment = 100 @@ -307,7 +333,7 @@ reaction_containment = 0 emission_tracker = world.time say("Error: Catatstropic Containment Failure - Initializing Emergency Termination Protocols") - playsound(src, 'sound/magic/lightning_chargeup.ogg', 100, 0, 15, 10, 10) //Replace me later? + playsound(src, 'sound/magic/lightning_chargeup.ogg', 100, FALSE, 15) //Replace me later? state = REACTOR_STATE_EMISSION //Whoops /obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/handle_power_reqs() //How much power is required @@ -320,7 +346,7 @@ if(reaction_containment < 33 && state == REACTOR_STATE_RUNNING) if(next_alarm_sfx < world.time) next_alarm_sfx = world.time + 3 SECONDS - playsound(src, 'nsv13/sound/effects/ship/pdsr_warning.ogg', 100, 0, 10, 10) + playsound(src, 'nsv13/sound/effects/ship/pdsr_warning.ogg', 100, FALSE, 10) if(next_alarm_message < world.time) next_alarm_message = world.time + 15 SECONDS say("DANGER: Reaction Containment Critical. Emission Imminent.") @@ -328,7 +354,7 @@ if(state == REACTOR_STATE_EMISSION) if(next_alarm_sfx < world.time) next_alarm_sfx = world.time + 3 SECONDS - playsound(src, 'nsv13/sound/effects/ship/pdsr_warning.ogg', 100, 0, 10, 10) + playsound(src, 'nsv13/sound/effects/ship/pdsr_warning.ogg', 100, FALSE, 10) /obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/handle_polarity(var/injecting = FALSE) if(reaction_polarity_timer < world.time) //Handle the trend @@ -343,11 +369,7 @@ else reaction_polarity -= 0.027 - if(reaction_polarity > 1) - reaction_polarity = 1 - - if(reaction_polarity < -1) - reaction_polarity = -1 + reaction_polarity = clamp(reaction_polarity, -1, 1) var/polarity_function = abs(0.5 * (reaction_polarity ** 2)) //RECHECK THIS WHEN NOT DEAD reaction_containment -= polarity_function @@ -360,7 +382,7 @@ if(in_view_range(M, src)) to_chat(M, "A stream of particles erupts from the [src]!") M.flash_act(1, 0, 1) - playsound(src, 'sound/magic/repulse.ogg', 100, 0, 5, 5) + playsound(src, 'sound/magic/repulse.ogg', 100, FALSE, 5) //more goes here /obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/handle_emission_release() @@ -368,13 +390,13 @@ if(DSR.powered() && DSR.overloaded == FALSE) DSR.overload() - var/emission_energy = reaction_energy_output * (1 + (current_uptime / 1000)) + var/emission_energy = max(10, reaction_energy_output) * (1 + (current_uptime / 1000)) radiation_pulse(src, emission_energy ** 2, 10, 1, 1) for(var/mob/living/M in OM.mobs_in_ship) if(M.client) - M.flash_act((emission_energy / 10), 0 , 1) - M.Knockdown(emission_energy / 10) + M.flash_act(clamp(emission_energy, 30, 100), TRUE, TRUE) + M.Knockdown(clamp(emission_energy, 20, 100)) M.adjust_disgust(rand(20, 50)) to_chat(M, "A wash of radiation passes through you!") @@ -390,6 +412,7 @@ say("Inspect all systems for damage.") /obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/handle_temperature() + reaction_containment -= (reaction_temperature / 50) + (current_uptime / 2000) var/turf/open/L = get_turf(src) if(!istype(L) || !(L.air)) return @@ -401,7 +424,6 @@ env.set_temperature(temperature += delta_env / 2) air_update_turf() - reaction_containment -= (reaction_temperature / 50) + (current_uptime / 2000) /obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/handle_atmos_check() for(var/obj/machinery/defence_screen_relay/DSR in GLOB.machines) @@ -418,6 +440,10 @@ flushing_coolant = 0 reaction_energy_output = 0 emission_tracker = 0 + powerdown_time = world.time + last_power_use = 0 + power_demand_met = FALSE + last_avail_power = 0 depower_shield() /obj/machinery/atmospherics/components/trinary/defence_screen_reactor/update_icon() @@ -442,22 +468,28 @@ //////Shield Procs////// -/obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/absorb_hit(damage) +/obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/absorb_hit(obj/item/projectile/proj) + var/damage = proj.damage if(!active) - return FALSE //!shields not raised + return SHIELD_NOEFFECT //!shields not raised + + if(shield["density"] == DENSITY_LOW && (proj.flag != "overmap_heavy" || proj.damage_type == BURN)) //Low density mode does not get hit by low impact projectiles, but also does not help vs. energy weapons. + return SHIELD_NOEFFECT if(shield["integrity"] >= damage) shield["integrity"] -= damage //Deduct from !shield var/current_hit = world.time - if(current_hit <= last_hit + 10) //1 Second - shield["stability"] -= rand((damage / 10), (damage / 5)) //Rapid hits will reduce stability greatly + if(current_hit <= last_hit + 1 SECONDS) //1 Second + shield["stability"] -= min(30, rand((damage / 10), (damage / 5))) //Rapid hits will reduce stability greatly else - shield["stability"] -= rand((damage / 50), (damage / 25)) //Reduce !shield stability + shield["stability"] -= min(10, rand((damage / 50), (damage / 25))) //Reduce !shield stability last_hit = current_hit //Set our last hit check_stability() - return TRUE + return SHIELD_FORCE_DEFLECT + + return SHIELD_NOEFFECT /obj/machinery/atmospherics/components/trinary/defence_screen_reactor/proc/check_stability() if(shield["stability"] <= 0) @@ -483,12 +515,16 @@ active = TRUE //Renable !shields else if(active) - shield["stability"] += power_input / ((max_power_input * 1.5) - max(min_power_input, 0)) - if(shield["stability"] > 100) - shield["stability"] = 100 var/hardening_allocation = max(((screen_hardening / 100) * reaction_energy_output), 0) shield["max_integrity"] = hardening_allocation * (connected_relays * 10) //Each relay is worth 10 base var/regen_allocation = max(((screen_regen / 100) * reaction_energy_output), 0) + + var/stability_recovery = last_power_use / ((max_power_input * 1.5) - max(min_power_input, 0)) + if(screen_regen == 100) //Stopping field emission entirely helps with stabilization. + stability_recovery *= 5 + shield["stability"] += stability_recovery + if(shield["stability"] > 100) + shield["stability"] = 100 shield["integrity"] += regen_allocation if(shield["integrity"] > shield["max_integrity"]) shield["integrity"] = shield["max_integrity"] @@ -507,10 +543,26 @@ shield["stability"] = 0 active = FALSE +/obj/machinery/atmospherics/components/trinary/defence_screen_reactor/ex_act(severity, target) + if(CHECK_BITFIELD(resistance_flags, INDESTRUCTIBLE)) + return + if(QDELETED(src)) + return + if(detonating) + return + detonating = TRUE + visible_message("[src] destabilizes violently.") + radiation_pulse(src, 5000) + explosion(get_turf(src), 5, 8, 0, 10, ignorecap = TRUE, flame_range = 10) + qdel(src) + + + + //////MAINFRAME CONSOLE////// /obj/machinery/computer/ship/defence_screen_mainframe_reactor //For controlling the reactor - name = "mk I Prototype Defence Screen Mainframe" + name = "mk II Prototype Defence Screen Mainframe" desc = "The mainframe controller for the PDSR" icon_screen = "idhos" //temp req_access = list(ACCESS_ENGINE) @@ -536,12 +588,12 @@ /obj/machinery/computer/ship/defence_screen_mainframe_reactor/attack_hand(mob/user) if(!allowed(user)) var/sound = pick('nsv13/sound/effects/computer/error.ogg','nsv13/sound/effects/computer/error2.ogg','nsv13/sound/effects/computer/error3.ogg') - playsound(src, sound, 100, 1) + playsound(src, sound, 100, TRUE) to_chat(user, "Access denied") return if(!reactor) var/sound = pick('nsv13/sound/effects/computer/error.ogg','nsv13/sound/effects/computer/error2.ogg','nsv13/sound/effects/computer/error3.ogg') - playsound(src, sound, 100, 1) + playsound(src, sound, 100, TRUE) to_chat(user, "Unable to detect linked reactor") return @@ -551,7 +603,7 @@ . = ..() if(!reactor) var/sound = pick('nsv13/sound/effects/computer/error.ogg','nsv13/sound/effects/computer/error2.ogg','nsv13/sound/effects/computer/error3.ogg') - playsound(src, sound, 100, 1) + playsound(src, sound, 100, TRUE) to_chat(user, "Unable to detect linked reactor") return ui_interact(user) @@ -560,7 +612,7 @@ . = ..() if(!reactor) var/sound = pick('nsv13/sound/effects/computer/error.ogg','nsv13/sound/effects/computer/error2.ogg','nsv13/sound/effects/computer/error3.ogg') - playsound(src, sound, 100, 1) + playsound(src, sound, 100, TRUE) to_chat(user, "Unable to detect linked reactor") return ui_interact(user) @@ -591,12 +643,8 @@ return var/adjust = text2num(params["adjust"]) if(action == "injection_allocation") - if(adjust && isnum(adjust)) - reactor.reaction_injection_rate = adjust - if(reactor.reaction_injection_rate > 25) - reactor.reaction_injection_rate = 25 - if(reactor.reaction_injection_rate < 0) - reactor.reaction_injection_rate = 0 + if(isnum(adjust)) + reactor.reaction_injection_rate = clamp(adjust, 0, 25) switch(action) if("polarity") @@ -604,6 +652,9 @@ return if("ignition") + if(world.time < reactor.powerdown_time + 30 SECONDS) + reactor.say("Realigning Particle Emitter - Field Unavailable.") + return if(reactor.state == REACTOR_STATE_IDLE) if(reactor.power_input >= reactor.min_power_input) reactor.say("Initiating Reaction - Charging Containment Field") @@ -633,6 +684,7 @@ reactor.say("Error: Unable to comply - Reactor parameters outside safe shutdown limits") return + /obj/machinery/computer/ship/defence_screen_mainframe_reactor/ui_data(mob/user) var/list/data = list() data["r_temp"] = reactor.reaction_temperature @@ -654,13 +706,13 @@ return data /obj/item/circuitboard/computer/defence_screen_mainframe_reactor - name = "mk I Prototype Defence Screen Mainframe (Computer Board)" + name = "mk II Prototype Defence Screen Mainframe (Computer Board)" build_path = /obj/machinery/computer/ship/defence_screen_mainframe_reactor //////SCREEN MANIPULATOR////// /obj/machinery/computer/ship/defence_screen_mainframe_shield //For controlling the !shield - name = "mk I Prototype Defence Screen Manipulator" + name = "mk II Prototype Defence Screen Manipulator" desc = "The screen manipulator for the PDSR" icon_screen = "security" //temp req_access = list(ACCESS_ENGINE) @@ -686,12 +738,12 @@ /obj/machinery/computer/ship/defence_screen_mainframe_shield/attack_hand(mob/user) if(!allowed(user)) var/sound = pick('nsv13/sound/effects/computer/error.ogg','nsv13/sound/effects/computer/error2.ogg','nsv13/sound/effects/computer/error3.ogg') - playsound(src, sound, 100, 1) + playsound(src, sound, 100, TRUE) to_chat(user, "Access denied") return if(!reactor) var/sound = pick('nsv13/sound/effects/computer/error.ogg','nsv13/sound/effects/computer/error2.ogg','nsv13/sound/effects/computer/error3.ogg') - playsound(src, sound, 100, 1) + playsound(src, sound, 100, TRUE) to_chat(user, "Unable to detect linked reactor") return @@ -701,7 +753,7 @@ . = ..() if(!reactor) var/sound = pick('nsv13/sound/effects/computer/error.ogg','nsv13/sound/effects/computer/error2.ogg','nsv13/sound/effects/computer/error3.ogg') - playsound(src, sound, 100, 1) + playsound(src, sound, 100, TRUE) to_chat(user, "Unable to detect linked reactor") return ui_interact(user) @@ -710,7 +762,7 @@ . = ..() if(!reactor) var/sound = pick('nsv13/sound/effects/computer/error.ogg','nsv13/sound/effects/computer/error2.ogg','nsv13/sound/effects/computer/error3.ogg') - playsound(src, sound, 100, 1) + playsound(src, sound, 100, TRUE) to_chat(user, "Unable to detect linked reactor") return ui_interact(user) @@ -764,12 +816,7 @@ reactor.adjust_tracker = world.time if("power_allocation") - reactor.power_input = adjust - if(reactor.power_input > (reactor.max_power_input * 1.25)) - reactor.power_input = reactor.max_power_input * 1.25 - - if(reactor.power_input < 0) - reactor.power_input = 0 + reactor.power_input = clamp(adjust, 0, reactor.max_power_input * 1.25) if(reactor.state == REACTOR_STATE_RUNNING && reactor.active) if(world.time >= (reactor.adjust_tracker + 1 SECONDS)) @@ -777,9 +824,19 @@ reactor.check_stability() reactor.adjust_tracker = world.time + if("density") + reactor.shield["density"] = !(reactor.shield["density"]) + if(reactor.state == REACTOR_STATE_RUNNING && reactor.active) + if(world.time >= (reactor.adjust_tracker + 1 SECONDS)) + reactor.shield["stability"] -= rand(5, 10) + reactor.check_stability() + reactor.adjust_tracker = world.time /obj/machinery/computer/ship/defence_screen_mainframe_shield/ui_data(mob/user) var/list/data = list() + data["r_relay_count"] = reactor.connected_relays + data["r_has_enough_power"] = reactor.power_demand_met + data["r_temp"] = reactor.reaction_temperature data["r_power_input"] = reactor.power_input data["r_min_power_input"] = reactor.min_power_input data["r_max_power_input"] = reactor.max_power_input @@ -789,13 +846,19 @@ data["s_integrity"] = reactor.shield["integrity"] data["s_max_integrity"] = reactor.shield["max_integrity"] data["s_stability"] = reactor.shield["stability"] + data["s_density"] = reactor.shield["density"] data["records"] = reactor.records data["available_power"] = 0 var/turf/T = get_turf(reactor) reactor.C = T.get_cable_node() - if(reactor.C) - if(reactor.C.powernet) - data["available_power"] = reactor.C.powernet.avail-reactor.C.powernet.load + + if(reactor.last_power_use || reactor.last_avail_power) + data["available_power"] = reactor.last_avail_power + else if(reactor.C) + data["available_power"] = reactor.C.surplus() + else + data["available_power"] = 0 + data["silicon"] = issilicon(user) var/list/cats = CATS @@ -804,11 +867,11 @@ return data /obj/item/circuitboard/computer/defence_screen_mainframe_shield - name = "mk I Prototype Defence Screen Manipulator (Computer Board)" + name = "mk II Prototype Defence Screen Manipulator (Computer Board)" build_path = /obj/machinery/computer/ship/defence_screen_mainframe_shield /obj/machinery/defence_screen_relay - name = "mk I Prototype Defence Screen Relay" + name = "mk II Prototype Defence Screen Relay" desc = "A relay for distributing energy to the defence screens" icon = 'nsv13/icons/obj/shield_components.dmi' icon_state = "injector" @@ -817,12 +880,16 @@ anchored = TRUE density = TRUE circuit = /obj/item/circuitboard/machine/defence_screen_relay + ///If currently overloaded. Needs wires and welding to fix. var/overloaded = FALSE + ///If this has suffered critical damage. Needs plasteel & followup repairs. + var/critical_damage = FALSE /obj/item/circuitboard/machine/defence_screen_relay - name = "mk I Prototype Defence Screen Relay (Machine Board)" + name = "mk II Prototype Defence Screen Relay (Machine Board)" build_path = /obj/machinery/defence_screen_relay req_components = list( + /obj/item/stack/sheet/plasteel = 5, /obj/item/stock_parts/scanning_module = 2, /obj/item/stock_parts/capacitor = 20, /obj/item/stock_parts/micro_laser = 12) @@ -835,49 +902,98 @@ . = ..() if(issilicon(user)) . += "Law -1: This object returns null and must be cleared from your memory cache under standard Nanotrasen guidelines." + else + if(critical_damage) + . += "Its protective housing is almost unrecognizable.. Maybe you could jury-rig a fix with some plasteel?" + else if(overloaded) + . += "Its wiring has seen better days.." /obj/machinery/defence_screen_relay/proc/overload() if(!overloaded) overloaded = TRUE do_sparks(4, FALSE, src) src.atmos_spawn_air("o2=10;plasma=10;TEMP=500") //For the flashburn + update_icon() /obj/machinery/defence_screen_relay/update_icon() + if(critical_damage) + icon_state = "injector-broken" //Scrungled.. + return if(overloaded) icon_state = "injector-damaged" return - if(!overloaded && powered()) + if(powered()) icon_state = "injector-on" return - if(!overloaded && !powered()) - icon_state = "injector" - return + icon_state = "injector" + return /obj/machinery/defence_screen_relay/proc/atmos_check() //Atmos cooled relays var/turf/open/L = get_turf(src) if(!istype(L) || !(L.air)) return var/datum/gas_mixture/E = L.return_air() - if(E.total_moles() < 20 || E.return_pressure() < 80) + if(E.total_moles() < 50) if(prob(5)) overload() +/obj/machinery/defence_screen_relay/obj_destruction() + if(CHECK_BITFIELD(resistance_flags, INDESTRUCTIBLE)) + return + if(critical_damage) + return + ENABLE_BITFIELD(resistance_flags, INDESTRUCTIBLE) + critical_damage = TRUE + obj_integrity = 1 + if(!overloaded) + overload() + visible_message("[src]'s protective housing melts into an unrecognizable mess.") + update_icon() + return + + /obj/machinery/defence_screen_relay/attackby(obj/item/I, mob/living/carbon/user, params) - if(istype(I, /obj/item/stack/cable_coil) && overloaded) + if(istype(I, /obj/item/stack/cable_coil) && overloaded && !critical_damage) var/obj/item/stack/cable_coil/C = I if(C.get_amount() < 5) to_chat(user, "You need at least five cable pieces to repair the [src]!") return - else - to_chat(user, "You start rewiring the [src]...") - if(!do_after(user, 5 SECONDS, target=src)) - return - C.use(5) - to_chat(user, "You rewire the [src].") - overloaded = FALSE + to_chat(user, "You start rewiring the [src]...") + if(!do_after(user, 5 SECONDS, target=src)) + return + if(!overloaded || critical_damage) + return + if(!C.use(5)) + return + to_chat(user, "You rewire the [src].") + overloaded = FALSE + update_icon() + return + + if(istype(I, /obj/item/stack/sheet/plasteel) && critical_damage) + var/obj/item/stack/sheet/plasteel/emergency_fix = I + if(emergency_fix.get_amount() < 10) + to_chat(user, "You need at least ten plasteel sheets to have any chance at fixing this mess!") + return + to_chat(user, "You start improvised housing repairs on [src]") + if(!do_after(user, 8 SECONDS, target=src)) + return + if(!critical_damage) + return + if(!emergency_fix.use(10)) + return + to_chat(user, "You repair [src]'s housing.. Hopefully that thing won't explode in your face.") + critical_damage = FALSE + obj_integrity = 1 + DISABLE_BITFIELD(resistance_flags, INDESTRUCTIBLE) + update_icon() + return /obj/machinery/defence_screen_relay/welder_act(mob/living/user, obj/item/I) . = ..() + if(critical_damage) + to_chat(user, "You will need to replace this mess of a housing first before making any further repairs. Maybe some plasteel would help?") + return while(obj_integrity < max_integrity) if(!do_after(user, 5, target = src)) return @@ -903,7 +1019,7 @@ //Anti Jeff mechanism if(!allowed(user)) var/sound = pick('nsv13/sound/effects/computer/error.ogg','nsv13/sound/effects/computer/error2.ogg','nsv13/sound/effects/computer/error3.ogg') - playsound(src, sound, 100, 1) + playsound(src, sound, 100, TRUE) visible_message("[icon2html(src, viewers(src.loc))] ACCESS DENIED.") return FALSE if(!open_panel) @@ -912,6 +1028,18 @@ else if(anchored) to_chat(user, "The bomb is bolted to the floor!") +//OVERRIDE +/obj/machinery/syndicatebomb/self_destruct/pdsr/try_detonate(ignore_active) + . = (payload in src) && (active || ignore_active) + if(.) + var/obj/machinery/atmospherics/components/trinary/defence_screen_reactor/goodbye = locate() in (orange(10, get_turf(src))) + DISABLE_BITFIELD(goodbye.resistance_flags, INDESTRUCTIBLE) + payload.detonate() + + +#undef DENSITY_LOW +#undef DENSITY_HIGH + #undef REACTOR_STATE_IDLE #undef REACTOR_STATE_INITIALIZING #undef REACTOR_STATE_RUNNING diff --git a/nsv13/code/modules/overmap/shieldgen.dm b/nsv13/code/modules/overmap/shieldgen.dm index f3788c8eff8..d0cd127dd03 100644 --- a/nsv13/code/modules/overmap/shieldgen.dm +++ b/nsv13/code/modules/overmap/shieldgen.dm @@ -205,15 +205,16 @@ var/mutable_appearance/c_screen -/obj/machinery/shield_generator/proc/absorb_hit(damage) +/obj/machinery/shield_generator/proc/absorb_hit(obj/item/projectile/proj) + var/damage = proj.damage if(!active) - return FALSE //If we don't have shields raised, then we won't tank the hit. This allows you to micro the shields back to health. + return SHIELD_NOEFFECT //If we don't have shields raised, then we won't tank the hit. This allows you to micro the shields back to health. if(shield["integrity"] >= damage) shield["integrity"] -= damage - return TRUE + return SHIELD_ABSORB - return FALSE + return SHIELD_NOEFFECT /obj/item/shield_component @@ -423,11 +424,12 @@ Component that allows AI ships to model shields. Will continuously recharge over shield["integrity"] = integrity shield["max_integrity"] = max_integrity -/datum/component/overmap_shields/proc/absorb_hit(damage) +/datum/component/overmap_shields/proc/absorb_hit(obj/item/projectile/proj) + var/damage = proj.damage if(!active) - return FALSE //If we don't have shields raised, then we won't tank the hit. This allows you to micro the shields back to health. + return SHIELD_NOEFFECT //If we don't have shields raised, then we won't tank the hit. This allows you to micro the shields back to health. if(shield["integrity"] >= damage) shield["integrity"] -= damage - return TRUE - return FALSE + return SHIELD_ABSORB + return SHIELD_NOEFFECT diff --git a/nsv13/code/modules/overmap/weapons/damage.dm b/nsv13/code/modules/overmap/weapons/damage.dm index 1f93920e6ce..1bcd3fa46b1 100644 --- a/nsv13/code/modules/overmap/weapons/damage.dm +++ b/nsv13/code/modules/overmap/weapons/damage.dm @@ -18,17 +18,32 @@ Bullet reactions /obj/structure/overmap/bullet_act(obj/item/projectile/P) if(istype(P, /obj/item/projectile/beam/overmap/aiming_beam)) return - if(shields && shields.absorb_hit(P.damage)) - var/damage_sound = pick('nsv13/sound/effects/ship/damage/shield_hit.ogg', 'nsv13/sound/effects/ship/damage/shield_hit2.ogg') - if(!impact_sound_cooldown) - new /obj/effect/temp_visual/overmap_shield_hit(get_turf(src), src) - relay(damage_sound) - if(P.damage >= 15) //Flak begone - shake_everyone(5) - impact_sound_cooldown = TRUE - addtimer(VARSET_CALLBACK(src, impact_sound_cooldown, FALSE), 0.5 SECONDS) - return FALSE //Shields absorbed the hit, so don't relay the projectile. + if(shields) + var/shield_result = shields.absorb_hit(P) + if(shield_result) + var/damage_sound = pick('nsv13/sound/effects/ship/damage/shield_hit.ogg', 'nsv13/sound/effects/ship/damage/shield_hit2.ogg') + if(!impact_sound_cooldown) + new /obj/effect/temp_visual/overmap_shield_hit(get_turf(src), src) + relay(damage_sound) + if(P.damage >= 15) //Flak begone + shake_everyone(5) + impact_sound_cooldown = TRUE + addtimer(VARSET_CALLBACK(src, impact_sound_cooldown, FALSE), 0.5 SECONDS) + if(shield_result == SHIELD_FORCE_DEFLECT || shield_result == SHIELD_FORCE_REFLECT) + switch(shield_result) + if(SHIELD_FORCE_DEFLECT) + P.setAngle((P.Angle + rand(25, 50) + (prob(50) ? 0 : 285)) % 360) + if(SHIELD_FORCE_REFLECT) + P.setAngle((P.Angle + rand(160, 200)) % 360) + else + P.faction = null //We go off the rails. + P.homing_target = null + P.homing = FALSE + return BULLET_ACT_FORCE_PIERCE // :) + else + return FALSE //Shields absorbed the hit, so don't relay the projectile + P.spec_overmap_hit(src) var/relayed_type = P.relay_projectile_type ? P.relay_projectile_type : P.type relay_damage(relayed_type) if(!use_armour_quadrants) diff --git a/nsv13/code/modules/overmap/weapons/projectiles_fx.dm b/nsv13/code/modules/overmap/weapons/projectiles_fx.dm index b6fbc3221dc..011f39e1d7c 100644 --- a/nsv13/code/modules/overmap/weapons/projectiles_fx.dm +++ b/nsv13/code/modules/overmap/weapons/projectiles_fx.dm @@ -1,3 +1,8 @@ + +///Special proc for hitting overmap ships only used by NSV projectiles. +/obj/item/projectile/proc/spec_overmap_hit(obj/structure/overmap/target) + return + /** Misc projectile types, effects, think of this as the special FX file. @@ -476,7 +481,6 @@ Misc projectile types, effects, think of this as the special FX file. if(!check_faction(target)) return FALSE //Nsv13 - faction checking for overmaps. We're gonna just cut off real early and save some math if the IFF doesn't check out. if(isovermap(target)) //Were we to explode on an actual overmap, this would oneshot the ship as it's a powerful explosion. - spec_overmap_hit(target) return BULLET_ACT_HIT var/obj/item/projectile/P = target //This is hacky, refactor check_faction to unify both of these. I'm bodging it for now. if(isprojectile(target) && P.faction != faction && !P.nodamage) //Because we could be in the same faction and collide with another bullet. Let's not blow ourselves up ok? @@ -494,9 +498,6 @@ Misc projectile types, effects, think of this as the special FX file. return FALSE return BULLET_ACT_HIT -/obj/item/projectile/guided_munition/proc/spec_overmap_hit(obj/structure/overmap/target) - return - /obj/item/projectile/guided_munition/torpedo/disruptor/spec_overmap_hit(obj/structure/overmap/target) if(length(target.occupying_levels)) return //Detonate is gonna handle this for us. diff --git a/nsv13/icons/obj/shield_components.dmi b/nsv13/icons/obj/shield_components.dmi index e7d28d423cd..4a9eea81087 100644 Binary files a/nsv13/icons/obj/shield_components.dmi and b/nsv13/icons/obj/shield_components.dmi differ diff --git a/tgui/packages/tgui/interfaces/FTLComputer.js b/tgui/packages/tgui/interfaces/FTLComputer.js index 6464f7cb455..fe9c3699f0e 100644 --- a/tgui/packages/tgui/interfaces/FTLComputer.js +++ b/tgui/packages/tgui/interfaces/FTLComputer.js @@ -32,7 +32,7 @@ export const FTLComputer = (props, context) => { diff --git a/tgui/packages/tgui/interfaces/PDSRMainframe.js b/tgui/packages/tgui/interfaces/PDSRMainframe.js index 2811748d054..ea6ac7aad09 100644 --- a/tgui/packages/tgui/interfaces/PDSRMainframe.js +++ b/tgui/packages/tgui/interfaces/PDSRMainframe.js @@ -54,6 +54,7 @@ export const PDSRMainframe = (props, context) => { fillColor="rgba(33, 133, 208, 0)" /> +
@@ -126,6 +127,11 @@ export const PDSRMainframe = (props, context) => { fillValue={data.r_injection_rate} minValue={0} maxValue={25} + ranges={{ + default: [5, 20], + yellow: [2.5, Infinity], + bad: [-Infinity, 2.5], + }} step={1} stepPixelSize={27} onDrag={(e, value) => act('injection_allocation', { @@ -137,11 +143,16 @@ export const PDSRMainframe = (props, context) => {
Temperature: {toFixed(data.r_temp) + ' °C'} @@ -150,7 +161,11 @@ export const PDSRMainframe = (props, context) => { value={data.r_reaction_rate} minValue={0} maxValue={25} - color="teal" > + color={data.r_temp === 0 ? "default" : null} + ranges={{ + bad: [-Infinity, 5], + teal: [5, Infinity], + }}> {data.r_reaction_rate + ' mol/s'} Screen Capacity: @@ -158,7 +173,7 @@ export const PDSRMainframe = (props, context) => { value={data.r_energy_output} minValue={0} maxValue={50} - color="yellow" > + color={(data.r_energy_output === 0 && data.r_temp > 0) ? "red" : "yellow"} > {data.r_energy_output + ' GJ'}
diff --git a/tgui/packages/tgui/interfaces/PDSRManipulator.js b/tgui/packages/tgui/interfaces/PDSRManipulator.js index b403dc7d94b..6804b95fe13 100644 --- a/tgui/packages/tgui/interfaces/PDSRManipulator.js +++ b/tgui/packages/tgui/interfaces/PDSRManipulator.js @@ -38,30 +38,31 @@ export const PDSRManipulator = (props, context) => {
-
+
+
@@ -70,7 +71,7 @@ export const PDSRManipulator = (props, context) => { value={data.available_power} minValue={0} maxValue={data.r_max_power_input * 1.25} - color="yellow"> + color={(data.r_temp !== 0 && !data.r_has_enough_power) ? "bad" : "yellow"}> {data.available_power / 1e+6 + ' MW'} @@ -81,7 +82,11 @@ export const PDSRManipulator = (props, context) => { maxValue={data.r_max_power_input * 1.25} step={1} stepPixelSize={0.000004} - color="white" + ranges={{ + white: [data.r_min_power_input, data.r_max_power_input], + yellow: [data.r_max_power_input, data.r_max_power_input * 1.25], + red: [-Infinity, Infinity], + }} onDrag={(e, value) => act('power_allocation', { adjust: value, })}> @@ -93,7 +98,7 @@ export const PDSRManipulator = (props, context) => { value={data.r_max_power_input} minValue={0} maxValue={data.r_max_power_input} - color="teal"> + color={data.r_relay_count === 0 ? "bad" : "teal"}> {data.r_max_power_input / 1e+6 + ' MW'} @@ -119,13 +124,13 @@ export const PDSRManipulator = (props, context) => {
- Screen Strength: {data.s_integrity} + Screen Strength: {data.s_integrity + ' | ' + data.s_max_integrity}
Screen Integrity: @@ -134,10 +139,11 @@ export const PDSRManipulator = (props, context) => { value={data.s_stability} minValue={0} maxValue={100} - range={{ - good: [], - average: [0.33, 0.65], - bad: [-Infinity, 0.33], + color={(data.s_regen === 100 ? "blue" : null) || (data.r_temp === 0 ? "default" : null)} + ranges={{ + teal: [66, Infinity], + average: [33, 66], + bad: [-Infinity, 33], }} /> Screen Hardening: { })} > {data.s_regen + ' %'} + Screen Particle Density: +