Overclocked Vent Pumps (#78583)

## About The Pull Request

Adds in the capability for vent pumps to be overclocked, which allows
them to ignore pressure differentials and move their entire air contents
each process. Doing this causes them to take damage over time however
which causes them to be less effective in normal operation.
**the penalty for low integrity does not apply to fans which are
overclocked, however reaching 0 integrity will still disable them**
## Why It's Good For The Game

Engineers got used to vent pumps being stupid and ignoring pressure, now
its a feature not a bug.
## Changelog
🆑
add: Vent Pumps can now be overclocked, do some light reading in the air
alarm to figure out what this means.
balance: Vent Pumps now have fan integrity, the damaging of which
reduces their ability to move air.
sound: Overclocking sounds, including spool, stop, and loop
/🆑

---------

Co-authored-by: Emmett Gaines <ninjanomnom@gmail.com>
This commit is contained in:
Zephyr
2023-10-14 02:09:57 -04:00
committed by GitHub
co-authored by Emmett Gaines
parent bd9d7ce7a2
commit 4bca299690
11 changed files with 180 additions and 14 deletions
+7
View File
@@ -0,0 +1,7 @@
/datum/looping_sound/vent_pump_overclock
start_sound = 'sound/machines/fan_start.ogg'
start_length = 1.5 SECONDS
end_sound = 'sound/machines/fan_stop.ogg'
end_sound = 1.5 SECONDS
mid_sounds = 'sound/machines/fan_loop.ogg'
mid_length = 2 SECONDS
+12
View File
@@ -51,6 +51,13 @@
if(atom_integrity == new_value)
return
atom_integrity = new_value
on_update_integrity(old_value, new_value)
return new_value
/// Handle updates to your atom's integrity
/atom/proc/on_update_integrity(old_value, new_value)
SHOULD_NOT_SLEEP(TRUE)
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ATOM_INTEGRITY_CHANGED, old_value, new_value)
/// This mostly exists to keep atom_integrity private. Might be useful in the future.
@@ -58,6 +65,11 @@
SHOULD_BE_PURE(TRUE)
return atom_integrity
/// Similar to get_integrity, but returns the percentage as [0-1] instead.
/atom/proc/get_integrity_percentage()
SHOULD_BE_PURE(TRUE)
return round(atom_integrity / max_integrity, 0.01)
///returns the damage value of the attack after processing the atom's various armor protections
/atom/proc/run_atom_armor(damage_amount, damage_type, damage_flag = 0, attack_dir, armour_penetration = 0)
if(!uses_integrity)
@@ -287,6 +287,8 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm)
"refID" = REF(vent),
"long_name" = sanitize(vent.name),
"power" = vent.on,
"overclock" = vent.fan_overclocked,
"integrity" = vent.get_integrity_percentage(),
"checks" = vent.pressure_checks,
"excheck" = vent.pressure_checks & ATMOS_EXTERNAL_BOUND,
"incheck" = vent.pressure_checks & ATMOS_INTERNAL_BOUND,
@@ -356,6 +358,14 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm)
powering.on = !!params["val"]
powering.atmos_conditions_changed()
powering.update_appearance(UPDATE_ICON)
if("overclock")
if(isnull(vent))
return TRUE
vent.toggle_overclock()
vent.update_appearance(UPDATE_ICON)
return TRUE
if ("direction")
if (isnull(vent))
return TRUE
@@ -15,6 +15,8 @@
shift_underlay_only = FALSE
pipe_state = "uvent"
vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED
// vents are more complex machinery and so are less resistant to damage
max_integrity = 100
///Direction of pumping the gas (ATMOS_DIRECTION_RELEASING or ATMOS_DIRECTION_SIPHONING)
var/pump_direction = ATMOS_DIRECTION_RELEASING
@@ -34,6 +36,18 @@
///area this vent is assigned to
var/area/assigned_area
/// Is this vent currently overclocked, removing pressure limits but damaging the fan?
var/fan_overclocked = FALSE
/// Rate of damage per atmos process to the fan when overclocked. Set to 0 to disable damage.
var/fan_damage_rate = 0.5
/// The cached string we show for examine that lets you know how fucked up the fan is.
var/examine_condition
/// Datum for managing the overclock sound loop
var/datum/looping_sound/vent_pump_overclock/sound_loop
/obj/machinery/atmospherics/components/unary/vent_pump/Initialize(mapload)
if(!id_tag)
id_tag = assign_random_name()
@@ -42,16 +56,44 @@
tool_screentips = string_assoc_nested_list(list(
TOOL_MULTITOOL = list(
SCREENTIP_CONTEXT_LMB = "Log to link later with air sensor",
)
),
TOOL_SCREWDRIVER = list(
SCREENTIP_CONTEXT_LMB = "Repair",
),
))
AddElement(/datum/element/contextual_screentip_tools, tool_screentips)
. = ..()
sound_loop = new(src)
assign_to_area()
/obj/machinery/atmospherics/components/unary/vent_pump/on_update_integrity(old_value, new_value)
. = ..()
var/condition_string
switch(get_integrity_percentage())
if(1)
condition_string = "perfect"
if(0.75 to 0.99)
condition_string = "good"
if(0.50 to 0.74)
condition_string = "okay"
if(0.25 to 0.49)
condition_string = "bad"
else
condition_string = "terrible"
examine_condition = "The fan is in [condition_string] condition."
/obj/machinery/atmospherics/components/unary/vent_pump/examine(mob/user)
. = ..()
. += span_notice("You can link it with an air sensor using a multitool.")
if(fan_overclocked)
. += span_warning("It is currently overclocked causing it to take damage over time.")
if(get_integrity() > 0)
. += span_notice(examine_condition)
else
. += span_warning("The fan is broken.")
/obj/machinery/atmospherics/components/unary/vent_pump/multitool_act(mob/living/user, obj/item/multitool/multi_tool)
if(istype(multi_tool.buffer, /obj/machinery/air_sensor))
var/obj/machinery/air_sensor/sensor = multi_tool.buffer
@@ -63,8 +105,33 @@
multi_tool.set_buffer(src)
return TOOL_ACT_TOOLTYPE_SUCCESS
/obj/machinery/atmospherics/components/unary/vent_pump/screwdriver_act(mob/living/user, obj/item/tool)
var/time_to_repair = (10 SECONDS) * (1 - get_integrity_percentage())
if(!time_to_repair)
return FALSE
balloon_alert(user, "repairing vent...")
if(do_after(user, time_to_repair, src))
balloon_alert(user, "vent repaired")
repair_damage(max_integrity)
else
balloon_alert(user, "interrupted!")
return TOOL_ACT_TOOLTYPE_SUCCESS
/obj/machinery/atmospherics/components/unary/vent_pump/atom_fix()
set_is_operational(TRUE)
update_appearance()
return ..()
/obj/machinery/atmospherics/components/unary/vent_pump/atom_break(damage_flag)
set_is_operational(FALSE)
update_appearance()
return ..()
/obj/machinery/atmospherics/components/unary/vent_pump/Destroy()
disconnect_from_area()
QDEL_NULL(sound_loop)
var/area/vent_area = get_area(src)
if(vent_area)
@@ -107,6 +174,17 @@
. = ..()
disconnect_from_area(area_to_unregister)
/obj/machinery/atmospherics/components/unary/vent_pump/update_overlays()
. = ..()
if(!powered())
return
if(get_integrity() <= 0)
. += mutable_appearance(icon, "broken")
else if(fan_overclocked)
. += mutable_appearance(icon, "overclocked")
/obj/machinery/atmospherics/components/unary/vent_pump/update_icon_nopipes()
cut_overlays()
if(showpipe)
@@ -144,6 +222,20 @@
else // pump_direction == SIPHONING
icon_state = "vent_in"
/obj/machinery/atmospherics/components/unary/vent_pump/proc/toggle_overclock(from_break = FALSE)
fan_overclocked = !fan_overclocked
if(from_break)
playsound(src, 'sound/machines/fan_break.ogg', 100)
fan_overclocked = FALSE
if(fan_overclocked)
sound_loop.start()
else
sound_loop.stop()
update_appearance()
/obj/machinery/atmospherics/components/unary/vent_pump/process_atmos()
if(!is_operational)
return
@@ -154,6 +246,17 @@
var/turf/open/us = loc
if(!istype(us))
return
var/current_integrity = get_integrity()
if(fan_overclocked)
take_damage(fan_damage_rate, sound_effect=FALSE)
if(current_integrity == 0)
on = FALSE
set_is_operational(FALSE)
toggle_overclock(from_break = TRUE)
return
var/percent_integrity = get_integrity_percentage()
var/datum/gas_mixture/air_contents = airs[1]
var/datum/gas_mixture/environment = us.return_air()
var/environment_pressure = environment.return_pressure()
@@ -168,9 +271,13 @@
if(pressure_delta > 0)
if(air_contents.temperature > 0)
if(environment_pressure >= 50 * ONE_ATMOSPHERE)
if(!fan_overclocked && (environment_pressure >= 50 * ONE_ATMOSPHERE))
return FALSE
var/transfer_moles = (pressure_delta * environment.volume) / (air_contents.temperature * R_IDEAL_GAS_EQUATION)
if(!fan_overclocked && (percent_integrity < 1))
transfer_moles *= percent_integrity
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
if(!removed || !removed.total_moles())
@@ -187,9 +294,12 @@
pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure()))
if(pressure_delta > 0 && environment.temperature > 0)
if(air_contents.return_pressure() >= 50 * ONE_ATMOSPHERE)
if(!fan_overclocked && (air_contents.return_pressure() >= 50 * ONE_ATMOSPHERE))
return FALSE
var/transfer_moles = (pressure_delta * air_contents.volume) / (environment.temperature * R_IDEAL_GAS_EQUATION)
if(!fan_overclocked && (percent_integrity < 1))
transfer_moles *= percent_integrity
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -1459,6 +1459,7 @@
#include "code\datums\looping_sounds\item_sounds.dm"
#include "code\datums\looping_sounds\machinery_sounds.dm"
#include "code\datums\looping_sounds\music.dm"
#include "code\datums\looping_sounds\vents.dm"
#include "code\datums\looping_sounds\weather.dm"
#include "code\datums\mapgen\_MapGenerator.dm"
#include "code\datums\mapgen\CaveGenerator.dm"
@@ -8,6 +8,8 @@ export type VentProps = {
refID: string;
long_name: string;
power: BooleanLike;
overclock: BooleanLike;
integrity: number;
checks: number;
excheck: BooleanLike;
incheck: BooleanLike;
@@ -37,6 +39,8 @@ export const Vent = (props: VentProps, context) => {
refID,
long_name,
power,
overclock,
integrity,
checks,
excheck,
incheck,
@@ -50,19 +54,41 @@ export const Vent = (props: VentProps, context) => {
<Section
title={decodeHtmlEntities(long_name)}
buttons={
<Button
icon={power ? 'power-off' : 'times'}
selected={power}
content={power ? 'On' : 'Off'}
onClick={() =>
act('power', {
ref: refID,
val: Number(!power),
})
}
/>
<>
<Button
icon={power ? 'power-off' : 'times'}
selected={power}
disabled={integrity <= 0}
content={power ? 'On' : 'Off'}
onClick={() =>
act('power', {
ref: refID,
val: Number(!power),
})
}
/>
<Button
icon="gauge-high"
color={overclock ? 'green' : 'yellow'}
disabled={integrity <= 0}
onClick={() =>
act('overclock', {
ref: refID,
})
}
tooltip={`${overclock ? 'Disable' : 'Enable'} overclocking`}
/>
</>
}>
<LabeledList>
<LabeledList.Item label="Integrity">
<p
title={
'Overclocking will allow the vent to overpower extreme pressure conditions. However, it will also cause the vent to become damaged over time and eventually fail. The lower the integrity, the less effective the vent will be when in normal operation.'
}>
Integrity: {(integrity * 100).toFixed(2)}%
</p>
</LabeledList.Item>
<LabeledList.Item label="Mode">
<Button
icon="sign-in-alt"