Skip to content

Commit

Permalink
Overclocked Vent Pumps (tgstation#78583)
Browse files Browse the repository at this point in the history
## 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
:cl:
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
/:cl:

---------

Co-authored-by: Emmett Gaines <[email protected]>
  • Loading branch information
ZephyrTFA and ninjanomnom authored Oct 14, 2023
1 parent bd9d7ce commit 4bca299
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 14 deletions.
7 changes: 7 additions & 0 deletions code/datums/looping_sounds/vents.dm
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions code/game/atom_defense.dm
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,25 @@
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.
/atom/proc/get_integrity()
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)
Expand Down
10 changes: 10 additions & 0 deletions code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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()
Expand All @@ -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())
Expand All @@ -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)

Expand Down
Binary file modified icons/obj/machines/atmospherics/unary_devices.dmi
Binary file not shown.
Binary file added sound/machines/fan_break.ogg
Binary file not shown.
Binary file added sound/machines/fan_loop.ogg
Binary file not shown.
Binary file added sound/machines/fan_start.ogg
Binary file not shown.
Binary file added sound/machines/fan_stop.ogg
Binary file not shown.
1 change: 1 addition & 0 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
48 changes: 37 additions & 11 deletions tgui/packages/tgui/interfaces/common/AtmosControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export type VentProps = {
refID: string;
long_name: string;
power: BooleanLike;
overclock: BooleanLike;
integrity: number;
checks: number;
excheck: BooleanLike;
incheck: BooleanLike;
Expand Down Expand Up @@ -37,6 +39,8 @@ export const Vent = (props: VentProps, context) => {
refID,
long_name,
power,
overclock,
integrity,
checks,
excheck,
incheck,
Expand All @@ -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"
Expand Down

0 comments on commit 4bca299

Please sign in to comment.