diff --git a/code/__DEFINES/mining.dm b/code/__DEFINES/mining.dm index 2f4b5446476..11d150a453d 100644 --- a/code/__DEFINES/mining.dm +++ b/code/__DEFINES/mining.dm @@ -44,4 +44,6 @@ /// The multiplier that gets applied for automatically generated mining points. #define MINING_POINT_MACHINE_MULTIPLIER 0.8 - +//String defines to use with CaveGenerator presets for what ore breakdown to use. +#define OREGEN_PRESET_LAVALAND "lavaland" +#define OREGEN_PRESET_TRIPLE_Z "triple_z" diff --git a/code/_globalvars/lists/ores_spawned.dm b/code/_globalvars/lists/ores_spawned.dm new file mode 100644 index 00000000000..227e06061ad --- /dev/null +++ b/code/_globalvars/lists/ores_spawned.dm @@ -0,0 +1,35 @@ +/** + * Sets of global lists breaking down the base spawning distributions for various maps and stations. + * + * Currently used for ore vents on roundstart when the map is generated. (See ore_vent.dm, seedRuins() and ore_generation.dm) + * Ore vent lists here are copied to ore_vent_minerals on ruin seeding, + * in order to dynamically adjust the spawn rates as materials are picked and set a global ore distribution from vents. + * + * By default vents pull 4 unique materials each, but this can vary with subtypes. + */ + +GLOBAL_LIST_INIT(ore_vent_minerals_lavaland, list( + /datum/material/iron = 13, + /datum/material/glass = 12, + /datum/material/plasma = 9, + /datum/material/titanium = 6, + /datum/material/silver = 5, + /datum/material/gold = 5, + /datum/material/diamond = 3, + /datum/material/uranium = 3, + /datum/material/bluespace = 3, + /datum/material/plastic = 1, + )) + +GLOBAL_LIST_INIT(ore_vent_minerals_triple_z, list( + /datum/material/iron = 24, + /datum/material/glass = 23, + /datum/material/plasma = 16, + /datum/material/titanium = 10, + /datum/material/silver = 8, + /datum/material/gold = 7, + /datum/material/diamond = 4, + /datum/material/uranium = 4, + /datum/material/bluespace = 3, + /datum/material/plastic = 1, + )) diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 3cc301a38ed..d010e3f95b5 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -247,12 +247,12 @@ SUBSYSTEM_DEF(mapping) // Generate mining ruins var/list/lava_ruins = levels_by_trait(ZTRAIT_LAVA_RUINS) if (lava_ruins.len) - seedRuins(lava_ruins, CONFIG_GET(number/lavaland_budget), list(/area/lavaland/surface/outdoors/unexplored), themed_ruins[ZTRAIT_LAVA_RUINS], clear_below = TRUE) + seedRuins(lava_ruins, CONFIG_GET(number/lavaland_budget), list(/area/lavaland/surface/outdoors/unexplored), themed_ruins[ZTRAIT_LAVA_RUINS], clear_below = TRUE, mineral_budget = 15, mineral_budget_update = OREGEN_PRESET_LAVALAND) var/list/ice_ruins = levels_by_trait(ZTRAIT_ICE_RUINS) if (ice_ruins.len) // needs to be whitelisted for underground too so place_below ruins work - seedRuins(ice_ruins, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/surface/outdoors/unexplored, /area/icemoon/underground/unexplored), themed_ruins[ZTRAIT_ICE_RUINS], clear_below = TRUE, mineral_budget = 4) + seedRuins(ice_ruins, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/surface/outdoors/unexplored, /area/icemoon/underground/unexplored), themed_ruins[ZTRAIT_ICE_RUINS], clear_below = TRUE, mineral_budget = 4, mineral_budget_update = OREGEN_PRESET_TRIPLE_Z) var/list/ice_ruins_underground = levels_by_trait(ZTRAIT_ICE_RUINS_UNDERGROUND) if (ice_ruins_underground.len) diff --git a/code/controllers/subsystem/ore_generation.dm b/code/controllers/subsystem/ore_generation.dm index e659b10d873..162bc2e99d9 100644 --- a/code/controllers/subsystem/ore_generation.dm +++ b/code/controllers/subsystem/ore_generation.dm @@ -11,29 +11,18 @@ SUBSYSTEM_DEF(ore_generation) var/list/available_boulders = list() /// All the ore vents that are currently in the game, not just the ones that are producing boulders. var/list/possible_vents = list() - /// A list of all the minerals that are being mined by ore vents. We reset this list every time cave generation is done. - var/list/ore_vent_minerals = list() /** - * Associated list of minerals to be associated with our ore vents. + * A list of all the minerals that are being mined by ore vents. We reset this list every time cave generation is done. * Generally Should be empty by the time initialize ends on lavaland. * Each key value is the number of vents that will have this ore as a unique possible choice. + * If we call cave_generation more than once, we copy a list from the lists in lists/ores_spawned.dm */ - var/static/list/ore_vent_minerals_default = list( - /datum/material/iron = 13, - /datum/material/glass = 12, - /datum/material/plasma = 9, - /datum/material/titanium = 6, - /datum/material/silver = 5, - /datum/material/gold = 5, - /datum/material/diamond = 3, - /datum/material/uranium = 3, - /datum/material/bluespace = 3, - /datum/material/plastic = 1, - ) + var/list/ore_vent_minerals = list() + /// A tracker of how many of each ore vent size we have in the game. Useful for tracking purposes. var/list/ore_vent_sizes = list( - LARGE_VENT_TYPE = 3, - MEDIUM_VENT_TYPE = 5, - SMALL_VENT_TYPE = 7, + LARGE_VENT_TYPE = 0, + MEDIUM_VENT_TYPE = 0, + SMALL_VENT_TYPE = 0, ) /// Ores spawned by proximity to an ore vent. Useful for logging purposes. var/list/post_ore_random = list( @@ -54,13 +43,20 @@ SUBSYSTEM_DEF(ore_generation) /datum/controller/subsystem/ore_generation/Initialize() //Basically, we're going to round robin through the list of ore vents and assign a mineral to them until complete. - while(ore_vent_minerals.len > 0) + while(length(ore_vent_minerals) > 0) //Keep looping if there's more to assign + var/stallbreaker = 0 for(var/obj/structure/ore_vent/vent as anything in possible_vents) + if(length(ore_vent_minerals) <= 0) //But break early if there's none left. + break if(vent.unique_vent) continue //Ya'll already got your minerals. - if(ore_vent_minerals.len <= 0) - break - vent.generate_mineral_breakdown(max_minerals = 1, map_loading = TRUE) + if(length(difflist(first = ore_vent_minerals, second = vent.mineral_breakdown, skiprep = 1))) + vent.generate_mineral_breakdown(new_minerals = 1, map_loading = TRUE) + else + stallbreaker++ + if(stallbreaker >= length(possible_vents)) + return SS_INIT_SUCCESS //We've done all we can here. + continue return SS_INIT_SUCCESS /datum/controller/subsystem/ore_generation/fire(resumed) diff --git a/code/datums/mapgen/CaveGenerator.dm b/code/datums/mapgen/CaveGenerator.dm index fdfe989e62e..7ace9dd0f24 100644 --- a/code/datums/mapgen/CaveGenerator.dm +++ b/code/datums/mapgen/CaveGenerator.dm @@ -114,7 +114,6 @@ var/megas_allowed = (generate_in.area_flags & MEGAFAUNA_SPAWN_ALLOWED) && length(megafauna_spawn_list) var/start_time = REALTIMEOFDAY - SSore_generation.ore_vent_minerals = (SSore_generation.ore_vent_minerals_default).Copy() //reset the ore vent minerals to the default for(var/turf/target_turf as anything in turfs) if(!(target_turf.type in open_turf_types)) //only put stuff on open turfs we generated, so closed walls and rivers and stuff are skipped diff --git a/code/datums/mapgen/Cavegens/IcemoonCaves.dm b/code/datums/mapgen/Cavegens/IcemoonCaves.dm index afabc7ffd43..9d7fb39af71 100644 --- a/code/datums/mapgen/Cavegens/IcemoonCaves.dm +++ b/code/datums/mapgen/Cavegens/IcemoonCaves.dm @@ -39,6 +39,13 @@ birth_limit = 5 death_limit = 4 smoothing_iterations = 10 + weighted_feature_spawn_list = list( + /obj/structure/geyser/hollowwater = 10, + /obj/structure/geyser/plasma_oxide = 10, + /obj/structure/geyser/protozine = 10, + /obj/structure/geyser/random = 2, + /obj/structure/geyser/wittel = 10, + ) /// Surface snow generator variant for forested station trait, WITH FORESTSSSS /datum/map_generator/cave_generator/icemoon/surface/forested diff --git a/code/game/objects/structures/lavaland/ore_vent.dm b/code/game/objects/structures/lavaland/ore_vent.dm index 72cdd7d4ba5..fe663efec48 100644 --- a/code/game/objects/structures/lavaland/ore_vent.dm +++ b/code/game/objects/structures/lavaland/ore_vent.dm @@ -18,7 +18,7 @@ var/tapped = FALSE /// Has this vent been scanned by a mining scanner? Cannot be scanned again. Adds ores to the vent's description. var/discovered = FALSE - /// Is this type of vent exempt from the 15 vent limit? Think the free iron/glass vent or boss vents. This also causes it to not roll for random mineral breakdown. + /// Is this type of vent exempt from the map's vent budget/limit? Think the free iron/glass vent or boss vents. This also causes it to not roll for random mineral breakdown. var/unique_vent = FALSE /// What icon_state do we use when the ore vent has been tapped? var/icon_state_tapped = "ore_vent_active" @@ -74,7 +74,8 @@ if(mapload) generate_description() register_context() - SSore_generation.possible_vents += src + if(!unique_vent) + SSore_generation.possible_vents += src boulder_icon_state = pick(list( "boulder", "rock", @@ -168,33 +169,37 @@ /** * This proc is called when the ore vent is initialized, in order to determine what minerals boulders it spawns can contain. * The materials available are determined by SSore_generation.ore_vent_minerals, which is a list of all minerals that can be contained in ore vents for a given cave generation. - * As a result, minerals use a weighted list as seen by ore_vent_minerals_default, which is then copied to ore_vent_minerals. + * As a result, minerals use a weighted list as seen by ore_vent_minerals_lavaland, which is then copied to ore_vent_minerals. * Once a material is picked from the weighted list, it's removed from ore_vent_minerals, so that it can't be picked again and provided it's own internal weight used when assigning minerals to boulders spawned by this vent. * May also be called after the fact, as seen in SSore_generation's initialize, to add more minerals to an existing vent. * - * The above applies only when spawning in at mapload, otherwise we pick randomly from ore_vent_minerals_default. + * The above applies only when spawning in at mapload, otherwise we pick randomly from ore_vent_minerals_lavaland. * - * @params max_minerals How many minerals should be added to this vent? Defaults to MINERAL_TYPE_OPTIONS_RANDOM, which is 4. - * @params map_loading Is this vent being spawned in at mapload? If so, we use the ore_generation subsystem's ore_vent_minerals list to pick minerals. Otherwise, we pick randomly from ore_vent_minerals_default. + * @params new_minerals How many minerals should be added to this vent? Defaults to MINERAL_TYPE_OPTIONS_RANDOM, which is 4. + * @params map_loading Is this vent being spawned in at mapload? If so, we use the ore_generation subsystem's ore_vent_minerals list to pick minerals. Otherwise, we pick randomly from ore_vent_minerals_lavaland. */ -/obj/structure/ore_vent/proc/generate_mineral_breakdown(max_minerals = MINERAL_TYPE_OPTIONS_RANDOM, map_loading = FALSE) - if(max_minerals < 1) - CRASH("generate_mineral_breakdown called with max_minerals < 1.") - for(var/iterator in 1 to max_minerals) - if(!SSore_generation.ore_vent_minerals.len && map_loading) - CRASH("No minerals left to pick from! We may have spawned too many ore vents in init, or added too many ores to the existing vents.") - var/datum/material/material +/obj/structure/ore_vent/proc/generate_mineral_breakdown(new_minerals = MINERAL_TYPE_OPTIONS_RANDOM, map_loading = FALSE) + if(new_minerals < 1) + CRASH("generate_mineral_breakdown called with new_minerals < 1.") + var/list/available_mats = difflist(first = SSore_generation.ore_vent_minerals, second = mineral_breakdown, skiprep = 1) + for(var/i in 1 to new_minerals) + if(!length(SSore_generation.ore_vent_minerals) && map_loading) + // We should prevent this from happening in SSore_generation, but if not then we crash here + CRASH("No minerals left to pick from! We may have spawned too many ore vents in init, or the map config in seedRuins may not have enough resources for the mineral budget.") + var/datum/material/new_material if(map_loading) - material = pick_weight(SSore_generation.ore_vent_minerals) - if(is_type_in_list(mineral_breakdown, material)) - continue - if(map_loading) - SSore_generation.ore_vent_minerals[material] -= 1 //We remove 1 from the ore vent's mineral breakdown weight, so that it can't be picked again. - if(SSore_generation.ore_vent_minerals[material] <= 0) - SSore_generation.ore_vent_minerals -= material + if(length(available_mats)) + new_material = pick(GLOB.ore_vent_minerals_lavaland) + var/datum/material/surrogate_mat = pick(SSore_generation.ore_vent_minerals) + available_mats -= surrogate_mat + SSore_generation.ore_vent_minerals -= surrogate_mat + else + new_material = pick(available_mats) + available_mats -= new_material + SSore_generation.ore_vent_minerals -= new_material else - material = pick_weight(SSore_generation.ore_vent_minerals_default) - mineral_breakdown[material] = rand(1, 4) + new_material = pick(GLOB.ore_vent_minerals_lavaland) + mineral_breakdown[new_material] = rand(1, 4) /** @@ -416,15 +421,15 @@ if(LARGE_VENT_TYPE) boulder_size = BOULDER_SIZE_LARGE if(mapload) - SSore_generation.ore_vent_sizes["large"] -= 1 + SSore_generation.ore_vent_sizes["large"] += 1 if(MEDIUM_VENT_TYPE) boulder_size = BOULDER_SIZE_MEDIUM if(mapload) - SSore_generation.ore_vent_sizes["medium"] -= 1 + SSore_generation.ore_vent_sizes["medium"] += 1 if(SMALL_VENT_TYPE) boulder_size = BOULDER_SIZE_SMALL if(mapload) - SSore_generation.ore_vent_sizes["small"] -= 1 + SSore_generation.ore_vent_sizes["small"] += 1 else boulder_size = BOULDER_SIZE_SMALL //Might as well set a default value name = initial(name) diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm index df9df7654d0..4d2a1d7ba6d 100644 --- a/code/game/turfs/closed/minerals.dm +++ b/code/game/turfs/closed/minerals.dm @@ -103,8 +103,6 @@ var/distance = 128 // Max distance for a get_dist is 127 for(var/obj/structure/ore_vent/vent as anything in SSore_generation.possible_vents) - if(vent.unique_vent) - continue if(vent.z != src.z) continue //Silly var/temp_distance = get_dist(src, vent) diff --git a/code/modules/mapping/ruins.dm b/code/modules/mapping/ruins.dm index d5ffa9f968d..4987016c5a0 100644 --- a/code/modules/mapping/ruins.dm +++ b/code/modules/mapping/ruins.dm @@ -71,8 +71,9 @@ * @param potentialRuins A list of ruins to choose from. * @param clear_below Whether to clear the area below the ruin. Used for multiz ruins. * @param mineral_budget The budget to spend on ruins that spawn ore vents. Map templates with vents have that defined by mineral_cost. + * @param mineral_budget_update What type of ore distribution should spawn from ruins picked by this cave generator? This list is copied from ores_spawned.dm into SSore_generation.ore_vent_minerals. */ -/proc/seedRuins(list/z_levels = null, budget = 0, whitelist = list(/area/space), list/potentialRuins, clear_below = FALSE, mineral_budget = 15) +/proc/seedRuins(list/z_levels = null, budget = 0, whitelist = list(/area/space), list/potentialRuins, clear_below = FALSE, mineral_budget = 15, mineral_budget_update) if(!z_levels || !z_levels.len) WARNING("No Z levels provided - Not generating ruins") return @@ -92,6 +93,12 @@ if(PERFORM_ALL_TESTS(log_mapping)) log_mapping("All ruins being loaded for map testing.") + switch(mineral_budget_update) //If we use more map configurations, add another case + if(OREGEN_PRESET_LAVALAND) + SSore_generation.ore_vent_minerals = expand_weights(GLOB.ore_vent_minerals_lavaland) + if(OREGEN_PRESET_TRIPLE_Z) + SSore_generation.ore_vent_minerals = expand_weights(GLOB.ore_vent_minerals_triple_z) + //Set up the starting ruin list for(var/key in ruins) var/datum/map_template/ruin/R = ruins[key] diff --git a/code/modules/mining/boulder_processing/refinery.dm b/code/modules/mining/boulder_processing/refinery.dm index 828ace377e9..a6c6c2e7dfc 100644 --- a/code/modules/mining/boulder_processing/refinery.dm +++ b/code/modules/mining/boulder_processing/refinery.dm @@ -1,15 +1,11 @@ /** * Your new favorite industrial waste magnet! * Accepts boulders and produces sheets of non-metalic materials. - * Can be upgraded with stock parts or through chemical inputs. * When upgraded, it can hold more boulders and process more at once. - * - * Chemical inputs can be used to boost the refinery's efficiency, but produces industrial waste, which eats through the station and is generally difficult to store. */ - /obj/machinery/bouldertech/refinery name = "boulder refinery" - desc = "BR for short. Accepts boulders and refines non-metallic ores into sheets using internal chemicals. Can be upgraded with stock parts or through chemical inputs." + desc = "BR for short. Accepts boulders and refines non-metallic ores into sheets using internal chemicals." icon_state = "stacker" holds_minerals = TRUE processable_materials = list( @@ -53,14 +49,11 @@ /** * Your other new favorite industrial waste magnet! * Accepts boulders and produces sheets of metalic materials. - * Can be upgraded with stock parts or through chemical inputs. * When upgraded, it can hold more boulders and process more at once. - * - * Chemical inputs can be used to boost the refinery's efficiency, but produces industrial waste, which eats through the station and is generally difficult to store. */ /obj/machinery/bouldertech/refinery/smelter name = "boulder smelter" - desc = "BS for short. Accept boulders and refines metallic ores into sheets. Can be upgraded with stock parts or through gas inputs." + desc = "BS for short. Accept boulders and refines metallic ores into sheets." icon_state = "smelter" processable_materials = list( /datum/material/iron, @@ -90,7 +83,6 @@ set_light_on(TRUE) return TRUE - /obj/machinery/bouldertech/refinery/smelter/process() . = ..() if(. == PROCESS_KILL) diff --git a/tgstation.dme b/tgstation.dme index 4840a63e042..92c4b4ddb16 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -528,6 +528,7 @@ #include "code\_globalvars\lists\mobs.dm" #include "code\_globalvars\lists\names.dm" #include "code\_globalvars\lists\objects.dm" +#include "code\_globalvars\lists\ores_spawned.dm" #include "code\_globalvars\lists\plumbing.dm" #include "code\_globalvars\lists\poll_ignore.dm" #include "code\_globalvars\lists\quirks.dm"