Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weather Radio Port #2517

Merged
merged 8 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions code/__DEFINES/colors.dm
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@
#define LIGHT_COLOR_LAVA "#C48A18"
/// Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75)
#define LIGHT_COLOR_FLARE "#FA644B"
/// Vivid red. Leans a bit darker to accentuate red colors and leave other channels a bit dry. rgb(200, 25, 25)
#define LIGHT_COLOR_INTENSE_RED "#C81919"
/// Weird color, between yellow and green, very slimy. rgb(175, 200, 75)
#define LIGHT_COLOR_SLIME_LAMP "#AFC84B"
/// Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175)
Expand Down
170 changes: 170 additions & 0 deletions code/datums/components/weatherannouncer.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#define WEATHER_ALERT_CLEAR 0
#define WEATHER_ALERT_INCOMING 1
#define WEATHER_ALERT_IMMINENT_OR_ACTIVE 2

/// Component which makes you yell about what the weather is
/datum/component/weather_announcer
/// Currently displayed warning level
var/warning_level = WEATHER_ALERT_CLEAR
/// Whether the incoming weather is actually going to harm you
var/is_weather_dangerous = TRUE
/// Are we actually turned on right now?
var/enabled = TRUE
/// Overlay added when things are alright
var/state_normal
/// Overlay added when you should start looking for shelter
var/state_warning
/// Overlay added when you are in danger
var/state_danger

/datum/component/weather_announcer/Initialize(
state_normal,
state_warning,
state_danger,
)
. = ..()
if (!ismovable(parent))
return COMPONENT_INCOMPATIBLE

START_PROCESSING(SSprocessing, src)
RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays))
RegisterSignal(parent, COMSIG_MACHINERY_POWER_RESTORED, PROC_REF(on_powered))
RegisterSignal(parent, COMSIG_MACHINERY_POWER_LOST, PROC_REF(on_power_lost))

src.state_normal = state_normal
src.state_warning = state_warning
src.state_danger = state_danger
var/atom/speaker = parent
speaker.update_appearance(UPDATE_ICON)
update_light_color()

/datum/component/weather_announcer/Destroy(force, silent)
STOP_PROCESSING(SSprocessing, src)
return ..()

/// Add appropriate overlays
/datum/component/weather_announcer/proc/on_update_overlays(atom/parent_atom, list/overlays)
SIGNAL_HANDLER
if (!enabled || !state_normal || !state_warning || !state_danger)
return

switch (warning_level)
if(WEATHER_ALERT_CLEAR)
overlays += state_normal
if(WEATHER_ALERT_INCOMING)
overlays += state_warning
if(WEATHER_ALERT_IMMINENT_OR_ACTIVE)
overlays += (is_weather_dangerous) ? state_danger : state_warning

/// If powered, receive updates
/datum/component/weather_announcer/proc/on_powered()
SIGNAL_HANDLER
enabled = TRUE
var/atom/speaker = parent
speaker.update_appearance(UPDATE_ICON)

/// If no power, don't receive updates
/datum/component/weather_announcer/proc/on_power_lost()
SIGNAL_HANDLER
enabled = FALSE
var/atom/speaker = parent
speaker.update_appearance(UPDATE_ICON)

/datum/component/weather_announcer/process(seconds_per_tick)
if (!enabled)
return

var/previous_level = warning_level
var/previous_danger = is_weather_dangerous
set_current_alert_level()
if(previous_level == warning_level && previous_danger == is_weather_dangerous)
return // No change
var/atom/movable/speaker = parent
speaker.say(get_warning_message())
speaker.update_appearance(UPDATE_ICON)
update_light_color()

/datum/component/weather_announcer/proc/update_light_color()
var/atom/movable/light = parent
switch(warning_level)
if(WEATHER_ALERT_CLEAR)
light.set_light_color(LIGHT_COLOR_GREEN)
if(WEATHER_ALERT_INCOMING)
light.set_light_color(LIGHT_COLOR_YELLOW)
if(WEATHER_ALERT_IMMINENT_OR_ACTIVE)
light.set_light_color(LIGHT_COLOR_INTENSE_RED)
light.update_light()

/// Returns a string we should display to communicate what you should be doing
/datum/component/weather_announcer/proc/get_warning_message()
if (!is_weather_dangerous)
return "No risk expected from incoming weather front."
switch(warning_level)
if(WEATHER_ALERT_CLEAR)
return "All clear, no weather alerts to report."
if(WEATHER_ALERT_INCOMING)
return "Weather front incoming, begin to seek shelter."
if(WEATHER_ALERT_IMMINENT_OR_ACTIVE)
return "Weather front imminent, find shelter immediately."
return "Error in meteorological calculation. Please report this deviation to a trained programmer."

/datum/component/weather_announcer/proc/time_till_storm()
var/datum/weather_controller/local_weather_controller = SSmapping.get_map_zone_weather_controller(parent)
if(!local_weather_controller.next_weather)
return null
for(var/type_index in local_weather_controller.current_weathers)
var/datum/weather/check_weather = local_weather_controller.current_weathers[type_index]
if(!check_weather.barometer_predictable || check_weather.stage == WIND_DOWN_STAGE || check_weather.stage == END_STAGE)
continue
warning_level = WEATHER_ALERT_IMMINENT_OR_ACTIVE
return 0

var/time_until_next = INFINITY
var/next_time = local_weather_controller.next_weather - world.time || INFINITY
if (next_time && next_time < time_until_next)
time_until_next = next_time
return time_until_next

