From b485162a047d8b9045e0519e3f08021f3c0af7f1 Mon Sep 17 00:00:00 2001
From: SkyratBot <59378654+SkyratBot@users.noreply.github.com>
Date: Thu, 8 Feb 2024 16:21:12 +0100
Subject: [PATCH] [MIRROR] Station Goals are now handled by SSstation instead
of a global list (#26313)
* Station Goals are now handled by SSstation instead of a global list (#81177)
## About The Pull Request
You can now get station goals in a slightly better way over using a
`locate() in` call on a global list.
The Meteor Satellite goal no longer stores a giant list of ALL OBJECTS
in view. And now correctly only counts turfs.
## Changelog
:cl:
fix: Meteor Satellites no longer erroneously count every piece of paper
as a protected turf.
fix: As a result the station goal is slightly more difficult
/:cl:
---------
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@ users.noreply.github.com>
* Station Goals are now handled by SSstation instead of a global list
* Will it work? I do not know. But it compiles.
---------
Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@ users.noreply.github.com>
Co-authored-by: Useroth <37159550+Useroth@users.noreply.github.com>
---
code/__HELPERS/roundend.dm | 11 +++--
code/controllers/subsystem/dynamic/dynamic.dm | 12 +++---
.../subsystem/processing/station.dm | 43 ++++++++++++++++++-
code/controllers/subsystem/ticker.dm | 1 -
.../machinery/satellite/satellite_control.dm | 7 ++-
code/modules/admin/topic.dm | 1 -
code/modules/admin/verbs/debug.dm | 4 +-
code/modules/station_goals/dna_vault.dm | 4 +-
code/modules/station_goals/generate_goals.dm | 12 ------
code/modules/station_goals/meteor_shield.dm | 21 ++++++---
code/modules/station_goals/station_goal.dm | 20 +++++----
.../code/game/gamemodes/dynamic.dm | 8 ++--
.../code/computers/station_goal_computer.dm | 2 +-
13 files changed, 95 insertions(+), 51 deletions(-)
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 363ac2fc7a5..24e4194593e 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -508,11 +508,14 @@ GLOBAL_LIST_INIT(achievements_unlocked, list())
return ""
/datum/controller/subsystem/ticker/proc/goal_report()
+ var/list/goals = SSstation.get_station_goals()
+ if(!length(goals))
+ return null
+
var/list/parts = list()
- if(GLOB.station_goals.len)
- for(var/datum/station_goal/goal as anything in GLOB.station_goals)
- parts += goal.get_result()
- return "
"
+ for(var/datum/station_goal/goal as anything in SSstation.get_station_goals())
+ parts += goal.get_result()
+ return ""
///Generate a report for how much money is on station, as well as the richest crewmember on the station.
/datum/controller/subsystem/ticker/proc/market_report()
diff --git a/code/controllers/subsystem/dynamic/dynamic.dm b/code/controllers/subsystem/dynamic/dynamic.dm
index 4650414f6e0..8c593113e0b 100644
--- a/code/controllers/subsystem/dynamic/dynamic.dm
+++ b/code/controllers/subsystem/dynamic/dynamic.dm
@@ -329,16 +329,16 @@ SUBSYSTEM_DEF(dynamic)
if(ruleset.weight <= 0 || ruleset.cost <= 0)
continue
min_threat = min(ruleset.cost, min_threat)
+
var/greenshift = GLOB.dynamic_forced_extended || (threat_level < min_threat && shown_threat < min_threat) //if both shown and real threat are below any ruleset, its extended time
+ SSstation.generate_station_goals(greenshift ? INFINITY : CONFIG_GET(number/station_goal_budget))
- generate_station_goals(greenshift ? INFINITY : CONFIG_GET(number/station_goal_budget))
-
- if (GLOB.station_goals.len > 0)
- var/list/texts = list("
Special Orders for [station_name()]:
")
- for(var/datum/station_goal/station_goal as anything in GLOB.station_goals)
+ var/list/datum/station_goal/goals = SSstation.get_station_goals()
+ if(length(goals))
+ var/list/texts = list("
Special Orders for [station_name()]:
")
+ for(var/datum/station_goal/station_goal as anything in goals)
station_goal.on_report()
texts += station_goal.get_report()
-
. += texts.Join("
")
var/list/trait_list_strings = list()
diff --git a/code/controllers/subsystem/processing/station.dm b/code/controllers/subsystem/processing/station.dm
index 9d99e19a70b..cae0f410586 100644
--- a/code/controllers/subsystem/processing/station.dm
+++ b/code/controllers/subsystem/processing/station.dm
@@ -16,8 +16,10 @@ PROCESSING_SUBSYSTEM_DEF(station)
///A list of trait roles that should never be able to roll antag
var/list/antag_restricted_roles = list()
-/datum/controller/subsystem/processing/station/Initialize()
+ /// Assosciative list of station goal type -> goal instance
+ var/list/datum/station_goal/goals_by_type = list()
+/datum/controller/subsystem/processing/station/Initialize()
//If doing unit tests we don't do none of that trait shit ya know?
// Autowiki also wants consistent outputs, for example making sure the vending machine page always reports the normal products
#if !defined(UNIT_TESTS) && !defined(AUTOWIKI)
@@ -30,6 +32,45 @@ PROCESSING_SUBSYSTEM_DEF(station)
return SS_INIT_SUCCESS
+/datum/controller/subsystem/processing/station/Recover()
+ station_traits = SSstation.station_traits
+ selectable_traits_by_types = SSstation.selectable_traits_by_types
+ announcer = SSstation.announcer
+ antag_protected_roles = SSstation.antag_protected_roles
+ antag_restricted_roles = SSstation.antag_restricted_roles
+ goals_by_type = SSstation.goals_by_type
+ ..()
+
+/// This gets called by SSdynamic during initial gamemode setup.
+/// This is done because for a greenshift we want all goals to be generated
+/datum/controller/subsystem/processing/station/proc/generate_station_goals(goal_budget)
+ var/list/possible = subtypesof(/datum/station_goal)
+
+ var/goal_weights = 0
+ var/chosen_goals = list()
+ var/is_planetary = SSmapping.is_planetary()
+ while(possible.len && goal_weights < goal_budget)
+ var/datum/station_goal/picked = pick_n_take(possible)
+ if(picked::requires_space && is_planetary)
+ continue
+
+ goal_weights += initial(picked.weight)
+ chosen_goals += picked
+
+ for(var/chosen in chosen_goals)
+ new chosen()
+
+/// Returns all station goals that are currently active
+/datum/controller/subsystem/processing/station/proc/get_station_goals()
+ var/list/goals = list()
+ for(var/goal_type in goals_by_type)
+ goals += goals_by_type[goal_type]
+ return goals
+
+/// Returns a specific station goal by type
+/datum/controller/subsystem/processing/station/proc/get_station_goal(goal_type)
+ return goals_by_type[goal_type]
+
///Rolls for the amount of traits and adds them to the traits list
/datum/controller/subsystem/processing/station/proc/SetupTraits()
if (CONFIG_GET(flag/forbid_station_traits))
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 06eb8d1b882..f2bcfbf64dc 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -239,7 +239,6 @@ SUBSYSTEM_DEF(ticker)
return TRUE
return FALSE
-
/datum/controller/subsystem/ticker/proc/setup()
to_chat(world, span_boldannounce("Starting game..."))
var/init_start = world.timeofday
diff --git a/code/game/machinery/satellite/satellite_control.dm b/code/game/machinery/satellite/satellite_control.dm
index e8482fe91df..c0875d9e26a 100644
--- a/code/game/machinery/satellite/satellite_control.dm
+++ b/code/game/machinery/satellite/satellite_control.dm
@@ -44,10 +44,9 @@
))
data["notice"] = notice
-
- var/datum/station_goal/station_shield/goal = locate() in GLOB.station_goals
- if(goal)
- data["meteor_shield"] = 1
+ var/datum/station_goal/station_shield/goal = SSstation.get_station_goal(/datum/station_goal/station_shield)
+ if(!isnull(goal))
+ data["meteor_shield"] = TRUE
data["meteor_shield_coverage"] = goal.get_coverage()
data["meteor_shield_coverage_max"] = goal.coverage_goal
return data
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 9e5ae1e835c..ad8aed969af 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1392,7 +1392,6 @@
return
G.report_message = description
message_admins("[key_name(usr)] created \"[G.name]\" station goal.")
- GLOB.station_goals += G
modify_goals()
else if(href_list["change_lag_switch"])
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 260bfb16bf3..126d8756762 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -546,8 +546,8 @@
/datum/admins/proc/modify_goals()
var/dat = ""
- for(var/datum/station_goal/S in GLOB.station_goals)
- dat += "[S.name] - Announce | Remove
"
+ for(var/datum/station_goal/goal as anything in SSstation.get_station_goals())
+ dat += "[goal.name] - Announce | Remove
"
dat += "
Add New Goal"
usr << browse(dat, "window=goals;size=400x400")
diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm
index 83fb1f0ea7f..5c146758d12 100644
--- a/code/modules/station_goals/dna_vault.dm
+++ b/code/modules/station_goals/dna_vault.dm
@@ -101,8 +101,8 @@
F.parent = src
fillers += F
- var/datum/station_goal/dna_vault/dna_vault_goal = locate() in GLOB.station_goals
- if (!isnull(dna_vault_goal))
+ var/datum/station_goal/dna_vault/dna_vault_goal = SSstation.get_station_goal(/datum/station_goal/dna_vault)
+ if(!isnull(dna_vault_goal))
animals_max = dna_vault_goal.animal_count
plants_max = dna_vault_goal.plant_count
dna_max = dna_vault_goal.human_count
diff --git a/code/modules/station_goals/generate_goals.dm b/code/modules/station_goals/generate_goals.dm
index 102212c1212..b37543d6de8 100644
--- a/code/modules/station_goals/generate_goals.dm
+++ b/code/modules/station_goals/generate_goals.dm
@@ -1,13 +1 @@
/// Creates the initial station goals.
-/proc/generate_station_goals(goal_budget)
- var/list/possible = subtypesof(/datum/station_goal)
- // Remove all goals that require space if space is not present
- if(SSmapping.is_planetary())
- for(var/datum/station_goal/goal as anything in possible)
- if(initial(goal.requires_space))
- possible -= goal
- var/goal_weights = 0
- while(possible.len && goal_weights < goal_budget)
- var/datum/station_goal/picked = pick_n_take(possible)
- goal_weights += initial(picked.weight)
- GLOB.station_goals += new picked
diff --git a/code/modules/station_goals/meteor_shield.dm b/code/modules/station_goals/meteor_shield.dm
index 3b87ef74578..84a61395a4b 100644
--- a/code/modules/station_goals/meteor_shield.dm
+++ b/code/modules/station_goals/meteor_shield.dm
@@ -14,8 +14,9 @@
// Satellites be actived to generate a shield that will block unorganic matter from passing it.
/datum/station_goal/station_shield
name = "Station Shield"
- var/coverage_goal = 500
requires_space = TRUE
+ var/coverage_goal = 500
+ VAR_PRIVATE/cached_coverage_length
/datum/station_goal/station_shield/get_report()
return list(
@@ -37,17 +38,24 @@
/datum/station_goal/station_shield/check_completion()
if(..())
return TRUE
- if(get_coverage() >= coverage_goal)
+ update_coverage()
+ if(cached_coverage_length >= coverage_goal)
return TRUE
return FALSE
-/datum/station_goal/proc/get_coverage()
+/datum/station_goal/station_shield/proc/get_coverage()
+ return cached_coverage_length
+
+/// Gets the coverage of all active meteor shield satellites
+/// Can be expensive, ensure you need this before calling it
+/datum/station_goal/station_shield/proc/update_coverage()
var/list/coverage = list()
for(var/obj/machinery/satellite/meteor_shield/shield_satt as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/satellite/meteor_shield))
if(!shield_satt.active || !is_station_level(shield_satt.z))
continue
- coverage |= view(shield_satt.kill_range, shield_satt)
- return coverage.len
+ for(var/turf/covered in view(shield_satt.kill_range, shield_satt))
+ coverage |= covered
+ cached_coverage_length = length(coverage)
/obj/machinery/satellite/meteor_shield
name = "\improper Meteor Shield Satellite"
@@ -109,6 +117,9 @@
if(obj_flags & EMAGGED)
update_emagged_meteor_sat(user)
+ var/datum/station_goal/station_shield/goal = SSstation.get_station_goal(/datum/station_goal/station_shield)
+ goal?.update_coverage()
+
/obj/machinery/satellite/meteor_shield/Destroy()
. = ..()
if(obj_flags & EMAGGED)
diff --git a/code/modules/station_goals/station_goal.dm b/code/modules/station_goals/station_goal.dm
index 30ed0b78b6c..d7fd5e7f752 100644
--- a/code/modules/station_goals/station_goal.dm
+++ b/code/modules/station_goals/station_goal.dm
@@ -1,6 +1,3 @@
-/// List of available station goals for the crew to be working on
-GLOBAL_LIST_EMPTY_TYPED(station_goals, /datum/station_goal)
-
/datum/station_goal
var/name = "Generic Goal"
var/weight = 1 //In case of multiple goals later.
@@ -30,13 +27,8 @@ GLOBAL_LIST_EMPTY_TYPED(station_goals, /datum/station_goal)
else
return "[name] : [span_redtext("Failed!")]"
-/datum/station_goal/Destroy()
- GLOB.station_goals -= src
- return ..()
-
/datum/station_goal/Topic(href, href_list)
..()
-
if(!check_rights(R_ADMIN) || !usr.client.holder.CheckAdminHref(href, href_list))
return
@@ -45,3 +37,15 @@ GLOBAL_LIST_EMPTY_TYPED(station_goals, /datum/station_goal)
send_report()
else if(href_list["remove"])
qdel(src)
+
+/datum/station_goal/New()
+ if(type in SSstation.goals_by_type)
+ stack_trace("Creating a new station_goal of type [type] when one already exists in SSstation.goals_by_type this is not supported anywhere. I trust you tho")
+ else
+ SSstation.goals_by_type[type] = src
+ return ..()
+
+/datum/station_goal/Destroy(force)
+ if(SSstation.goals_by_type[type] == src)
+ SSstation.goals_by_type -= type
+ return ..()
diff --git a/modular_skyrat/master_files/code/game/gamemodes/dynamic.dm b/modular_skyrat/master_files/code/game/gamemodes/dynamic.dm
index f1524ee5d7f..4bad9e66e6f 100644
--- a/modular_skyrat/master_files/code/game/gamemodes/dynamic.dm
+++ b/modular_skyrat/master_files/code/game/gamemodes/dynamic.dm
@@ -7,9 +7,9 @@
. = "Central Command Status Summary
"
var/greenshift = GLOB.dynamic_forced_extended || (threat_level < MIN_MIDROUND_COST && shown_threat < MIN_MIDROUND_COST) // if both shown and real threat are below any ruleset, its greenshift time
- generate_station_goals(greenshift)
+ SSstation.generate_station_goals(greenshift)
- if(!GLOB.station_goals.len)
+ if(!length(SSstation.get_station_goals()))
. = "
No assigned goals.
"
else
. += generate_station_goal_report()
@@ -30,11 +30,11 @@
* Returns a formatted string all station goals that are available to the station.
*/
/datum/controller/subsystem/dynamic/proc/generate_station_goal_report()
- if(!GLOB.station_goals.len)
+ if(!length(SSstation.get_station_goals()))
return
. = "
Special Orders for [station_name()]:
"
var/list/goal_reports = list()
- for(var/datum/station_goal/station_goal as anything in GLOB.station_goals)
+ for(var/datum/station_goal/station_goal as anything in SSstation.get_station_goals())
station_goal.on_report()
goal_reports += station_goal.get_report()
diff --git a/modular_skyrat/modules/central_command_module/code/computers/station_goal_computer.dm b/modular_skyrat/modules/central_command_module/code/computers/station_goal_computer.dm
index 44bd53615a4..a1464e08d3e 100644
--- a/modular_skyrat/modules/central_command_module/code/computers/station_goal_computer.dm
+++ b/modular_skyrat/modules/central_command_module/code/computers/station_goal_computer.dm
@@ -59,7 +59,7 @@
if(initial(iterating_goal.name) == selected_goal)
var/datum/station_goal/goal_to_set = new iterating_goal()
goal_to_set.send_report()
- GLOB.station_goals += goal_to_set
+ SSstation.goals_by_type[iterating_goal] = goal_to_set
goal_assigned = TRUE
break
updateUsrDialog()