/// Polls existing weather for what kind of warnings we should be displaying.
/datum/component/weather_announcer/proc/set_current_alert_level()
var/time_until_next = time_till_storm()
if(isnull(time_until_next))
return // No problems if there are no mining z levels
if(time_until_next >= 2 MINUTES)
warning_level = WEATHER_ALERT_CLEAR
return

if(time_until_next >= 30 SECONDS)
warning_level = WEATHER_ALERT_INCOMING
return

// Weather is here, now we need to figure out if it is dangerous
warning_level = WEATHER_ALERT_IMMINENT_OR_ACTIVE

var/datum/weather_controller/local_weather_controller = SSmapping.get_map_zone_weather_controller(parent)
for(var/type_index in local_weather_controller.current_weathers)
var/datum/weather/check_weather = local_weather_controller.current_weathers[type_index]
if(!check_weather.barometer_predictable || check_weather.stage == WIND_DOWN_STAGE || check_weather.stage == END_STAGE)
continue
is_weather_dangerous = !check_weather.aesthetic
return

/datum/component/weather_announcer/proc/on_examine(atom/radio, mob/examiner, list/examine_texts)
var/time_until_next = time_till_storm()
if(isnull(time_until_next))
return
if (time_until_next == 0)
examine_texts += span_warning ("A storm is currently active, please seek shelter.")
else
examine_texts += span_notice("The next storm is inbound in [DisplayTimeText(time_until_next)].")

/datum/component/weather_announcer/RegisterWithParent()
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))

/datum/component/weather_announcer/UnregisterFromParent()
.=..()
UnregisterSignal(parent, COMSIG_PARENT_EXAMINE)

#undef WEATHER_ALERT_CLEAR
#undef WEATHER_ALERT_INCOMING
#undef WEATHER_ALERT_IMMINENT_OR_ACTIVE
3 changes: 2 additions & 1 deletion code/modules/jobs/job_types/shaft_miner.dm
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
backpack_contents = list(
/obj/item/flashlight/seclite=1,\
/obj/item/kitchen/knife/combat/survival=1,\
/obj/item/stack/marker_beacon/ten=1)
/obj/item/stack/marker_beacon/ten=1,\
/obj/item/radio/weather_monitor=1)

backpack = /obj/item/storage/backpack/explorer
satchel = /obj/item/storage/backpack/satchel/explorer
Expand Down
23 changes: 23 additions & 0 deletions code/modules/mining/equipment/miningradio.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/// Portable mining radio purchasable by miners
/obj/item/radio/weather_monitor
icon = 'icons/obj/miningradio.dmi'
name = "mining weather radio"
icon_state = "miningradio"
desc = "A weather radio designed for use in inhospitable environments. Gives audible warnings when storms approach."
luminosity = 1
light_power = 1
light_range = 1.6

/obj/item/radio/weather_monitor/update_overlays()
. = ..()
. += emissive_appearance(icon, "small_emissive", src, alpha = src.alpha)

/obj/item/radio/weather_monitor/Initialize(mapload)
. = ..()
AddComponent( \
/datum/component/weather_announcer, \
state_normal = "weatherwarning", \
state_warning = "urgentwarning", \
state_danger = "direwarning", \
)
set_frequency(FREQ_COMMON)
10 changes: 10 additions & 0 deletions code/modules/research/designs/mining_designs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,13 @@
build_path = /obj/item/borg/upgrade/modkit/aoe/turfs
category = list("Mining Designs", "Cyborg Upgrade Modules")
departmental_flags = DEPARTMENTAL_FLAG_CARGO

/datum/design/weather_monitor
name = "Weather Radio"
desc = "A weather radio designed for use in inhospitable environments. Gives audible warnings when storms approach."
id = "weatherradio"
build_type = PROTOLATHE
materials = list(/datum/material/iron=75, /datum/material/glass=25)
build_path = /obj/item/radio/weather_monitor
category = list("Mining Designs")
departmental_flags = DEPARTMENTAL_FLAG_CARGO
2 changes: 1 addition & 1 deletion code/modules/research/techweb/all_nodes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@
display_name = "Mining Technology"
description = "Better than Efficiency V."
prereq_ids = list("engineering", "basic_plasma")
design_ids = list("drill", "superresonator", "triggermod", "damagemod", "cooldownmod", "rangemod", "ore_redemption", "mining_equipment_vendor", "cargoexpress", "plasmacutter", "mecha_kineticgun")//e a r l y g a m e)
design_ids = list("drill", "superresonator", "triggermod", "damagemod", "cooldownmod", "rangemod", "ore_redemption", "mining_equipment_vendor", "cargoexpress", "plasmacutter", "mecha_kineticgun", "weatherradio")//e a r l y g a m e)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000

Expand Down
Binary file added icons/obj/miningradio.dmi
Binary file not shown.
2 changes: 2 additions & 0 deletions shiptest.dme
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@
#include "code\datums\components\udder.dm"
#include "code\datums\components\uplink.dm"
#include "code\datums\components\wearertargeting.dm"
#include "code\datums\components\weatherannouncer.dm"
#include "code\datums\components\wet_floor.dm"
#include "code\datums\components\crafting\crafting.dm"
#include "code\datums\components\crafting\guncrafting.dm"
Expand Down Expand Up @@ -2367,6 +2368,7 @@
#include "code\modules\mining\equipment\marker_beacons.dm"
#include "code\modules\mining\equipment\mineral_scanner.dm"
#include "code\modules\mining\equipment\mining_tools.dm"
#include "code\modules\mining\equipment\miningradio.dm"
#include "code\modules\mining\equipment\regenerative_core.dm"
#include "code\modules\mining\equipment\resonator.dm"
#include "code\modules\mining\equipment\survival_pod.dm"
Expand Down