diff --git a/code/__defines/mapping.dm b/code/__defines/mapping.dm
index 5cf7407fb5e..d8219fb0c6e 100644
--- a/code/__defines/mapping.dm
+++ b/code/__defines/mapping.dm
@@ -36,3 +36,5 @@ if(other_init) { \
#define MAP_TEMPLATE_CATEGORY_EXOPLANET "exoplanet_template"
#define MAP_TEMPLATE_CATEGORY_SPACE "space_template"
#define MAP_TEMPLATE_CATEGORY_AWAYSITE "awaysite_template"
+///PS13 Template that is spawned as part of the main map, and shouldn't be considered an away site during unit tests.
+#define MAP_TEMPLATE_CATEGORY_MAIN_SITE "main_site_template"
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 07f7005f433..2996f20e2bb 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -7,9 +7,20 @@
#define TURF_IS_HOLOMAP_PATH BITFLAG(4)
#define TURF_IS_HOLOMAP_ROCK BITFLAG(5)
-#define TRANSITIONEDGE 7 // Distance from edge to move to another z-level.
+///Width or height of a transition edge area along the map's borders where transition edge turfs are placed to connect levels together.
+#define TRANSITIONEDGE 7
+///Extra spacing needed between any random ruins and the transition edge of a level.
#define RUIN_MAP_EDGE_PAD 15
+///Enum value for a level edge that's to be untouched
+#define LEVEL_EDGE_NONE 0
+///Enum value for a level edge that's to be looped with the opposite edge
+#define LEVEL_EDGE_LOOP 1
+///Enum value for a level edge that's to be filled with a wall filler turfs
+#define LEVEL_EDGE_WALL 2
+///Enum value for a level edge that's to be connected with another z-level
+#define LEVEL_EDGE_CON 3
+
// Invisibility constants.
#define INVISIBILITY_LIGHTING 20
#define INVISIBILITY_LEVEL_ONE 35
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 88e5450eb9c..77fa63d52ad 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -928,7 +928,12 @@ var/global/list/gamemode_cache = list()
config.withdraw_period = value DAYS
if("interest_period")
config.interest_period = value DAYS
-
+ if("grant_default_darksight")
+ config.grant_default_darksight = TRUE
+ if("default_darksight_range")
+ config.default_darksight_range = max(text2num(value), 0)
+ if("default_darksight_effectiveness")
+ config.default_darksight_effectiveness = clamp(text2num(value), 0, 1)
if("interest_mod_delay")
config.interest_mod_delay = value DAYS
if("withdraw_mod_delay")
diff --git a/code/controllers/subsystems/ambience.dm b/code/controllers/subsystems/ambience.dm
index 6bbe3b27fea..879c6584d8c 100644
--- a/code/controllers/subsystems/ambience.dm
+++ b/code/controllers/subsystems/ambience.dm
@@ -41,7 +41,7 @@ SUBSYSTEM_DEF(ambience)
if(lit)
// Grab what we need to set ambient light from our level handler.
- var/obj/abstract/level_data/level_data = SSmapping.levels_by_z[z]
+ var/datum/level_data/level_data = SSmapping.levels_by_z[z]
if(level_data?.ambient_light_level)
set_ambient_light(level_data.ambient_light_color, level_data.ambient_light_level)
return TRUE
diff --git a/code/controllers/subsystems/mapping.dm b/code/controllers/subsystems/mapping.dm
index 2aac24ed7eb..38d84944812 100644
--- a/code/controllers/subsystems/mapping.dm
+++ b/code/controllers/subsystems/mapping.dm
@@ -81,6 +81,8 @@ SUBSYSTEM_DEF(mapping)
// This needs to be non-null even if the overmap isn't created for this map.
overmap_event_handler = GET_DECL(/decl/overmap_event_handler)
+ //PS13 Build main map sites templates
+ global.using_map.build_main_sites()
// Build away sites.
global.using_map.build_away_sites()
@@ -89,9 +91,9 @@ SUBSYSTEM_DEF(mapping)
config.generate_map = TRUE
#endif
for(var/z = 1 to world.maxz)
- var/obj/abstract/level_data/level = levels_by_z[z]
+ var/datum/level_data/level = levels_by_z[z]
if(!istype(level))
- level = new /obj/abstract/level_data/space(locate(round(world.maxx*0.5), round(world.maxy*0.5), z))
+ level = new /datum/level_data/space(z)
PRINT_STACK_TRACE("Missing z-level data object for z[num2text(z)]!")
level.setup_level_data()
@@ -141,9 +143,10 @@ SUBSYSTEM_DEF(mapping)
// Z-Level procs after this point.
/datum/controller/subsystem/mapping/proc/get_gps_level_name(var/z)
if(z)
- var/obj/abstract/level_data/level = levels_by_z[z]
- if(level?.name)
- return level.get_gps_level_name()
+ var/datum/level_data/level = levels_by_z[z]
+ . = level.get_display_name()
+ if(length(.))
+ return .
return "Unknown Sector"
/datum/controller/subsystem/mapping/proc/reindex_lists()
@@ -162,24 +165,72 @@ SUBSYSTEM_DEF(mapping)
PRINT_STACK_TRACE("Missing z-level data type for z["[world.maxz]"]!")
return
- var/obj/abstract/level_data/level = new new_level_type(locate(round(world.maxx*0.5), round(world.maxy*0.5), world.maxz), defer_setup)
- level.initialize_level()
+ var/datum/level_data/level = new new_level_type(world.maxz, defer_setup)
+ level.initialize_new_level()
return level
/datum/controller/subsystem/mapping/proc/get_connected_levels(z)
if(z <= 0 || z > length(levels_by_z))
CRASH("Invalid z-level supplied to get_connected_levels: [isnull(z) ? "NULL" : z]")
- . = list(z)
+ var/list/root_stack = list(z)
// Traverse up and down to get the multiz stack.
for(var/level = z, HasBelow(level), level--)
- . |= level-1
+ root_stack |= level-1
for(var/level = z, HasAbove(level), level++)
- . |= level+1
+ root_stack |= level+1
+ . = list()
// Check stack for any laterally connected neighbors.
- for(var/tz in .)
- var/obj/abstract/level_data/level = levels_by_z[tz]
+ for(var/tz in root_stack)
+ var/datum/level_data/level = levels_by_z[tz]
if(level)
- level.find_connected_levels(.)
+ var/list/cur_connected = level.get_all_connected_level_z()
+ if(length(cur_connected))
+ . |= cur_connected
+ . |= root_stack
+
+///Returns a list of all the level data of all the connected z levels to the given z.DBColumn
+/datum/controller/subsystem/mapping/proc/get_connected_levels_data(z)
+ if(z <= 0 || z > length(levels_by_z))
+ CRASH("Invalid z-level supplied to get_connected_levels_data: [isnull(z) ? "NULL" : z]")
+ var/list/root_lvl_data = list(levels_by_z[z])
+
+ // Traverse up and down to get the multiz stack.
+ for(var/level = z, HasBelow(level), level--)
+ root_lvl_data |= levels_by_z[level - 1]
+ for(var/level = z, HasAbove(level), level++)
+ root_lvl_data |= levels_by_z[level + 1]
+
+ . = list()
+ // Check stack for any laterally connected neighbors.
+ for(var/datum/level_data/L in root_lvl_data)
+ var/list/cur_connected = L.get_all_connected_level_data()
+ if(length(cur_connected))
+ . |= cur_connected
+ . |= root_lvl_data
+
+/datum/controller/subsystem/mapping/proc/get_connected_levels_ids(z)
+ if(z <= 0 || z > length(levels_by_z))
+ CRASH("Invalid z-level supplied to get_connected_levels_ids: [isnull(z) ? "NULL" : z]")
+ var/datum/level_data/LD = levels_by_z[z]
+ var/list/root_lvl_ids = list(LD.level_id)
+
+ // Traverse up and down to get the multiz stack.
+ for(var/level = z, HasBelow(level), level--)
+ var/datum/level_data/L = levels_by_z[level - 1]
+ root_lvl_ids |= L.level_id
+ for(var/level = z, HasAbove(level), level++)
+ var/datum/level_data/L = levels_by_z[level + 1]
+ root_lvl_ids |= L.level_id
+
+ . = list()
+ // Check stack for any laterally connected neighbors.
+ for(var/id in root_lvl_ids)
+ var/datum/level_data/level = levels_by_id[id]
+ if(level)
+ var/list/cur_connected = level.get_all_connected_level_ids()
+ if(length(cur_connected))
+ . |= cur_connected
+ . |= root_lvl_ids
/datum/controller/subsystem/mapping/proc/are_connected_levels(var/zA, var/zB)
if (zA <= 0 || zB <= 0 || zA > world.maxz || zB > world.maxz)
@@ -196,3 +247,56 @@ SUBSYSTEM_DEF(mapping)
connected_z_cache.len = zA
connected_z_cache[zA] = new_entry
return new_entry[zB]
+
+/// Registers all the needed infos from a level_data into the mapping subsystem
+/datum/controller/subsystem/mapping/proc/register_level_data(var/datum/level_data/LD)
+ if(levels_by_z.len < LD.level_z)
+ levels_by_z.len = max(levels_by_z.len, LD.level_z)
+ PRINT_STACK_TRACE("Attempting to initialize a z-level([LD.level_z]) that has not incremented world.maxz.")
+
+ //Assign level z
+ var/datum/level_data/old_level = levels_by_z[LD.level_z]
+ levels_by_z[LD.level_z] = LD
+
+ if(old_level)
+ // Swap out the old one but preserve any relevant references etc.
+ old_level.replace_with(LD)
+ QDEL_NULL(old_level)
+
+ //Setup ID ref
+ if(isnull(LD.level_id))
+ PRINT_STACK_TRACE("Null level_id specified for z[LD.level_z].")
+ else if(LD.level_id in levels_by_id)
+ PRINT_STACK_TRACE("Duplicate level_id '[LD.level_id]' for z[LD.level_z].")
+ else
+ levels_by_id[LD.level_id] = LD
+
+ //Always add base turf for Z. It'll get replaced as needed.
+ base_turf_by_z[LD.level_z] = LD.base_turf || world.turf
+
+ //Add to level flags lookup lists
+ if(LD.level_flags & ZLEVEL_STATION)
+ station_levels |= LD.level_z
+ if(LD.level_flags & ZLEVEL_ADMIN)
+ admin_levels |= LD.level_z
+ if(LD.level_flags & ZLEVEL_CONTACT)
+ contact_levels |= LD.level_z
+ if(LD.level_flags & ZLEVEL_PLAYER)
+ player_levels |= LD.level_z
+ if(LD.level_flags & ZLEVEL_SEALED)
+ sealed_levels |= LD.level_z
+ return TRUE
+
+/datum/controller/subsystem/mapping/proc/unregister_level_data(var/datum/level_data/LD)
+ if(levels_by_z[LD.level_z] == LD)
+ //Clear the level data ref from the list if we're in it.
+ levels_by_z[LD.level_z] = null
+ levels_by_id -= LD.level_id
+
+ base_turf_by_z[LD.level_z] = world.turf
+ station_levels -= LD.level_z
+ admin_levels -= LD.level_z
+ contact_levels -= LD.level_z
+ player_levels -= LD.level_z
+ sealed_levels -= LD.level_z
+ return TRUE
\ No newline at end of file
diff --git a/code/controllers/subsystems/zcopy.dm b/code/controllers/subsystems/zcopy.dm
index fdadc76814b..058afaa1f3d 100644
--- a/code/controllers/subsystems/zcopy.dm
+++ b/code/controllers/subsystems/zcopy.dm
@@ -432,10 +432,11 @@ SUBSYSTEM_DEF(zcopy)
qo_idex = 1
/datum/controller/subsystem/zcopy/proc/flush_z_state(turf/T)
- if (T.below.mimic_above_copy)
- QDEL_NULL(T.below.mimic_above_copy)
- if (T.below.mimic_proxy)
- QDEL_NULL(T.below.mimic_proxy)
+ if(T.below)
+ if (T.below.mimic_above_copy)
+ QDEL_NULL(T.below.mimic_above_copy)
+ if (T.below.mimic_proxy)
+ QDEL_NULL(T.below.mimic_proxy)
for (var/atom/movable/openspace/OO in T)
if (istype(OO, /atom/movable/openspace/mimic))
qdel(OO)
diff --git a/code/datums/trading/traders/ai.dm b/code/datums/trading/traders/ai.dm
index b14cc79939f..a698401b6ed 100644
--- a/code/datums/trading/traders/ai.dm
+++ b/code/datums/trading/traders/ai.dm
@@ -75,48 +75,49 @@ They sell generic supplies and ask for generic supplies.
origin = "Mining Beacon"
possible_trading_items = list(
- /obj/item/stack/material/ore = TRADER_SUBTYPES_ONLY,
- /obj/item/stack/material/pane/mapped/glass = TRADER_ALL,
- /obj/item/stack/material/pane/mapped/glass/fifty = TRADER_BLACKLIST,
- /obj/item/stack/material/ingot/mapped/iron = TRADER_THIS_TYPE,
- /obj/item/stack/material/brick/mapped/sandstone = TRADER_THIS_TYPE,
- /obj/item/stack/material/brick/mapped/marble = TRADER_THIS_TYPE,
- /obj/item/stack/material/gemstone/mapped/diamond = TRADER_THIS_TYPE,
- /obj/item/stack/material/puck/mapped/uranium = TRADER_THIS_TYPE,
- /obj/item/stack/material/panel/mapped/plastic = TRADER_THIS_TYPE,
- /obj/item/stack/material/ingot/mapped/gold = TRADER_THIS_TYPE,
- /obj/item/stack/material/ingot/mapped/silver = TRADER_THIS_TYPE,
- /obj/item/stack/material/ingot/mapped/platinum = TRADER_THIS_TYPE,
- /obj/item/stack/material/segment/mapped/mhydrogen = TRADER_THIS_TYPE,
- /obj/item/stack/material/aerogel/mapped/tritium = TRADER_THIS_TYPE,
- /obj/item/stack/material/ingot/mapped/osmium = TRADER_THIS_TYPE,
- /obj/item/stack/material/sheet/mapped/steel = TRADER_THIS_TYPE,
+ /obj/item/stack/material/ore = TRADER_SUBTYPES_ONLY,
+ /obj/item/stack/material/pane/mapped/glass = TRADER_ALL,
+ /obj/item/stack/material/pane/mapped/glass/fifty = TRADER_BLACKLIST,
+ /obj/item/stack/material/ingot/mapped/iron = TRADER_THIS_TYPE,
+ /obj/item/stack/material/brick/mapped/sandstone = TRADER_THIS_TYPE,
+ /obj/item/stack/material/brick/mapped/marble = TRADER_THIS_TYPE,
+ /obj/item/stack/material/gemstone/mapped/diamond = TRADER_THIS_TYPE,
+ /obj/item/stack/material/puck/mapped/uranium = TRADER_THIS_TYPE,
+ /obj/item/stack/material/panel/mapped/plastic = TRADER_THIS_TYPE,
+ /obj/item/stack/material/ingot/mapped/gold = TRADER_THIS_TYPE,
+ /obj/item/stack/material/ingot/mapped/silver = TRADER_THIS_TYPE,
+ /obj/item/stack/material/ingot/mapped/platinum = TRADER_THIS_TYPE,
+ /obj/item/stack/material/segment/mapped/mhydrogen = TRADER_THIS_TYPE,
+ /obj/item/stack/material/aerogel/mapped/tritium = TRADER_THIS_TYPE,
+ /obj/item/stack/material/ingot/mapped/osmium = TRADER_THIS_TYPE,
+ /obj/item/stack/material/sheet/mapped/steel = TRADER_THIS_TYPE,
/obj/item/stack/material/reinforced/mapped/plasteel = TRADER_THIS_TYPE,
- /obj/machinery/mining = TRADER_SUBTYPES_ONLY
+ /obj/machinery/mining = TRADER_SUBTYPES_ONLY
)
/datum/trader/trading_beacon/manufacturing
origin = "Manifacturing Beacon"
- possible_trading_items = list(/obj/structure/aicore = TRADER_THIS_TYPE,
- /obj/structure/girder = TRADER_THIS_TYPE,
- /obj/structure/grille = TRADER_THIS_TYPE,
- /obj/structure/mopbucket = TRADER_THIS_TYPE,
- /obj/structure/ore_box = TRADER_THIS_TYPE,
- /obj/structure/coatrack = TRADER_THIS_TYPE,
- /obj/structure/bookcase = TRADER_THIS_TYPE,
- /obj/item/bee_pack = TRADER_THIS_TYPE,
- /obj/item/bee_smoker = TRADER_THIS_TYPE,
- /obj/item/beehive_assembly = TRADER_THIS_TYPE,
- /obj/item/glass_jar = TRADER_THIS_TYPE,
- /obj/item/honey_frame = TRADER_THIS_TYPE,
- /obj/item/target = TRADER_ALL,
- /obj/structure/tank_rack = TRADER_SUBTYPES_ONLY,
- /obj/structure/filing_cabinet = TRADER_THIS_TYPE,
- /obj/structure/safe = TRADER_THIS_TYPE,
- /obj/structure/plushie = TRADER_SUBTYPES_ONLY,
- /obj/structure/sign = TRADER_SUBTYPES_ONLY,
- /obj/structure/sign/double = TRADER_BLACKLIST_ALL,
- /obj/structure/sign/goldenplaque = TRADER_BLACKLIST_ALL,
- /obj/structure/sign/poster = TRADER_BLACKLIST
- )
\ No newline at end of file
+ possible_trading_items = list(
+ /obj/structure/aicore = TRADER_THIS_TYPE,
+ /obj/structure/girder = TRADER_THIS_TYPE,
+ /obj/structure/grille = TRADER_THIS_TYPE,
+ /obj/structure/mopbucket = TRADER_THIS_TYPE,
+ /obj/structure/ore_box = TRADER_THIS_TYPE,
+ /obj/structure/coatrack = TRADER_THIS_TYPE,
+ /obj/structure/bookcase = TRADER_THIS_TYPE,
+ /obj/item/bee_pack = TRADER_THIS_TYPE,
+ /obj/item/bee_smoker = TRADER_THIS_TYPE,
+ /obj/item/beehive_assembly = TRADER_THIS_TYPE,
+ /obj/item/glass_jar = TRADER_THIS_TYPE,
+ /obj/item/honey_frame = TRADER_THIS_TYPE,
+ /obj/item/target = TRADER_ALL,
+ /obj/structure/tank_rack = TRADER_SUBTYPES_ONLY,
+ /obj/structure/filing_cabinet = TRADER_THIS_TYPE,
+ /obj/structure/safe = TRADER_THIS_TYPE,
+ /obj/structure/plushie = TRADER_SUBTYPES_ONLY,
+ /obj/structure/sign = TRADER_SUBTYPES_ONLY,
+ /obj/structure/sign/double = TRADER_BLACKLIST_ALL,
+ /obj/structure/sign/goldenplaque = TRADER_BLACKLIST_ALL,
+ /obj/structure/sign/poster = TRADER_BLACKLIST
+ )
\ No newline at end of file
diff --git a/code/datums/trading/traders/books.dm b/code/datums/trading/traders/books.dm
index 37868196b8a..5bc123f0fa1 100644
--- a/code/datums/trading/traders/books.dm
+++ b/code/datums/trading/traders/books.dm
@@ -6,27 +6,29 @@
possible_wanted_items = list()
price_rng = 30
- possible_trading_items = list(/obj/item/book/skill/organizational/literacy = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/organizational/finance = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/general/eva = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/general/mech = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/general/pilot = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/general/hauling = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/general/computer = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/service/botany = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/service/cooking = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/security/combat = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/security/weapons = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/security/forensics = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/engineering/construction = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/engineering/electrical = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/engineering/atmos = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/engineering/engines = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/research/devices = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/research/science = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/medical/chemistry = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/medical/medicine = TRADER_SUBTYPES_ONLY,
- /obj/item/book/skill/medical/anatomy = TRADER_SUBTYPES_ONLY)
+ possible_trading_items = list(
+ /obj/item/book/skill/organizational/literacy = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/organizational/finance = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/general/eva = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/general/mech = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/general/pilot = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/general/hauling = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/general/computer = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/service/botany = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/service/cooking = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/security/combat = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/security/weapons = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/security/forensics = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/engineering/construction = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/engineering/electrical = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/engineering/atmos = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/engineering/engines = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/research/devices = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/research/science = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/medical/chemistry = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/medical/medicine = TRADER_SUBTYPES_ONLY,
+ /obj/item/book/skill/medical/anatomy = TRADER_SUBTYPES_ONLY
+ )
speech = list("hail_generic" = "Yes hello hello! Many fine paperstacks for sale! Please buy!",
"hail_deny" = "Not in! I'm not here! Go away!!",
diff --git a/code/datums/trading/traders/food.dm b/code/datums/trading/traders/food.dm
index 49fa1e9b218..6325df8a7f4 100644
--- a/code/datums/trading/traders/food.dm
+++ b/code/datums/trading/traders/food.dm
@@ -5,7 +5,7 @@
possible_origins = list("Papa Joe's", "Pizza Ship", "Dominator Pizza", "Little Kaezars", "Pizza Planet", "Cheese Louise", "Little Taste o' Neo-Italy", "Pizza Gestapo")
trade_flags = TRADER_MONEY
possible_wanted_items = list() //They are a pizza shop, not a bargainer.
- possible_trading_items = list(/obj/item/chems/food/sliceable/pizza = TRADER_SUBTYPES_ONLY)
+ possible_trading_items = list(/obj/item/chems/food/sliceable/pizza = TRADER_SUBTYPES_ONLY)
speech = list("hail_generic" = "Hello! Welcome to ORIGIN, may I take your order?",
"hail_deny" = "Beeeep... I'm sorry, your connection has been severed.",
@@ -40,14 +40,15 @@
possible_origins = list("888 Shanghai Kitchen", "Mr. Lee's Greater Hong Kong", "The House of the Venerable and Inscrutable Colonel", "Lucky Dragon")
trade_flags = TRADER_MONEY
possible_wanted_items = list()
- possible_trading_items = list(/obj/item/chems/food/meatkabob = TRADER_THIS_TYPE,
- /obj/item/chems/food/monkeysdelight = TRADER_THIS_TYPE,
- /obj/item/chems/food/ricepudding = TRADER_THIS_TYPE,
- /obj/item/chems/food/slice/xenomeatbread/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/soydope = TRADER_THIS_TYPE,
- /obj/item/chems/food/stewedsoymeat = TRADER_THIS_TYPE,
- /obj/item/chems/drinks/dry_ramen = TRADER_THIS_TYPE
- )
+ possible_trading_items = list(
+ /obj/item/chems/food/meatkabob = TRADER_THIS_TYPE,
+ /obj/item/chems/food/monkeysdelight = TRADER_THIS_TYPE,
+ /obj/item/chems/food/ricepudding = TRADER_THIS_TYPE,
+ /obj/item/chems/food/slice/xenomeatbread/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/soydope = TRADER_THIS_TYPE,
+ /obj/item/chems/food/stewedsoymeat = TRADER_THIS_TYPE,
+ /obj/item/chems/drinks/dry_ramen = TRADER_THIS_TYPE
+ )
var/list/fortunes = list("Today it's up to you to create the peacefulness you long for.",
"If you refuse to accept anything but the best, you very often get it.",
@@ -92,19 +93,20 @@
possible_origins = list("HyTee", "Kreugars", "Spaceway", "Privaxs", "FutureValue", "Phyvendyme", "Seller's Market")
trade_flags = TRADER_MONEY
- possible_trading_items = list(/obj/item/chems/food = TRADER_SUBTYPES_ONLY,
- /obj/item/chems/drinks/cans = TRADER_SUBTYPES_ONLY,
- /obj/item/chems/drinks/bottle = TRADER_SUBTYPES_ONLY,
- /obj/item/chems/drinks/bottle/small = TRADER_BLACKLIST,
- /obj/item/chems/food/checker = TRADER_BLACKLIST_ALL,
- /obj/item/chems/food/fruit_slice = TRADER_BLACKLIST,
- /obj/item/chems/food/slice = TRADER_BLACKLIST_ALL,
- /obj/item/chems/food/grown = TRADER_BLACKLIST_ALL,
- /obj/item/chems/food/human = TRADER_BLACKLIST_ALL,
- /obj/item/chems/food/sliceable/braincake = TRADER_BLACKLIST,
- /obj/item/chems/food/meat/human = TRADER_BLACKLIST,
- /obj/item/chems/food/variable = TRADER_BLACKLIST_ALL
- )
+ possible_trading_items = list(
+ /obj/item/chems/food = TRADER_SUBTYPES_ONLY,
+ /obj/item/chems/drinks/cans = TRADER_SUBTYPES_ONLY,
+ /obj/item/chems/drinks/bottle = TRADER_SUBTYPES_ONLY,
+ /obj/item/chems/drinks/bottle/small = TRADER_BLACKLIST,
+ /obj/item/chems/food/checker = TRADER_BLACKLIST_ALL,
+ /obj/item/chems/food/fruit_slice = TRADER_BLACKLIST,
+ /obj/item/chems/food/slice = TRADER_BLACKLIST_ALL,
+ /obj/item/chems/food/grown = TRADER_BLACKLIST_ALL,
+ /obj/item/chems/food/human = TRADER_BLACKLIST_ALL,
+ /obj/item/chems/food/sliceable/braincake = TRADER_BLACKLIST,
+ /obj/item/chems/food/meat/human = TRADER_BLACKLIST,
+ /obj/item/chems/food/variable = TRADER_BLACKLIST_ALL
+ )
speech = list("hail_generic" = "Hello, welcome to ORIGIN, grocery store of the future!",
"hail_deny" = "I'm sorry, we've blacklisted your communications due to rude behavior.",
@@ -145,20 +147,22 @@
"bribe_refusal" = "Oh ho ho! I'd never think of taking ORIGIN on the road!",
)
- possible_trading_items = list(/obj/item/chems/food/slice/birthdaycake/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/slice/carrotcake/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/slice/cheesecake/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/slice/chocolatecake/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/slice/lemoncake/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/slice/limecake/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/slice/orangecake/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/slice/plaincake/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/slice/pumpkinpie/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/slice/bananabread/filled = TRADER_THIS_TYPE,
- /obj/item/chems/food/sliceable = TRADER_SUBTYPES_ONLY,
- /obj/item/chems/food/sliceable/pizza = TRADER_BLACKLIST_ALL,
- /obj/item/chems/food/sliceable/xenomeatbread = TRADER_BLACKLIST,
- /obj/item/chems/food/sliceable/flatdough = TRADER_BLACKLIST,
- /obj/item/chems/food/sliceable/braincake = TRADER_BLACKLIST,
- /obj/item/chems/food/pie = TRADER_THIS_TYPE,
- /obj/item/chems/food/applepie = TRADER_THIS_TYPE)
\ No newline at end of file
+ possible_trading_items = list(
+ /obj/item/chems/food/slice/birthdaycake/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/slice/carrotcake/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/slice/cheesecake/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/slice/chocolatecake/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/slice/lemoncake/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/slice/limecake/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/slice/orangecake/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/slice/plaincake/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/slice/pumpkinpie/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/slice/bananabread/filled = TRADER_THIS_TYPE,
+ /obj/item/chems/food/sliceable = TRADER_SUBTYPES_ONLY,
+ /obj/item/chems/food/sliceable/pizza = TRADER_BLACKLIST_ALL,
+ /obj/item/chems/food/sliceable/xenomeatbread = TRADER_BLACKLIST,
+ /obj/item/chems/food/sliceable/flatdough = TRADER_BLACKLIST,
+ /obj/item/chems/food/sliceable/braincake = TRADER_BLACKLIST,
+ /obj/item/chems/food/pie = TRADER_THIS_TYPE,
+ /obj/item/chems/food/applepie = TRADER_THIS_TYPE
+ )
\ No newline at end of file
diff --git a/code/datums/trading/traders/goods.dm b/code/datums/trading/traders/goods.dm
index bc35fc9aece..4a10c72202e 100644
--- a/code/datums/trading/traders/goods.dm
+++ b/code/datums/trading/traders/goods.dm
@@ -71,24 +71,26 @@
"bribe_accept" = "Why not! Glad to be here for a few more minutes.",
)
- possible_trading_items = list(/obj/item/stock_parts/computer/battery_module = TRADER_SUBTYPES_ONLY,
- /obj/item/stock_parts/circuitboard = TRADER_SUBTYPES_ONLY,
- /obj/item/stock_parts/circuitboard/telecomms = TRADER_BLACKLIST,
- /obj/item/stock_parts/circuitboard/unary_atmos = TRADER_BLACKLIST,
- /obj/item/stock_parts/circuitboard/arcade = TRADER_BLACKLIST,
- /obj/item/stock_parts/circuitboard/broken = TRADER_BLACKLIST,
- /obj/item/stack/cable_coil = TRADER_SUBTYPES_ONLY,
- /obj/item/stack/cable_coil/cyborg = TRADER_BLACKLIST,
- /obj/item/stack/cable_coil/random = TRADER_BLACKLIST,
- /obj/item/stack/cable_coil/cut = TRADER_BLACKLIST,
- /obj/item/stock_parts/circuitboard/air_alarm = TRADER_THIS_TYPE,
- /obj/item/stock_parts/circuitboard/airlock_electronics = TRADER_ALL,
- /obj/item/cell = TRADER_THIS_TYPE,
- /obj/item/cell/crap = TRADER_THIS_TYPE,
- /obj/item/cell/high = TRADER_THIS_TYPE,
- /obj/item/cell/super = TRADER_THIS_TYPE,
- /obj/item/cell/hyper = TRADER_THIS_TYPE,
- /obj/item/tracker_electronics = TRADER_THIS_TYPE)
+ possible_trading_items = list(
+ /obj/item/stock_parts/computer/battery_module = TRADER_SUBTYPES_ONLY,
+ /obj/item/stock_parts/circuitboard = TRADER_SUBTYPES_ONLY,
+ /obj/item/stock_parts/circuitboard/telecomms = TRADER_BLACKLIST,
+ /obj/item/stock_parts/circuitboard/unary_atmos = TRADER_BLACKLIST,
+ /obj/item/stock_parts/circuitboard/arcade = TRADER_BLACKLIST,
+ /obj/item/stock_parts/circuitboard/broken = TRADER_BLACKLIST,
+ /obj/item/stack/cable_coil = TRADER_SUBTYPES_ONLY,
+ /obj/item/stack/cable_coil/cyborg = TRADER_BLACKLIST,
+ /obj/item/stack/cable_coil/random = TRADER_BLACKLIST,
+ /obj/item/stack/cable_coil/cut = TRADER_BLACKLIST,
+ /obj/item/stock_parts/circuitboard/air_alarm = TRADER_THIS_TYPE,
+ /obj/item/stock_parts/circuitboard/airlock_electronics = TRADER_ALL,
+ /obj/item/cell = TRADER_THIS_TYPE,
+ /obj/item/cell/crap = TRADER_THIS_TYPE,
+ /obj/item/cell/high = TRADER_THIS_TYPE,
+ /obj/item/cell/super = TRADER_THIS_TYPE,
+ /obj/item/cell/hyper = TRADER_THIS_TYPE,
+ /obj/item/tracker_electronics = TRADER_THIS_TYPE
+ )
/* Clothing stores: each a different type. A hat/glove store, a shoe store, and a jumpsuit store. */
@@ -117,60 +119,66 @@
"bribe_accept" = "Hm.... sure! We'll have a few minutes of 'engine troubles'.",
)
- possible_trading_items = list(/obj/item/clothing/under = TRADER_SUBTYPES_ONLY,
- /obj/item/clothing/under/chameleon = TRADER_BLACKLIST,
- /obj/item/clothing/under/color = TRADER_BLACKLIST,
- /obj/item/clothing/under/dress = TRADER_BLACKLIST,
- /obj/item/clothing/under/gimmick = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/under/lawyer = TRADER_BLACKLIST,
- /obj/item/clothing/under/pj = TRADER_BLACKLIST,
- /obj/item/clothing/under = TRADER_BLACKLIST,
- /obj/item/clothing/pants/shorts = TRADER_BLACKLIST,
- /obj/item/clothing/under/mankini = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/under/syndicate = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/under/tactical = TRADER_BLACKLIST,
- /obj/item/clothing/under/waiter/monke = TRADER_BLACKLIST,
- /obj/item/clothing/under/wedding = TRADER_BLACKLIST,
- /obj/item/clothing/pants/casual/mustangjeans/monke = TRADER_BLACKLIST)
+ possible_trading_items = list(
+ /obj/item/clothing/under = TRADER_SUBTYPES_ONLY,
+ /obj/item/clothing/under/chameleon = TRADER_BLACKLIST,
+ /obj/item/clothing/under/color = TRADER_BLACKLIST,
+ /obj/item/clothing/under/dress = TRADER_BLACKLIST,
+ /obj/item/clothing/under/gimmick = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/under/lawyer = TRADER_BLACKLIST,
+ /obj/item/clothing/under/pj = TRADER_BLACKLIST,
+ /obj/item/clothing/under = TRADER_BLACKLIST,
+ /obj/item/clothing/pants/shorts = TRADER_BLACKLIST,
+ /obj/item/clothing/under/mankini = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/under/syndicate = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/under/tactical = TRADER_BLACKLIST,
+ /obj/item/clothing/under/waiter/monke = TRADER_BLACKLIST,
+ /obj/item/clothing/under/wedding = TRADER_BLACKLIST,
+ /obj/item/clothing/pants/casual/mustangjeans/monke = TRADER_BLACKLIST
+ )
/datum/trader/ship/clothingshop/shoes
possible_origins = list("Foot Safe", "Paysmall", "Popular Footwear", "Grimbly's Shoes", "Right Steps")
- possible_trading_items = list(/obj/item/clothing/shoes = TRADER_SUBTYPES_ONLY,
- /obj/item/clothing/shoes/chameleon = TRADER_BLACKLIST,
- /obj/item/clothing/shoes/jackboots/swat/combat = TRADER_BLACKLIST,
- /obj/item/clothing/shoes/clown_shoes = TRADER_BLACKLIST,
- /obj/item/clothing/shoes/cult = TRADER_BLACKLIST,
- /obj/item/clothing/shoes/lightrig = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/shoes/magboots = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/shoes/jackboots/swat = TRADER_BLACKLIST,
- /obj/item/clothing/shoes/syndigaloshes = TRADER_BLACKLIST)
+ possible_trading_items = list(
+ /obj/item/clothing/shoes = TRADER_SUBTYPES_ONLY,
+ /obj/item/clothing/shoes/chameleon = TRADER_BLACKLIST,
+ /obj/item/clothing/shoes/jackboots/swat/combat = TRADER_BLACKLIST,
+ /obj/item/clothing/shoes/clown_shoes = TRADER_BLACKLIST,
+ /obj/item/clothing/shoes/cult = TRADER_BLACKLIST,
+ /obj/item/clothing/shoes/lightrig = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/shoes/magboots = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/shoes/jackboots/swat = TRADER_BLACKLIST,
+ /obj/item/clothing/shoes/syndigaloshes = TRADER_BLACKLIST
+ )
/datum/trader/ship/clothingshop/hatglovesaccessories
possible_origins = list("Baldie's Hats and Accessories", "The Right Fit", "Like a Glove", "Space Fashion")
- possible_trading_items = list(/obj/item/clothing/accessory = TRADER_ALL,
- /obj/item/clothing/accessory/badge = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/accessory/storage/holster = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/accessory/medal = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/accessory/storage = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/gloves = TRADER_SUBTYPES_ONLY,
- /obj/item/clothing/gloves/lightrig = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/gloves/rig = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/gloves/thick/swat = TRADER_BLACKLIST,
- /obj/item/clothing/gloves/chameleon = TRADER_BLACKLIST,
- /obj/item/clothing/head = TRADER_SUBTYPES_ONLY,
- /obj/item/clothing/head/HoS = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/head/bio_hood = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/head/bomb_hood = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/head/caphat = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/head/centhat = TRADER_BLACKLIST,
- /obj/item/clothing/head/chameleon = TRADER_BLACKLIST,
- /obj/item/clothing/head/collectable = TRADER_BLACKLIST,
- /obj/item/clothing/head/culthood = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/head/helmet = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/head/lightrig = TRADER_BLACKLIST_ALL,
- /obj/item/clothing/head/radiation = TRADER_BLACKLIST,
- /obj/item/clothing/head/warden = TRADER_BLACKLIST,
- /obj/item/clothing/head/welding = TRADER_BLACKLIST)
+ possible_trading_items = list(
+ /obj/item/clothing/accessory = TRADER_ALL,
+ /obj/item/clothing/accessory/badge = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/accessory/storage/holster = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/accessory/medal = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/accessory/storage = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/gloves = TRADER_SUBTYPES_ONLY,
+ /obj/item/clothing/gloves/lightrig = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/gloves/rig = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/gloves/thick/swat = TRADER_BLACKLIST,
+ /obj/item/clothing/gloves/chameleon = TRADER_BLACKLIST,
+ /obj/item/clothing/head = TRADER_SUBTYPES_ONLY,
+ /obj/item/clothing/head/HoS = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/head/bio_hood = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/head/bomb_hood = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/head/caphat = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/head/centhat = TRADER_BLACKLIST,
+ /obj/item/clothing/head/chameleon = TRADER_BLACKLIST,
+ /obj/item/clothing/head/collectable = TRADER_BLACKLIST,
+ /obj/item/clothing/head/culthood = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/head/helmet = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/head/lightrig = TRADER_BLACKLIST_ALL,
+ /obj/item/clothing/head/radiation = TRADER_BLACKLIST,
+ /obj/item/clothing/head/warden = TRADER_BLACKLIST,
+ /obj/item/clothing/head/welding = TRADER_BLACKLIST
+ )
@@ -182,43 +190,45 @@ Sells devices, odds and ends, and medical stuff
name_language = TRADER_DEFAULT_NAME
origin = "Drugstore"
possible_origins = list("Buy 'n Save", "Drug Carnival", "C&B", "Fentles", "Dr. Goods", "Beevees", "McGillicuddy's")
- possible_trading_items = list(/obj/item/flashlight = TRADER_ALL,
- /obj/item/kit/paint = TRADER_SUBTYPES_ONLY,
- /obj/item/aicard = TRADER_THIS_TYPE,
- /obj/item/binoculars = TRADER_THIS_TYPE,
- /obj/item/cable_painter = TRADER_THIS_TYPE,
- /obj/item/flash = TRADER_THIS_TYPE,
- /obj/item/paint_sprayer = TRADER_THIS_TYPE,
- /obj/item/multitool = TRADER_THIS_TYPE,
- /obj/item/lightreplacer = TRADER_THIS_TYPE,
- /obj/item/megaphone = TRADER_THIS_TYPE,
- /obj/item/paicard = TRADER_THIS_TYPE,
- /obj/item/scanner/health = TRADER_THIS_TYPE,
- /obj/item/scanner/breath = TRADER_THIS_TYPE,
- /obj/item/scanner/gas = TRADER_ALL,
- /obj/item/scanner/spectrometer = TRADER_ALL,
- /obj/item/scanner/reagent = TRADER_ALL,
- /obj/item/scanner/xenobio = TRADER_THIS_TYPE,
- /obj/item/suit_cooling_unit = TRADER_THIS_TYPE,
- /obj/item/t_scanner = TRADER_THIS_TYPE,
- /obj/item/taperecorder = TRADER_THIS_TYPE,
- /obj/item/batterer = TRADER_THIS_TYPE,
- /obj/item/synthesized_instrument/violin = TRADER_THIS_TYPE,
- /obj/item/hailer = TRADER_THIS_TYPE,
- /obj/item/uv_light = TRADER_THIS_TYPE,
- /obj/item/mmi = TRADER_ALL,
- /obj/item/robotanalyzer = TRADER_THIS_TYPE,
- /obj/item/chems/toner_cartridge = TRADER_THIS_TYPE,
- /obj/item/camera_film = TRADER_THIS_TYPE,
- /obj/item/camera = TRADER_THIS_TYPE,
- /obj/item/destTagger = TRADER_THIS_TYPE,
- /obj/item/gps = TRADER_THIS_TYPE,
- /obj/item/measuring_tape = TRADER_THIS_TYPE,
- /obj/item/ano_scanner = TRADER_THIS_TYPE,
- /obj/item/core_sampler = TRADER_THIS_TYPE,
- /obj/item/depth_scanner = TRADER_THIS_TYPE,
- /obj/item/pinpointer/radio = TRADER_THIS_TYPE,
- /obj/item/stack/medical/advanced = TRADER_BLACKLIST)
+ possible_trading_items = list(
+ /obj/item/flashlight = TRADER_ALL,
+ /obj/item/kit/paint = TRADER_SUBTYPES_ONLY,
+ /obj/item/aicard = TRADER_THIS_TYPE,
+ /obj/item/binoculars = TRADER_THIS_TYPE,
+ /obj/item/cable_painter = TRADER_THIS_TYPE,
+ /obj/item/flash = TRADER_THIS_TYPE,
+ /obj/item/paint_sprayer = TRADER_THIS_TYPE,
+ /obj/item/multitool = TRADER_THIS_TYPE,
+ /obj/item/lightreplacer = TRADER_THIS_TYPE,
+ /obj/item/megaphone = TRADER_THIS_TYPE,
+ /obj/item/paicard = TRADER_THIS_TYPE,
+ /obj/item/scanner/health = TRADER_THIS_TYPE,
+ /obj/item/scanner/breath = TRADER_THIS_TYPE,
+ /obj/item/scanner/gas = TRADER_ALL,
+ /obj/item/scanner/spectrometer = TRADER_ALL,
+ /obj/item/scanner/reagent = TRADER_ALL,
+ /obj/item/scanner/xenobio = TRADER_THIS_TYPE,
+ /obj/item/suit_cooling_unit = TRADER_THIS_TYPE,
+ /obj/item/t_scanner = TRADER_THIS_TYPE,
+ /obj/item/taperecorder = TRADER_THIS_TYPE,
+ /obj/item/batterer = TRADER_THIS_TYPE,
+ /obj/item/synthesized_instrument/violin = TRADER_THIS_TYPE,
+ /obj/item/hailer = TRADER_THIS_TYPE,
+ /obj/item/uv_light = TRADER_THIS_TYPE,
+ /obj/item/mmi = TRADER_ALL,
+ /obj/item/robotanalyzer = TRADER_THIS_TYPE,
+ /obj/item/chems/toner_cartridge = TRADER_THIS_TYPE,
+ /obj/item/camera_film = TRADER_THIS_TYPE,
+ /obj/item/camera = TRADER_THIS_TYPE,
+ /obj/item/destTagger = TRADER_THIS_TYPE,
+ /obj/item/gps = TRADER_THIS_TYPE,
+ /obj/item/measuring_tape = TRADER_THIS_TYPE,
+ /obj/item/ano_scanner = TRADER_THIS_TYPE,
+ /obj/item/core_sampler = TRADER_THIS_TYPE,
+ /obj/item/depth_scanner = TRADER_THIS_TYPE,
+ /obj/item/pinpointer/radio = TRADER_THIS_TYPE,
+ /obj/item/stack/medical/advanced = TRADER_BLACKLIST
+ )
speech = list("hail_generic" = "Hello, hello! Bits and bobs and everything in between, I hope you find what you're looking for!",
"hail_silicon" = "Ah! Hello, robot. We only sell things that, ah.... people can hold in their hands, unfortunately. You are still allowed to buy, though!",
"hail_deny" = "Oh no. I don't want to deal with YOU.",
@@ -243,10 +253,11 @@ Sells devices, odds and ends, and medical stuff
origin = "Robot Store"
possible_origins = list("AI for the Straight Guy", "Mechanical Buddies", "Bot Chop Shop", "Omni Consumer Projects")
possible_trading_items = list(
- /obj/item/bot_kit = TRADER_THIS_TYPE,
- /obj/item/paicard = TRADER_THIS_TYPE,
- /obj/item/aicard = TRADER_THIS_TYPE,
- /mob/living/bot = TRADER_SUBTYPES_ONLY)
+ /obj/item/bot_kit = TRADER_THIS_TYPE,
+ /obj/item/paicard = TRADER_THIS_TYPE,
+ /obj/item/aicard = TRADER_THIS_TYPE,
+ /mob/living/bot = TRADER_SUBTYPES_ONLY
+ )
speech = list("hail_generic" = "Welcome to ORIGIN! Let me walk you through our fine robotic selection!",
"hail_silicon" = "Welcome to ORIGIN! Let- oh, you're a synth! Well, your money is good anyway. Welcome, welcome!",
"hail_deny" = "ORIGIN no longer wants to speak to you.",
@@ -287,18 +298,21 @@ Sells devices, odds and ends, and medical stuff
"insult_bad" = "I have traded dogs with more bark than that.",
)
- possible_wanted_items = list(/mob/living/simple_animal/tindalos = TRADER_THIS_TYPE,
- /mob/living/simple_animal/tomato = TRADER_THIS_TYPE,
- /mob/living/simple_animal/yithian = TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/beast/shantak= TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/beast/samak= TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE)
-
- possible_trading_items = list(/mob/living/simple_animal/hostile/carp= TRADER_THIS_TYPE,
- /obj/item/dociler = TRADER_THIS_TYPE,
- /obj/item/beartrap = TRADER_THIS_TYPE,
- /obj/item/scanner/xenobio = TRADER_THIS_TYPE)
+ possible_wanted_items = list(
+ /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/tomato = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/yithian = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/beast/shantak = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/beast/samak = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE
+ )
+ possible_trading_items = list(
+ /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE,
+ /obj/item/dociler = TRADER_THIS_TYPE,
+ /obj/item/beartrap = TRADER_THIS_TYPE,
+ /obj/item/scanner/xenobio = TRADER_THIS_TYPE
+ )
/datum/trader/medical
name = "Medical Supplier"
@@ -323,35 +337,37 @@ Sells devices, odds and ends, and medical stuff
"insult_bad" = "*muffled laughter* Sorry, was that you trying to talk shit? Adorable.",
)
- possible_wanted_items = list(/obj/item/chems/drinks/bottle = TRADER_THIS_TYPE,
- /obj/item/organ/internal/liver = TRADER_THIS_TYPE,
- /obj/item/organ/internal/kidneys = TRADER_THIS_TYPE,
- /obj/item/organ/internal/lungs = TRADER_THIS_TYPE,
- /obj/item/organ/internal/heart = TRADER_THIS_TYPE,
- /obj/item/storage/fancy/cigarettes = TRADER_ALL
- )
-
- possible_trading_items = list(/obj/item/storage/pill_bottle = TRADER_SUBTYPES_ONLY,
- /obj/item/storage/firstaid/fire = TRADER_THIS_TYPE,
- /obj/item/storage/firstaid/toxin = TRADER_THIS_TYPE,
- /obj/item/storage/firstaid/adv = TRADER_THIS_TYPE,
- /obj/item/storage/box/bloodpacks = TRADER_THIS_TYPE,
- /obj/item/chems/ivbag = TRADER_SUBTYPES_ONLY,
- /obj/item/retractor = TRADER_THIS_TYPE,
- /obj/item/hemostat = TRADER_THIS_TYPE,
- /obj/item/cautery = TRADER_THIS_TYPE,
- /obj/item/surgicaldrill = TRADER_THIS_TYPE,
- /obj/item/scalpel = TRADER_THIS_TYPE,
- /obj/item/incision_manager = TRADER_THIS_TYPE,
- /obj/item/circular_saw = TRADER_THIS_TYPE,
- /obj/item/bonegel = TRADER_THIS_TYPE,
- /obj/item/bonesetter = TRADER_THIS_TYPE,
- /obj/item/chems/glass/bottle/stabilizer = TRADER_THIS_TYPE,
- /obj/item/chems/glass/bottle/sedatives = TRADER_THIS_TYPE,
- /obj/item/chems/glass/bottle/antitoxin = TRADER_THIS_TYPE,
- /obj/item/bodybag/cryobag = TRADER_THIS_TYPE,
- /obj/item/sign/medipolma = TRADER_THIS_TYPE
- )
+ possible_wanted_items = list(
+ /obj/item/chems/drinks/bottle = TRADER_THIS_TYPE,
+ /obj/item/organ/internal/liver = TRADER_THIS_TYPE,
+ /obj/item/organ/internal/kidneys = TRADER_THIS_TYPE,
+ /obj/item/organ/internal/lungs = TRADER_THIS_TYPE,
+ /obj/item/organ/internal/heart = TRADER_THIS_TYPE,
+ /obj/item/storage/fancy/cigarettes = TRADER_ALL
+ )
+
+ possible_trading_items = list(
+ /obj/item/storage/pill_bottle = TRADER_SUBTYPES_ONLY,
+ /obj/item/storage/firstaid/fire = TRADER_THIS_TYPE,
+ /obj/item/storage/firstaid/toxin = TRADER_THIS_TYPE,
+ /obj/item/storage/firstaid/adv = TRADER_THIS_TYPE,
+ /obj/item/storage/box/bloodpacks = TRADER_THIS_TYPE,
+ /obj/item/chems/ivbag = TRADER_SUBTYPES_ONLY,
+ /obj/item/retractor = TRADER_THIS_TYPE,
+ /obj/item/hemostat = TRADER_THIS_TYPE,
+ /obj/item/cautery = TRADER_THIS_TYPE,
+ /obj/item/surgicaldrill = TRADER_THIS_TYPE,
+ /obj/item/scalpel = TRADER_THIS_TYPE,
+ /obj/item/incision_manager = TRADER_THIS_TYPE,
+ /obj/item/circular_saw = TRADER_THIS_TYPE,
+ /obj/item/bonegel = TRADER_THIS_TYPE,
+ /obj/item/bonesetter = TRADER_THIS_TYPE,
+ /obj/item/chems/glass/bottle/stabilizer = TRADER_THIS_TYPE,
+ /obj/item/chems/glass/bottle/sedatives = TRADER_THIS_TYPE,
+ /obj/item/chems/glass/bottle/antitoxin = TRADER_THIS_TYPE,
+ /obj/item/bodybag/cryobag = TRADER_THIS_TYPE,
+ /obj/item/sign/medipolma = TRADER_THIS_TYPE
+ )
/datum/trader/mining
name = "Rock'n'Drill Mining Inc"
@@ -377,19 +393,19 @@ Sells devices, odds and ends, and medical stuff
)
possible_wanted_items = list(
- /obj/item/stack/material/ore = TRADER_SUBTYPES_ONLY,
- /obj/item/disk/survey = TRADER_THIS_TYPE,
- /obj/item/stack/material/ore/slag = TRADER_BLACKLIST
+ /obj/item/stack/material/ore = TRADER_SUBTYPES_ONLY,
+ /obj/item/disk/survey = TRADER_THIS_TYPE,
+ /obj/item/stack/material/ore/slag = TRADER_BLACKLIST
)
possible_trading_items = list(
- /obj/machinery/mining/drill = TRADER_THIS_TYPE,
- /obj/machinery/mining/brace = TRADER_THIS_TYPE,
- /obj/machinery/floodlight = TRADER_THIS_TYPE,
- /obj/item/storage/box/greenglowsticks = TRADER_THIS_TYPE,
+ /obj/machinery/mining/drill = TRADER_THIS_TYPE,
+ /obj/machinery/mining/brace = TRADER_THIS_TYPE,
+ /obj/machinery/floodlight = TRADER_THIS_TYPE,
+ /obj/item/storage/box/greenglowsticks = TRADER_THIS_TYPE,
/obj/item/clothing/suit/space/void/engineering/salvage/prepared = TRADER_THIS_TYPE,
- /obj/item/stack/material/puck/mapped/uranium/ten = TRADER_THIS_TYPE,
- /obj/item/stack/material/reinforced/mapped/plasteel/fifty = TRADER_THIS_TYPE,
- /obj/item/stack/material/sheet/mapped/steel/fifty = TRADER_THIS_TYPE,
- /obj/item/stack/material/ingot/mapped/copper/fifty = TRADER_THIS_TYPE
+ /obj/item/stack/material/puck/mapped/uranium/ten = TRADER_THIS_TYPE,
+ /obj/item/stack/material/reinforced/mapped/plasteel/fifty = TRADER_THIS_TYPE,
+ /obj/item/stack/material/sheet/mapped/steel/fifty = TRADER_THIS_TYPE,
+ /obj/item/stack/material/ingot/mapped/copper/fifty = TRADER_THIS_TYPE
)
diff --git a/code/datums/trading/traders/misc.dm b/code/datums/trading/traders/misc.dm
index e53ed1417c8..80b69e2dbb5 100644
--- a/code/datums/trading/traders/misc.dm
+++ b/code/datums/trading/traders/misc.dm
@@ -23,47 +23,51 @@
"bribe_accept" = "Hm. It'll be good for the animals, so sure.",
)
- possible_wanted_items = list(/mob/living/simple_animal/corgi = TRADER_THIS_TYPE,
- /mob/living/simple_animal/cat = TRADER_THIS_TYPE,
- /mob/living/simple_animal/crab = TRADER_THIS_TYPE,
- /mob/living/simple_animal/lizard = TRADER_THIS_TYPE,
- /mob/living/simple_animal/mouse = TRADER_THIS_TYPE,
- /mob/living/simple_animal/mushroom = TRADER_THIS_TYPE,
- /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE,
- /mob/living/simple_animal/tomato = TRADER_THIS_TYPE,
- /mob/living/simple_animal/cow = TRADER_THIS_TYPE,
- /mob/living/simple_animal/chick = TRADER_THIS_TYPE,
- /mob/living/simple_animal/chicken = TRADER_THIS_TYPE,
- /mob/living/simple_animal/yithian = TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/bear= TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/beast/shantak= TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/parrot = TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/beast/samak= TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/goat = TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE)
+ possible_wanted_items = list(
+ /mob/living/simple_animal/corgi = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/cat = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/crab = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/lizard = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/mouse = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/mushroom = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/tomato = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/cow = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/chick = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/chicken = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/yithian = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/bear = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/beast/shantak = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/parrot = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/beast/samak = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/goat = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE
+ )
- possible_trading_items = list(/mob/living/simple_animal/corgi = TRADER_THIS_TYPE,
- /mob/living/simple_animal/cat = TRADER_THIS_TYPE,
- /mob/living/simple_animal/crab = TRADER_THIS_TYPE,
- /mob/living/simple_animal/lizard = TRADER_THIS_TYPE,
- /mob/living/simple_animal/mouse = TRADER_THIS_TYPE,
- /mob/living/simple_animal/mushroom = TRADER_THIS_TYPE,
- /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE,
- /mob/living/simple_animal/tomato = TRADER_THIS_TYPE,
- /mob/living/simple_animal/cow = TRADER_THIS_TYPE,
- /mob/living/simple_animal/chick = TRADER_THIS_TYPE,
- /mob/living/simple_animal/chicken = TRADER_THIS_TYPE,
- /mob/living/simple_animal/yithian = TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/bear= TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/beast/shantak= TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/parrot = TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/beast/samak= TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/retaliate/goat = TRADER_THIS_TYPE,
- /mob/living/simple_animal/hostile/carp= TRADER_THIS_TYPE,
- /obj/item/dociler = TRADER_THIS_TYPE,
- /obj/structure/dogbed = TRADER_THIS_TYPE)
+ possible_trading_items = list(
+ /mob/living/simple_animal/corgi = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/cat = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/crab = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/lizard = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/mouse = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/mushroom = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/tomato = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/cow = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/chick = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/chicken = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/yithian = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/bear = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/beast/shantak = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/parrot = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/beast/samak = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/retaliate/goat = TRADER_THIS_TYPE,
+ /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE,
+ /obj/item/dociler = TRADER_THIS_TYPE,
+ /obj/structure/dogbed = TRADER_THIS_TYPE
+ )
/datum/trader/ship/prank_shop
name = "Prank Shop Owner"
@@ -89,21 +93,23 @@
"bribe_refusal" = "We are sorry, but we cannot accept.",
"bribe_accept" = "We are happy to say that we accept this bribe.",
)
- possible_trading_items = list(/obj/item/clothing/mask/gas/clown_hat = TRADER_THIS_TYPE,
- /obj/item/clothing/mask/gas/mime = TRADER_THIS_TYPE,
- /obj/item/clothing/shoes/clown_shoes = TRADER_THIS_TYPE,
- /obj/item/clothing/under/clown = TRADER_THIS_TYPE,
- /obj/item/stamp/clown = TRADER_THIS_TYPE,
- /obj/item/storage/backpack/clown = TRADER_THIS_TYPE,
- /obj/item/bananapeel = TRADER_THIS_TYPE,
- /obj/item/gun/launcher/money = TRADER_THIS_TYPE,
- /obj/item/chems/food/pie = TRADER_THIS_TYPE,
- /obj/item/bikehorn = TRADER_THIS_TYPE,
- /obj/item/chems/spray/waterflower = TRADER_THIS_TYPE,
- /obj/item/gun/launcher/pneumatic/small = TRADER_THIS_TYPE,
- /obj/item/gun/projectile/revolver/capgun = TRADER_THIS_TYPE,
- /obj/item/clothing/mask/fakemoustache = TRADER_THIS_TYPE,
- /obj/item/grenade/spawnergrenade/fake_carp = TRADER_THIS_TYPE)
+ possible_trading_items = list(
+ /obj/item/clothing/mask/gas/clown_hat = TRADER_THIS_TYPE,
+ /obj/item/clothing/mask/gas/mime = TRADER_THIS_TYPE,
+ /obj/item/clothing/shoes/clown_shoes = TRADER_THIS_TYPE,
+ /obj/item/clothing/under/clown = TRADER_THIS_TYPE,
+ /obj/item/stamp/clown = TRADER_THIS_TYPE,
+ /obj/item/storage/backpack/clown = TRADER_THIS_TYPE,
+ /obj/item/bananapeel = TRADER_THIS_TYPE,
+ /obj/item/gun/launcher/money = TRADER_THIS_TYPE,
+ /obj/item/chems/food/pie = TRADER_THIS_TYPE,
+ /obj/item/bikehorn = TRADER_THIS_TYPE,
+ /obj/item/chems/spray/waterflower = TRADER_THIS_TYPE,
+ /obj/item/gun/launcher/pneumatic/small = TRADER_THIS_TYPE,
+ /obj/item/gun/projectile/revolver/capgun = TRADER_THIS_TYPE,
+ /obj/item/clothing/mask/fakemoustache = TRADER_THIS_TYPE,
+ /obj/item/grenade/spawnergrenade/fake_carp = TRADER_THIS_TYPE
+ )
/datum/trader/ship/replica_shop
name = "Replica Store Owner"
@@ -127,27 +133,29 @@
"bribe_refusal" = "Alas, traveler - I could stay all eve, but I've an client in waiting, and they are not known for patience.",
"bribe_accept" = "Mayhaps I could set a spell longer, and rest my weary feet.",
)
- possible_trading_items = list(/obj/item/clothing/head/wizard/magus = TRADER_THIS_TYPE,
- /obj/item/shield/buckler = TRADER_THIS_TYPE,
- /obj/item/clothing/head/redcoat = TRADER_THIS_TYPE,
- /obj/item/clothing/head/powdered_wig = TRADER_THIS_TYPE,
- /obj/item/clothing/head/hasturhood = TRADER_THIS_TYPE,
- /obj/item/clothing/head/helmet/gladiator=TRADER_THIS_TYPE,
- /obj/item/clothing/head/plaguedoctorhat= TRADER_THIS_TYPE,
- /obj/item/clothing/glasses/eyepatch/monocle = TRADER_THIS_TYPE,
- /obj/item/clothing/mask/smokable/pipe = TRADER_THIS_TYPE,
- /obj/item/clothing/mask/gas/plaguedoctor=TRADER_THIS_TYPE,
- /obj/item/clothing/suit/hastur = TRADER_THIS_TYPE,
- /obj/item/clothing/suit/imperium_monk = TRADER_THIS_TYPE,
- /obj/item/clothing/suit/judgerobe = TRADER_THIS_TYPE,
- /obj/item/clothing/suit/wizrobe/magusred=TRADER_THIS_TYPE,
- /obj/item/clothing/suit/wizrobe/magusblue=TRADER_THIS_TYPE,
- /obj/item/clothing/under/gladiator = TRADER_THIS_TYPE,
- /obj/item/clothing/under/kilt = TRADER_THIS_TYPE,
- /obj/item/clothing/under/redcoat = TRADER_THIS_TYPE,
- /obj/item/clothing/under/soviet = TRADER_THIS_TYPE,
- /obj/item/harpoon = TRADER_THIS_TYPE,
- /obj/item/sword = TRADER_ALL,
- /obj/item/scythe = TRADER_THIS_TYPE,
- /obj/item/star = TRADER_THIS_TYPE,
- /obj/item/twohanded/baseballbat = TRADER_THIS_TYPE)
\ No newline at end of file
+ possible_trading_items = list(
+ /obj/item/clothing/head/wizard/magus = TRADER_THIS_TYPE,
+ /obj/item/shield/buckler = TRADER_THIS_TYPE,
+ /obj/item/clothing/head/redcoat = TRADER_THIS_TYPE,
+ /obj/item/clothing/head/powdered_wig = TRADER_THIS_TYPE,
+ /obj/item/clothing/head/hasturhood = TRADER_THIS_TYPE,
+ /obj/item/clothing/head/helmet/gladiator = TRADER_THIS_TYPE,
+ /obj/item/clothing/head/plaguedoctorhat = TRADER_THIS_TYPE,
+ /obj/item/clothing/glasses/eyepatch/monocle = TRADER_THIS_TYPE,
+ /obj/item/clothing/mask/smokable/pipe = TRADER_THIS_TYPE,
+ /obj/item/clothing/mask/gas/plaguedoctor = TRADER_THIS_TYPE,
+ /obj/item/clothing/suit/hastur = TRADER_THIS_TYPE,
+ /obj/item/clothing/suit/imperium_monk = TRADER_THIS_TYPE,
+ /obj/item/clothing/suit/judgerobe = TRADER_THIS_TYPE,
+ /obj/item/clothing/suit/wizrobe/magusred = TRADER_THIS_TYPE,
+ /obj/item/clothing/suit/wizrobe/magusblue = TRADER_THIS_TYPE,
+ /obj/item/clothing/under/gladiator = TRADER_THIS_TYPE,
+ /obj/item/clothing/under/kilt = TRADER_THIS_TYPE,
+ /obj/item/clothing/under/redcoat = TRADER_THIS_TYPE,
+ /obj/item/clothing/under/soviet = TRADER_THIS_TYPE,
+ /obj/item/harpoon = TRADER_THIS_TYPE,
+ /obj/item/sword = TRADER_ALL,
+ /obj/item/scythe = TRADER_THIS_TYPE,
+ /obj/item/star = TRADER_THIS_TYPE,
+ /obj/item/twohanded/baseballbat = TRADER_THIS_TYPE
+ )
\ No newline at end of file
diff --git a/code/datums/trading/traders/unique.dm b/code/datums/trading/traders/unique.dm
index 66b3d8b6732..b4a4cc110c8 100644
--- a/code/datums/trading/traders/unique.dm
+++ b/code/datums/trading/traders/unique.dm
@@ -30,13 +30,14 @@
origin = "SGS Severance"
possible_wanted_items = list(
- /obj/item/chems/food/human = TRADER_SUBTYPES_ONLY,
- /obj/item/chems/food/meat/human = TRADER_THIS_TYPE,
- /mob/living/carbon/human = TRADER_ALL
- )
+ /obj/item/chems/food/human = TRADER_SUBTYPES_ONLY,
+ /obj/item/chems/food/meat/human = TRADER_THIS_TYPE,
+ /mob/living/carbon/human = TRADER_ALL
+ )
- possible_trading_items = list(/obj/item/gun/projectile/automatic = TRADER_SUBTYPES_ONLY
- )
+ possible_trading_items = list(
+ /obj/item/gun/projectile/automatic = TRADER_SUBTYPES_ONLY
+ )
blacklisted_trade_items = null
@@ -62,9 +63,13 @@
name = "Bobo"
origin = "Floating rock"
- possible_wanted_items = list(/obj/item/stack/material/ore = TRADER_ALL)
- possible_trading_items = list(/obj/machinery/power/supermatter = TRADER_ALL,
- /obj/item/aiModule = TRADER_SUBTYPES_ONLY)
+ possible_wanted_items = list(
+ /obj/item/stack/material/ore = TRADER_ALL
+ )
+ possible_trading_items = list(
+ /obj/machinery/power/supermatter = TRADER_ALL,
+ /obj/item/aiModule = TRADER_SUBTYPES_ONLY
+ )
want_multiplier = 5000
speech = list("hail_generic" = "Blub am MERCHANT. Blub hunger for things. Boo bring them to blub, yes?",
@@ -91,25 +96,27 @@
possible_origins = list("An indistinct location", "Unknown location", "The Diamond Sphere", "Beyond the Veil", "Deadverse")
name_language = TRADER_DEFAULT_NAME
- possible_wanted_items = list(/mob/living/simple_animal/construct = TRADER_SUBTYPES_ONLY,
- /obj/item/sword/cultblade = TRADER_THIS_TYPE,
- /obj/item/clothing/head/culthood = TRADER_ALL,
- /obj/item/clothing/suit/space/cult = TRADER_ALL,
- /obj/item/clothing/suit/cultrobes = TRADER_ALL,
- /obj/item/clothing/head/helmet/space/cult = TRADER_ALL,
- /obj/structure/cult = TRADER_SUBTYPES_ONLY,
- /obj/structure/constructshell = TRADER_ALL,
- /mob/living/simple_animal/familiar = TRADER_SUBTYPES_ONLY,
- /mob/living/simple_animal/familiar/pet = TRADER_BLACKLIST,
- /mob/living/simple_animal/hostile/mimic = TRADER_ALL)
-
- possible_trading_items = list(/obj/item/clothing/gloves/wizard = TRADER_THIS_TYPE,
- /obj/item/clothing/head/helmet/space/void/wizard = TRADER_THIS_TYPE,
- /obj/item/clothing/head/wizard = TRADER_ALL,
- /obj/item/clothing/suit/space/void/wizard = TRADER_THIS_TYPE,
- /obj/item/toy/figure/wizard = TRADER_THIS_TYPE,
- /obj/item/staff = TRADER_ALL,
- ) //Probably see about getting some more wizard based shit
+ possible_wanted_items = list(
+ /mob/living/simple_animal/construct = TRADER_SUBTYPES_ONLY,
+ /obj/item/sword/cultblade = TRADER_THIS_TYPE,
+ /obj/item/clothing/head/culthood = TRADER_ALL,
+ /obj/item/clothing/suit/space/cult = TRADER_ALL,
+ /obj/item/clothing/suit/cultrobes = TRADER_ALL,
+ /obj/item/clothing/head/helmet/space/cult = TRADER_ALL,
+ /obj/structure/cult = TRADER_SUBTYPES_ONLY,
+ /obj/structure/constructshell = TRADER_ALL,
+ /mob/living/simple_animal/familiar = TRADER_SUBTYPES_ONLY,
+ /mob/living/simple_animal/familiar/pet = TRADER_BLACKLIST,
+ /mob/living/simple_animal/hostile/mimic = TRADER_ALL
+ )
+ possible_trading_items = list(
+ /obj/item/clothing/gloves/wizard = TRADER_THIS_TYPE,
+ /obj/item/clothing/head/helmet/space/void/wizard = TRADER_THIS_TYPE,
+ /obj/item/clothing/head/wizard = TRADER_ALL,
+ /obj/item/clothing/suit/space/void/wizard = TRADER_THIS_TYPE,
+ /obj/item/toy/figure/wizard = TRADER_THIS_TYPE,
+ /obj/item/staff = TRADER_ALL,
+ ) //Probably see about getting some more wizard based shit
speech = list("hail_generic" = "Hello! Are you here on pleasure or business?",
"hail_Golem" = "Interesting... how incredibly interesting... come! Let us do business!",
diff --git a/code/datums/trading/traders/weaponry.dm b/code/datums/trading/traders/weaponry.dm
index 1d2872f219a..2f9d25d5c04 100644
--- a/code/datums/trading/traders/weaponry.dm
+++ b/code/datums/trading/traders/weaponry.dm
@@ -18,15 +18,17 @@
"insult_bad" = "If I had my gun I'd shoot you!"
)
- possible_trading_items = list(/obj/item/gun/projectile/pistol/holdout = TRADER_ALL,
- /obj/item/gun/projectile/shotgun/pump= TRADER_SUBTYPES_ONLY,
- /obj/item/ammo_magazine = TRADER_SUBTYPES_ONLY,
- /obj/item/ammo_magazine/rifle/empty = TRADER_BLACKLIST,
- /obj/item/ammo_magazine/pistol/small/empty = TRADER_BLACKLIST,
- /obj/item/ammo_magazine/pistol/empty = TRADER_BLACKLIST,
- /obj/item/ammo_magazine/box/pistol/empty = TRADER_BLACKLIST,
- /obj/item/ammo_magazine/smg/empty = TRADER_BLACKLIST,
- /obj/item/clothing/accessory/storage/holster = TRADER_ALL)
+ possible_trading_items = list(
+ /obj/item/gun/projectile/pistol/holdout = TRADER_ALL,
+ /obj/item/gun/projectile/shotgun/pump = TRADER_SUBTYPES_ONLY,
+ /obj/item/ammo_magazine = TRADER_SUBTYPES_ONLY,
+ /obj/item/ammo_magazine/rifle/empty = TRADER_BLACKLIST,
+ /obj/item/ammo_magazine/pistol/small/empty = TRADER_BLACKLIST,
+ /obj/item/ammo_magazine/pistol/empty = TRADER_BLACKLIST,
+ /obj/item/ammo_magazine/box/pistol/empty = TRADER_BLACKLIST,
+ /obj/item/ammo_magazine/smg/empty = TRADER_BLACKLIST,
+ /obj/item/clothing/accessory/storage/holster = TRADER_ALL
+ )
/datum/trader/ship/egunshop
name = "Energy Gun Shop Employee"
@@ -48,16 +50,18 @@
"insult_bad" = "That's... very mean. I won't think twice about blacklisting your channel, so stop."
)
- possible_trading_items = list(/obj/item/gun/energy/taser = TRADER_THIS_TYPE,
- /obj/item/gun/energy/xray = TRADER_THIS_TYPE,
- /obj/item/gun/energy/laser = TRADER_THIS_TYPE,
- /obj/item/gun/energy/gun = TRADER_THIS_TYPE,
- /obj/item/cell = TRADER_THIS_TYPE,
- /obj/item/cell/crap = TRADER_THIS_TYPE,
- /obj/item/cell/high = TRADER_THIS_TYPE,
- /obj/item/cell/super = TRADER_THIS_TYPE,
- /obj/item/cell/hyper = TRADER_THIS_TYPE,
- /obj/item/clothing/accessory/storage/holster = TRADER_ALL)
+ possible_trading_items = list(
+ /obj/item/gun/energy/taser = TRADER_THIS_TYPE,
+ /obj/item/gun/energy/xray = TRADER_THIS_TYPE,
+ /obj/item/gun/energy/laser = TRADER_THIS_TYPE,
+ /obj/item/gun/energy/gun = TRADER_THIS_TYPE,
+ /obj/item/cell = TRADER_THIS_TYPE,
+ /obj/item/cell/crap = TRADER_THIS_TYPE,
+ /obj/item/cell/high = TRADER_THIS_TYPE,
+ /obj/item/cell/super = TRADER_THIS_TYPE,
+ /obj/item/cell/hyper = TRADER_THIS_TYPE,
+ /obj/item/clothing/accessory/storage/holster = TRADER_ALL
+ )
/datum/trader/dogan
name = "Dogan"
@@ -79,8 +83,10 @@
compliment_increase = 0
insult_drop = 0
- possible_trading_items = list(/obj/item/gun/projectile/zipgun = TRADER_THIS_TYPE,
- /obj/item/gun/projectile/bolt_action/sniper/ant = TRADER_THIS_TYPE,
- /obj/item/gun/energy/laser/dogan = TRADER_THIS_TYPE,
- /obj/item/gun/projectile/automatic/smg/usi = TRADER_THIS_TYPE,
- /obj/item/clothing/accessory/storage/holster = TRADER_ALL)
\ No newline at end of file
+ possible_trading_items = list(
+ /obj/item/gun/projectile/zipgun = TRADER_THIS_TYPE,
+ /obj/item/gun/projectile/bolt_action/sniper/ant = TRADER_THIS_TYPE,
+ /obj/item/gun/energy/laser/dogan = TRADER_THIS_TYPE,
+ /obj/item/gun/projectile/automatic/smg/usi = TRADER_THIS_TYPE,
+ /obj/item/clothing/accessory/storage/holster = TRADER_ALL
+ )
diff --git a/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm b/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm
index fae76f7aadc..ebb26b19070 100644
--- a/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm
+++ b/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm
@@ -9,12 +9,12 @@
affected_levels = zlevels
/datum/universal_state/jump/OnEnter()
- var/obj/abstract/level_data/space_zlevel = SSmapping.increment_world_z_size(/obj/abstract/level_data/space) //get a place for stragglers
+ var/datum/level_data/space_zlevel = SSmapping.increment_world_z_size(/datum/level_data/space) //get a place for stragglers
for(var/mob/living/M in SSmobs.mob_list)
if(M.z in affected_levels)
var/area/A = get_area(M)
if(istype(A,/area/space)) //straggler
- var/turf/T = locate(M.x, M.y, space_zlevel.my_z)
+ var/turf/T = locate(M.x, M.y, space_zlevel.level_z)
if(T)
M.forceMove(T)
else
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 912119325ee..2b6ca88221d 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -222,8 +222,8 @@
if(length(possible_locations))
newz = pick(possible_locations)
if(!newz)
- var/obj/abstract/level_data/level = SSmapping.increment_world_z_size(/obj/abstract/level_data/space)
- newz = level?.my_z
+ var/datum/level_data/level = SSmapping.increment_world_z_size(/datum/level_data/space)
+ newz = level.level_z
if(newz)
var/turf/nloc = locate(rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE), rand(TRANSITIONEDGE, world.maxy-TRANSITIONEDGE), newz)
diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm
index 96d124af584..218e980f804 100644
--- a/code/game/objects/items/weapons/storage/boxes.dm
+++ b/code/game/objects/items/weapons/storage/boxes.dm
@@ -186,6 +186,9 @@
/obj/item/storage/box/ammo/shotgunammo/WillContain()
return list(/obj/item/ammo_magazine/shotholder = 2)
+/obj/item/storage/box/ammo/shotgunammo/large/WillContain()
+ return list(/obj/item/ammo_magazine/shotholder = 4)
+
/obj/item/storage/box/ammo/shotgunshells
name = "box of shotgun shells"
/obj/item/storage/box/ammo/shotgunshells/WillContain()
@@ -201,6 +204,9 @@
/obj/item/storage/box/ammo/stunshells/WillContain()
return list(/obj/item/ammo_magazine/shotholder/stun = 2)
+/obj/item/storage/box/ammo/stunshells/large/WillContain()
+ return list(/obj/item/ammo_magazine/shotholder/stun = 4)
+
/obj/item/storage/box/ammo/sniperammo
name = "box of sniper shells"
/obj/item/storage/box/ammo/sniperammo/WillContain()
diff --git a/code/game/turfs/exterior/_exterior.dm b/code/game/turfs/exterior/_exterior.dm
index 57812497ba0..d61c708ab9e 100644
--- a/code/game/turfs/exterior/_exterior.dm
+++ b/code/game/turfs/exterior/_exterior.dm
@@ -18,8 +18,9 @@
// Bit faster than return_air() for exoplanet exterior turfs
/turf/exterior/get_air_graphic()
- var/obj/abstract/level_data/level = SSmapping.levels_by_z[z]
- return level?.exterior_atmosphere?.graphic
+ var/datum/level_data/level = SSmapping.levels_by_z[z]
+ var/datum/gas_mixture/atmos = level?.get_exterior_atmosphere()
+ return atmos?.graphic
/turf/exterior/Initialize(mapload, no_update_icon = FALSE)
@@ -82,7 +83,7 @@
. = ..()
/turf/exterior/return_air()
- var/obj/abstract/level_data/level = SSmapping.levels_by_z[z]
+ var/datum/level_data/level = SSmapping.levels_by_z[z]
var/datum/gas_mixture/gas = level?.get_exterior_atmosphere()
if(!gas)
return
diff --git a/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm b/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm
index eb02821ccad..6cb202ff7f3 100644
--- a/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm
+++ b/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm
@@ -505,3 +505,6 @@
/datum/fabricator_recipe/imprinter/circuit/holomap
path = /obj/item/stock_parts/circuitboard/holomap
+
+/datum/fabricator_recipe/imprinter/circuit/geothermal_generator
+ path = /obj/item/stock_parts/circuitboard/geothermal
\ No newline at end of file
diff --git a/code/modules/maps/_map_template.dm b/code/modules/maps/_map_template.dm
index cb5ffa982f1..8acc9e73fb1 100644
--- a/code/modules/maps/_map_template.dm
+++ b/code/modules/maps/_map_template.dm
@@ -114,7 +114,6 @@
var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF)
var/list/atoms_to_initialise = list()
var/shuttle_state = pre_init_shuttles()
-
var/map_hash = modify_tag_vars && "[sequential_id("map_id")]"
ASSERT(isnull(global._preloader.current_map_hash)) // Recursive maploading is possible, but not from this block: recursive loads should be triggered in Initialize, from init_atoms below.
global._preloader.current_map_hash = map_hash
@@ -135,7 +134,7 @@
init_shuttles(shuttle_state, map_hash, initialized_areas_by_type)
after_load()
for(var/z_index = bounds[MAP_MINZ] to bounds[MAP_MAXZ])
- var/obj/abstract/level_data/level = SSmapping.levels_by_z[z_index]
+ var/datum/level_data/level = SSmapping.levels_by_z[z_index]
level.post_template_load(src)
if(SSlighting.initialized)
SSlighting.InitializeZlev(z_index)
diff --git a/code/modules/maps/reader.dm b/code/modules/maps/reader.dm
index 66640af2f4c..f25242d5c23 100644
--- a/code/modules/maps/reader.dm
+++ b/code/modules/maps/reader.dm
@@ -57,7 +57,7 @@ var/global/dmm_suite/preloader/_preloader = new
#endif
Master.StopLoadingMap()
-/dmm_suite/proc/load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf, clear_contents, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, initialized_areas_by_type, level_data_type = /obj/abstract/level_data/space)
+/dmm_suite/proc/load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf, clear_contents, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, initialized_areas_by_type, level_data_type = /datum/level_data/space)
var/tfile = dmm_file//the map file we're creating
if(isfile(tfile))
tfile = safe_file2text(tfile, FALSE)
diff --git a/code/modules/materials/geology/_strata.dm b/code/modules/materials/geology/_strata.dm
index 80c930392e4..c72506db47f 100644
--- a/code/modules/materials/geology/_strata.dm
+++ b/code/modules/materials/geology/_strata.dm
@@ -7,8 +7,9 @@
var/maximum_temperature = INFINITY
/decl/strata/proc/is_valid_exoplanet_strata(var/obj/effect/overmap/visitable/sector/exoplanet/planet)
- var/obj/abstract/level_data/level_data = planet?.zlevels[1]
- var/check_temp = level_data?.exterior_atmosphere?.temperature || 0
+ var/datum/level_data/level_data = planet? SSmapping.levels_by_z[planet.map_z[1]] : null
+ var/datum/gas_mixture/atmos = level_data?.get_exterior_atmosphere()
+ var/check_temp = atmos?.temperature || 0
. = check_temp <= maximum_temperature
/decl/strata/Initialize()
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 6f5f80de575..8c828148b34 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -31,12 +31,12 @@
if(prob(20))
overlay_detail = "asteroid[rand(0,9)]"
. = ..()
- var/obj/abstract/level_data/mining_level/level = SSmapping.levels_by_z[z]
+ var/datum/level_data/mining_level/level = SSmapping.levels_by_z[z]
if(istype(level))
LAZYADD(level.mining_turfs, src)
/turf/simulated/floor/asteroid/Destroy()
- var/obj/abstract/level_data/mining_level/level = SSmapping.levels_by_z[z]
+ var/datum/level_data/mining_level/level = SSmapping.levels_by_z[z]
if(istype(level))
LAZYREMOVE(level.mining_turfs, src)
return ..()
diff --git a/code/modules/multiz/level_data.dm b/code/modules/multiz/level_data.dm
index fc85ce6c010..d0294cab20c 100644
--- a/code/modules/multiz/level_data.dm
+++ b/code/modules/multiz/level_data.dm
@@ -1,132 +1,237 @@
-/obj/abstract/level_data
- /// Name displayed on GPS when this sector is shown.
- var/gps_name
- /// z-level associated with this datum
- var/my_z
- /// A unique identifier for the level, used for SSmapping looup
+/// Returns all the turfs within a zlevel's transition edge, on a given direction.
+/// If include corners is true, the corners of the map will be included.
+/proc/get_transition_edge_turfs(var/z, var/dir_edge, var/include_corners = FALSE)
+ var/datum/level_data/LD = SSmapping.levels_by_z[z]
+
+ //minimum and maximum corners making up the box, between which the transition edge is
+ var/min_x = 1 //X of lower left corner of the edge
+ var/min_y = 1 //Y of lower left corner of the edge
+ var/max_x = 1 //X of upper right corner of the edge
+ var/max_y = 1 //Y of upper right corner of the edge
+
+ //Pos before or after the transition edge on either ends of each axis of the level. (Including corners or not)
+ var/x_bef_transit = include_corners? (LD.level_inner_min_x - TRANSITIONEDGE) : (LD.level_inner_min_x)
+ var/x_aft_transit = include_corners? (LD.level_inner_max_x + TRANSITIONEDGE) : (LD.level_inner_max_x)
+ var/y_bef_transit = include_corners? (LD.level_inner_min_y - TRANSITIONEDGE) : (LD.level_inner_min_y)
+ var/y_aft_transit = include_corners? (LD.level_inner_max_y + TRANSITIONEDGE) : (LD.level_inner_max_y)
+
+ switch(dir_edge)
+ if(NORTH)
+ min_x = x_bef_transit
+ min_y = LD.level_inner_max_y + 1 //Add one so we're outside the inner area (inner min/max are inclusive)
+ max_x = x_aft_transit
+ max_y = LD.level_inner_max_y + TRANSITIONEDGE //End of the transition edge on that axis
+ if(SOUTH)
+ min_x = x_bef_transit
+ min_y = LD.level_inner_min_y - TRANSITIONEDGE
+ max_x = x_aft_transit
+ max_y = LD.level_inner_min_y - 1
+ if(EAST)
+ min_x = LD.level_inner_max_x + 1
+ min_y = y_bef_transit
+ max_x = LD.level_inner_max_x + TRANSITIONEDGE
+ max_y = y_aft_transit
+ if(WEST)
+ min_x = LD.level_inner_min_x - TRANSITIONEDGE
+ min_y = y_bef_transit
+ max_x = LD.level_inner_min_x - 1
+ max_y = y_aft_transit
+
+ return block(
+ locate(min_x, min_y, LD.level_z),
+ locate(max_x, max_y, LD.level_z)
+ )
+
+///Returns all the turfs from all 4 corners of the transition border of a level.
+/proc/get_transition_edge_corner_turfs(var/z)
+ var/datum/level_data/LD = SSmapping.levels_by_z[z]
+ //South-West
+ . = block(
+ locate(LD.level_inner_min_x - TRANSITIONEDGE, LD.level_inner_min_y - TRANSITIONEDGE, LD.level_z),
+ locate(LD.level_inner_min_x - 1, LD.level_inner_min_y - 1, LD.level_z))
+ //South-East
+ . |= block(
+ locate(LD.level_inner_max_x + 1, LD.level_inner_min_y - TRANSITIONEDGE, LD.level_z),
+ locate(LD.level_inner_max_x + TRANSITIONEDGE, LD.level_inner_min_y - 1, LD.level_z))
+ //North-West
+ . |= block(
+ locate(LD.level_inner_min_x - TRANSITIONEDGE, LD.level_inner_max_y + 1, LD.level_z),
+ locate(LD.level_inner_min_x - 1, LD.level_inner_max_y + TRANSITIONEDGE, LD.level_z))
+ //North-East
+ . |= block(
+ locate(LD.level_inner_max_x + 1, LD.level_inner_max_y + 1, LD.level_z),
+ locate(LD.level_inner_max_x + TRANSITIONEDGE, LD.level_inner_max_y + TRANSITIONEDGE, LD.level_z))
+
+///Keeps details on how to generate, maintain and access a zlevel.
+/datum/level_data
+ ///Name displayed to the player to refer to this level in user interfaces and etc. If null, one will be generated.
+ var/name
+
+ /// The z-level that was assigned to this level_data
+ var/level_z
+ /// A unique string identifier for this particular z-level. Used to fetch a level without knowing its z-level.
var/level_id
- /// The base turf of the level (space, rock, etc)
- var/base_turf
- /// A list of ids that this level connects to horizontally.
- var/list/connects_to
/// Various flags indicating what this level functions as.
- var/level_flags
- /// Temperature of standard exterior atmosphere.
- var/exterior_atmos_temp = T20C
- /// Gaxmix datum returned to exterior return_air. Set to assoc list of material to moles to initialize the gas datum.
- var/datum/gas_mixture/exterior_atmosphere
- /// Default turf for this level on creation (if created via z-level incrementing)
- var/created_base_turf_type = /turf/space
- /// Default area for this level on creation (as above)
- var/created_base_area_type = /area/space
- /// Set to false to leave dark
- var/take_starlight_ambience = TRUE
- /// This default makes turfs not generate light. Adjust to have exterior areas be lit.
+ var/level_flags = 0
+ /// The desired width of the level, including the TRANSITIONEDGE.
+ ///If world.maxx is bigger, the exceeding area will be filled with turfs of "border_filler" type if defined, or base_turf otherwise.
+ var/level_max_width
+ /// The desired height of the level, including the TRANSITIONEDGE.
+ ///If world.maxy is bigger, the exceeding area will be filled with turfs of "border_filler" type if defined, or base_turf otherwise.
+ var/level_max_height
+
+ /// Filled by map gen on init. Indicates where the accessible level area starts past the transition edge.
+ var/level_inner_min_x
+ /// Filled by map gen on init. Indicates where the accessible level area starts past the transition edge.
+ var/level_inner_min_y
+ /// Filled by map gen on init. Indicates where the accessible level area starts past the transition edge.
+ var/level_inner_max_x
+ /// Filled by map gen on init. Indicates where the accessible level area starts past the transition edge.
+ var/level_inner_max_y
+
+ /// Filled by map gen on init. Indicates the width of the accessible area within the transition edges.
+ var/level_inner_width
+ /// Filled by map gen on init.Indicates the height of the accessible area within the transition edges.
+ var/level_inner_height
+
+ // *** Lighting ***
+ /// Set to false to override with our own.
+ var/use_global_exterior_ambience = TRUE
+ /// Ambient lighting light intensity turfs on this level should have. Value from 0 to 1.
var/ambient_light_level = 0
- /// Colour of ambient light.
+ /// Colour of ambient light for turfs on this level.
var/ambient_light_color = COLOR_WHITE
-INITIALIZE_IMMEDIATE(/obj/abstract/level_data)
-/obj/abstract/level_data/Initialize(var/ml, var/defer_level_setup = FALSE)
- . = ..()
+ // *** Level Gen ***
+ ///The default base turf type for the whole level. It will be the base turf type for the z level, unless loaded by map.
+ /// filler_turf overrides what turfs the level will be created with.
+ var/base_turf = /turf/space
+ /// When the level is created dynamically, all turfs on the map will be changed to this one type. If null, will use the base_turf instead.
+ var/filler_turf
+ ///The default area type for the whole level. It will be applied to all turfs in the level on creation, unless loaded by map.
+ var/base_area = /area/space
+ ///The turf to fill the border area beyond the bounds of the level with.
+ /// If null, nothing will be placed in the border area. (This is also placed when a border cannot be looped if loop_unconnected_borders is TRUE)
+ var/border_filler// = /turf/unsimulated/mineral
+ ///If set we will put a looping edge on every unconnected edge of the map. If null, will not loop unconnected edges.
+ /// If an unconnected edge is facing a connected edge, it will be instead filled with "border_filler" instead, if defined.
+ var/loop_turf_type// = /turf/unsimulated/mimc_edge/transition/loop
+ /// The turf type to use for zlevel lateral connections
+ var/transition_turf_type = /turf/unsimulated/mimic_edge/transition
+
+ // *** Atmos ***
+ /// Temperature of standard exterior atmosphere.
+ var/exterior_atmos_temp = T20C
+ /// Gas mixture datum returned to exterior return_air. Set to assoc list of material to moles to initialize the gas datum.
+ var/datum/gas_mixture/exterior_atmosphere
- my_z = z
- forceMove(null)
+ // *** Connections ***
+ ///A list of all level_ids, and a direction. Indicates what direction of the map connects to what level
+ var/list/connected_levels
+ ///A cached list of connected directions to their connected level id. Filled up at runtime.
+ var/tmp/list/cached_connections
- if(SSmapping.levels_by_z.len < my_z)
- SSmapping.levels_by_z.len = max(SSmapping.levels_by_z.len, my_z)
- PRINT_STACK_TRACE("Attempting to initialize a z-level that has not incremented world.maxz.")
+ ///A list of /datum/random_map types to apply to this level if we're running level generation.
+ /// Those are run before any parents/map_templates map generators.
+ var/list/level_generators
- // Swap out the old one but preserve any relevant references etc.
- if(SSmapping.levels_by_z[my_z])
- var/obj/abstract/level_data/old_level = SSmapping.levels_by_z[my_z]
- old_level.replace_with(src)
- qdel(old_level)
+ ///Whether the level data was setup already.
+ var/_level_setup_completed = FALSE
- SSmapping.levels_by_z[my_z] = src
- if(!level_id)
- level_id = "leveldata_[my_z]_[sequential_id(/obj/abstract/level_data)]"
- if(level_id in SSmapping.levels_by_id)
- PRINT_STACK_TRACE("Duplicate level_id '[level_id]' for z[my_z].")
- else
- SSmapping.levels_by_id[level_id] = src
+/datum/level_data/New(var/_z_level, var/defer_level_setup = FALSE)
+ . = ..()
+ level_z = _z_level
+ if(isnull(_z_level))
+ PRINT_STACK_TRACE("Attempting to initialize a null z-level.")
+ initialize_level_id()
+ SSmapping.register_level_data(src)
if(SSmapping.initialized && !defer_level_setup)
setup_level_data()
-/obj/abstract/level_data/proc/post_template_load(var/datum/map_template/template)
- if(template.accessibility_weight)
- SSmapping.accessible_z_levels[num2text(my_z)] = template.accessibility_weight
- SSmapping.player_levels |= my_z
+/datum/level_data/Destroy(force)
+ log_debug("Level data datum being destroyed: [log_info_line(src)]")
+ //Since this is a datum that lives inside the SSmapping subsystem, I'm not sure if we really need to prevent deletion.
+ // It was fine for the obj version of this, but not much point now?
+ SSmapping.unregister_level_data(src)
+ . = ..()
-/obj/abstract/level_data/Destroy(var/force)
- if(force)
- new type(locate(round(world.maxx/2), round(world.maxy/2), my_z))
- return ..()
- return QDEL_HINT_LETMELIVE
+///Generates a level_id if none were specified in the datum definition.
+/datum/level_data/proc/initialize_level_id()
+ if(level_id)
+ return
+ level_id = "leveldata_[level_z]_[sequential_id(/datum/level_data)]"
-/obj/abstract/level_data/proc/replace_with(var/obj/abstract/level_data/new_level)
+///Handle a new level_data datum overwriting us.
+/datum/level_data/proc/replace_with(var/datum/level_data/new_level)
new_level.copy_from(src)
-/obj/abstract/level_data/proc/copy_from(var/obj/abstract/level_data/old_level)
+///Handle copying data from a previous level_data we're replacing.
+/datum/level_data/proc/copy_from(var/datum/level_data/old_level)
return
-/obj/abstract/level_data/proc/initialize_level()
- var/change_turf = (created_base_turf_type && created_base_turf_type != world.turf)
- var/change_area = (created_base_area_type && created_base_area_type != world.area)
+///Initialize the turfs on the z-level.
+/datum/level_data/proc/initialize_new_level()
+ //#TODO: Is it really necessary to do this for any and all levels? Seems mainly useful for space levels?
+ var/picked_turf = filler_turf || base_turf //Pick the filler_turf for filling if it's set, otherwise use the base_turf
+ var/change_turf = (picked_turf && picked_turf != world.turf)
+ var/change_area = (base_area && base_area != world.area)
if(!change_turf && !change_area)
return
- var/corner_start = locate(1, 1, my_z)
- var/corner_end = locate(world.maxx, world.maxy, my_z)
- var/area/A = change_area ? new created_base_area_type : null
+ var/corner_start = locate(1, 1, level_z)
+ var/corner_end = locate(world.maxx, world.maxy, level_z)
+ var/area/A = change_area ? get_base_area_instance() : null
for(var/turf/T as anything in block(corner_start, corner_end))
if(change_turf)
- T = T.ChangeTurf(created_base_turf_type)
+ T = T.ChangeTurf(picked_turf)
if(change_area)
ChangeArea(T, A)
-/obj/abstract/level_data/proc/setup_level_data()
-
- if(take_starlight_ambience)
- ambient_light_level = config.exterior_ambient_light
- ambient_light_color = SSskybox.background_color
- if(base_turf)
- SSmapping.base_turf_by_z[my_z] = base_turf
- if(level_flags & ZLEVEL_STATION)
- SSmapping.station_levels |= my_z
- if(level_flags & ZLEVEL_ADMIN)
- SSmapping.admin_levels |= my_z
- if(level_flags & ZLEVEL_CONTACT)
- SSmapping.contact_levels |= my_z
- if(level_flags & ZLEVEL_PLAYER)
- SSmapping.player_levels |= my_z
- if(level_flags & ZLEVEL_SEALED)
- SSmapping.sealed_levels |= my_z
-
- build_exterior_atmosphere()
- if(config.generate_map)
- build_level()
-
-/obj/abstract/level_data/proc/build_level()
- return
-
-/obj/abstract/level_data/proc/find_connected_levels(var/list/found)
- for(var/other_id in connects_to)
- var/obj/abstract/level_data/neighbor = SSmapping.levels_by_id[other_id]
- neighbor.add_connected_levels(found)
-
-/obj/abstract/level_data/proc/add_connected_levels(var/list/found)
- . = found
- if((my_z in found))
+///Prepare level for being used. Setup borders, lateral z connections, ambient lighting, atmosphere, etc..
+/datum/level_data/proc/setup_level_data()
+ if(_level_setup_completed)
+ return //Since we can defer setup, make sure we only setup once
+
+ setup_level_bounds()
+ setup_ambient()
+ setup_exterior_atmosphere()
+ generate_level()
+ after_generate_level()
+ _level_setup_completed = TRUE
+
+///Calculate the bounds of the level, the border area, and the inner accessible area.
+/datum/level_data/proc/setup_level_bounds()
+ level_max_width = level_max_width ? level_max_width : world.maxx
+ level_max_height = level_max_height ? level_max_height : world.maxy
+ var/x_origin = round((world.maxx - level_max_width) / 2)
+ var/y_origin = round((world.maxy - level_max_height) / 2)
+
+ //The first x/y that's within the accessible level
+ level_inner_min_x = x_origin + TRANSITIONEDGE + 1
+ level_inner_min_y = y_origin + TRANSITIONEDGE + 1
+
+ //The last x/y that's within the accessible level
+ level_inner_max_x = (level_max_width - level_inner_min_x) + 1
+ level_inner_max_y = (level_max_height - level_inner_min_y) + 1
+
+ //The width of the accessible inner area of the level
+ level_inner_width = level_max_width - (2 * TRANSITIONEDGE)
+ level_inner_height = level_max_height - (2 * TRANSITIONEDGE)
+
+///Setup ambient lighting for the level
+/datum/level_data/proc/setup_ambient()
+ if(!use_global_exterior_ambience)
return
- LAZYADD(found, my_z)
- if(!length(connects_to))
+ ambient_light_level = config.exterior_ambient_light
+ ambient_light_color = SSskybox.background_color
+
+///Setup/generate atmosphere for exterior turfs on the level.
+/datum/level_data/proc/setup_exterior_atmosphere()
+ //Skip setup if we've been set to a ref already
+ if(istype(exterior_atmosphere))
+ exterior_atmosphere.update_values() //Might as well update
+ exterior_atmosphere.check_tile_graphic()
return
- for(var/other_id in connects_to)
- var/obj/abstract/level_data/neighbor = SSmapping.levels_by_id[other_id]
- neighbor.add_connected_levels(found)
-
-/obj/abstract/level_data/proc/build_exterior_atmosphere()
var/list/exterior_atmos_composition = exterior_atmosphere
exterior_atmosphere = new
if(islist(exterior_atmos_composition))
@@ -136,80 +241,306 @@ INITIALIZE_IMMEDIATE(/obj/abstract/level_data)
exterior_atmosphere.update_values()
exterior_atmosphere.check_tile_graphic()
-/obj/abstract/level_data/proc/get_exterior_atmosphere()
- if(isnull(exterior_atmosphere) || islist(exterior_atmosphere)) //#FIXME: remove once we get the level_data improvements in
- build_exterior_atmosphere()
+//
+// Level Load/Gen
+//
+
+///Called when setting up the level. Apply generators and anything that modifies the turfs of the level.
+/datum/level_data/proc/generate_level()
+ var/origx = level_inner_min_x
+ var/origy = level_inner_min_y
+ var/endx = level_inner_min_x + level_inner_width
+ var/endy = level_inner_min_y + level_inner_height
+ for(var/gen_type in level_generators)
+ new gen_type(origx, origy, level_z, endx, endy, FALSE, TRUE, get_base_area_instance())
+
+///Apply the parent entity's map generators. (Planets generally)
+///This proc is to give a chance to level_data subtypes to individually chose to ignore the parent generators.
+/datum/level_data/proc/apply_map_generators(var/list/map_gen)
+ var/origx = level_inner_min_x
+ var/origy = level_inner_min_y
+ var/endx = level_inner_min_x + level_inner_width
+ var/endy = level_inner_min_y + level_inner_height
+ for(var/gen_type in map_gen)
+ new gen_type(origx, origy, level_z, endx, endy, FALSE, TRUE, get_base_area_instance())
+
+///Called during level setup. Run anything that should happen only after the map is fully generated.
+/datum/level_data/proc/after_generate_level()
+ build_border()
+
+///Changes anything named we may need to rename accordingly to the parent location name. For instance, exoplanets levels.
+/datum/level_data/proc/adapt_location_name(var/location_name)
+ SHOULD_CALL_PARENT(TRUE)
+ if(!base_area || ispath(base_area, /area/space))
+ return FALSE
+ return TRUE
+
+///Called after a map_template has been loaded on our z-level. Only apply to templates loaded onto new z-levels.
+/datum/level_data/proc/post_template_load(var/datum/map_template/template)
+ if(template.accessibility_weight)
+ SSmapping.accessible_z_levels[num2text(level_z)] = template.accessibility_weight
+ SSmapping.player_levels |= level_z
+
+///Builds the map's transition edge if applicable
+/datum/level_data/proc/build_border()
+ var/list/edge_states = compute_level_edges_states()
+ for(var/edge_dir in global.cardinal)
+ build_border_edge(edge_states[edge_dir], edge_dir)
+
+ //Now prepare the corners of the border
+ build_border_corners()
+
+///Loop through the edges of the level and determine if they're connected, looping, filled, or untouched.
+/datum/level_data/proc/compute_level_edges_states()
+ var/list/edge_states = list()
+ edge_states.len = 8 //Largest cardinal direction is WEST or 8
+ var/should_loop_edges = ispath(loop_turf_type)
+ var/has_filler_edge = ispath(border_filler)
+
+ //First determine and validate the borders
+ for(var/adir in global.cardinal)
+ //First check for connections, or loop
+ if(get_connected_level_id(adir))
+ edge_states[adir] = LEVEL_EDGE_CON
+ var/reverse = global.reverse_dir[adir]
+ //When facing a connected edge that wasn't set yet, make sure we don't put a loop edge opposite of it.
+ if(should_loop_edges && ((edge_states[reverse] == LEVEL_EDGE_LOOP) || !edge_states[reverse]))
+ edge_states[reverse] = has_filler_edge? LEVEL_EDGE_WALL : LEVEL_EDGE_NONE
+
+ if(edge_states[adir])
+ continue //Skip edges which either connect to another z-level, or have been forced to a specific type already
+ if(should_loop_edges)
+ edge_states[adir] = LEVEL_EDGE_LOOP
+ else if(ispath(border_filler))
+ edge_states[adir] = LEVEL_EDGE_WALL //Apply filler wall last if we have no connections or loop
+ else
+ edge_states[adir] = LEVEL_EDGE_NONE
+
+ return edge_states
+
+///Apply the specified edge type to the specified edge's turfs
+/datum/level_data/proc/build_border_edge(var/edge_type, var/edge_dir)
+ if(edge_type == LEVEL_EDGE_NONE)
+ return
+
+ var/list/edge_turfs
+ switch(edge_type)
+ if(LEVEL_EDGE_LOOP)
+ edge_turfs = get_transition_edge_turfs(level_z, edge_dir, FALSE)
+ for(var/turf/T in edge_turfs)
+ T.ChangeTurf(loop_turf_type)
+ if(LEVEL_EDGE_CON)
+ edge_turfs = get_transition_edge_turfs(level_z, edge_dir, FALSE)
+ for(var/turf/T in edge_turfs)
+ T.ChangeTurf(transition_turf_type)
+ if(LEVEL_EDGE_WALL)
+ edge_turfs = get_transition_edge_turfs(level_z, edge_dir, TRUE)
+ for(var/turf/T in edge_turfs)
+ T.ChangeTurf(border_filler)
+
+///Handle preparing the level's border's corners after we've stup the edges.
+/datum/level_data/proc/build_border_corners()
+ //Now prepare the corners of the border
+ var/list/all_corner_turfs = get_transition_edge_corner_turfs(level_z)
+ for(var/turf/T in all_corner_turfs)
+ //In case we got filler turfs for borders, make sure to fill the corners with it
+ if(border_filler)
+ T.ChangeTurf(border_filler)
+ //Force corner turfs to be solid, so nothing end up being lost/stuck in there
+ T.set_density(TRUE)
+
+//
+// Accessors
+//
+/datum/level_data/proc/get_exterior_atmosphere()
+ if(!istype(exterior_atmosphere)) //#FIXME: Temporary measure until the exoplanet gen stuff is moved out of overmap markers
+ setup_exterior_atmosphere()
if(exterior_atmosphere)
var/datum/gas_mixture/gas = new
gas.copy_from(exterior_atmosphere)
return gas
-/obj/abstract/level_data/proc/get_gps_level_name()
- if(!gps_name)
- var/obj/effect/overmap/overmap_entity = global.overmap_sectors[num2text(z)]
+/datum/level_data/proc/get_display_name()
+ if(!name)
+ var/obj/effect/overmap/overmap_entity = global.overmap_sectors[num2text(level_z)]
if(overmap_entity?.name)
- gps_name = overmap_entity.name
- else if(name)
- gps_name = name
+ name = overmap_entity.name
else
- gps_name = "Sector #[my_z]"
- return gps_name
+ name = "Sector #[level_z]"
+ return name
+
+/datum/level_data/proc/get_connected_level_id(var/direction)
+ if(!length(cached_connections))
+ //Build a list that we can access with the direction value instead of having to do string conversions
+ cached_connections = list()
+ cached_connections.len = DOWN //Down is the largest of the directional values
+ for(var/lvlid in connected_levels)
+ cached_connections[connected_levels[lvlid]] = lvlid
+
+ if(istext(direction))
+ CRASH("Direction must be a direction flag.")
+ return cached_connections[direction]
+
+///Returns recursively a list of level_data for each connected levels.
+/datum/level_data/proc/get_all_connected_level_data(var/list/_connected_siblings)
+ . = list()
+ //Since levels may refer to eachothers, make sure we're in the siblings list to avoid infinite recursion
+ LAZYDISTINCTADD(_connected_siblings, src)
+ for(var/id in connected_levels)
+ var/datum/level_data/LD = SSmapping.levels_by_id[id]
+ if(LD in _connected_siblings)
+ continue
+ . |= LD
+ var/list/cur_con = LD.get_all_connected_level_data(_connected_siblings)
+ if(length(cur_con))
+ . |= cur_con
+
+///Returns recursively a list of level_ids for each connected levels.
+/datum/level_data/proc/get_all_connected_level_ids(var/list/_connected_siblings)
+ . = list()
+ //Since levels may refer to eachothers, make sure we're in the siblings list to avoid infinite recursion
+ LAZYDISTINCTADD(_connected_siblings, level_id)
+ for(var/id in connected_levels)
+ var/datum/level_data/LD = SSmapping.levels_by_id[id]
+ if(LD.level_id in _connected_siblings)
+ continue
+ . |= LD.level_id
+ var/list/cur_con = LD.get_all_connected_level_ids(_connected_siblings)
+ if(length(cur_con))
+ . |= cur_con
+
+///Returns recursively a list of z-level indices for each connected levels. Parameter is to keep trakc
+/datum/level_data/proc/get_all_connected_level_z(var/list/_connected_siblings)
+ . = list()
+ //Since levels may refer to eachothers, make sure we're in the siblings list to avoid infinite recursion
+ LAZYDISTINCTADD(_connected_siblings, level_z)
+ for(var/id in connected_levels)
+ var/datum/level_data/LD = SSmapping.levels_by_id[id]
+ if(LD.level_z in _connected_siblings)
+ continue
+ . |= LD.level_z
+ var/list/cur_con = LD.get_all_connected_level_z(_connected_siblings)
+ if(length(cur_con))
+ . |= cur_con
+
+
+/datum/level_data/proc/find_connected_levels(var/list/found)
+ LAZYDISTINCTADD(found, level_z)
+ for(var/other_id in connected_levels)
+ var/datum/level_data/neighbor = SSmapping.levels_by_id[other_id]
+ if(neighbor.level_z in found)
+ continue
+ LAZYADD(found, neighbor.level_z)
+ if(!length(neighbor.connected_levels))
+ continue
+ neighbor.find_connected_levels(found)
+
+///Returns the instance of the base area for this level
+/datum/level_data/proc/get_base_area_instance()
+ var/area/found = locate(base_area)
+ if(found)
+ return found
+ if(ispath(base_area))
+ return new base_area
+ return locate(world.area)
+
+////////////////////////////////////////////
+// Level Data Spawner
+////////////////////////////////////////////
+
+/// Mapper helper for spawning a specific level_data datum with the map as it gets loaded
+/obj/abstract/level_data_spawner
+ name = "level data spawner"
+ var/level_data_type = /datum/level_data/space
+
+INITIALIZE_IMMEDIATE(/obj/abstract/level_data_spawner)
+/obj/abstract/level_data_spawner/Initialize()
+ var/datum/level_data/LD = new level_data_type(z)
+ //Let the mapper forward a level name for the level_data, if none was defined
+ if(!length(LD.name) && length(name))
+ LD.name = name
+ ..()
+ return INITIALIZE_HINT_QDEL
+
+////////////////////////////////////////////
+// Mapper Templates
+////////////////////////////////////////////
+/obj/abstract/level_data_spawner/player
+ level_data_type = /datum/level_data/player_level
+
+/obj/abstract/level_data_spawner/main_level
+ level_data_type = /datum/level_data/main_level
+
+/obj/abstract/level_data_spawner/admin_level
+ level_data_type = /datum/level_data/admin_level
+
+/obj/abstract/level_data_spawner/debug
+ level_data_type = /datum/level_data/debug
+
+/obj/abstract/level_data_spawner/mining_level
+ level_data_type = /datum/level_data/mining_level
-/*
- * Mappable subtypes.
- */
-/obj/abstract/level_data/debug
+/obj/abstract/level_data_spawner/exoplanet
+ level_data_type = /datum/level_data/exoplanet
+
+////////////////////////////////////////////
+// Level Data Implementations
+////////////////////////////////////////////
+/datum/level_data/space
+
+/datum/level_data/debug
name = "Debug Level"
-/obj/abstract/level_data/main_level
+/datum/level_data/main_level
level_flags = (ZLEVEL_STATION|ZLEVEL_CONTACT|ZLEVEL_PLAYER)
-/obj/abstract/level_data/admin_level
+/datum/level_data/admin_level
level_flags = (ZLEVEL_ADMIN|ZLEVEL_SEALED)
-/obj/abstract/level_data/player_level
+/datum/level_data/player_level
level_flags = (ZLEVEL_CONTACT|ZLEVEL_PLAYER)
-/obj/abstract/level_data/space
-
-/obj/abstract/level_data/exoplanet
+/datum/level_data/exoplanet
exterior_atmosphere = list(
/decl/material/gas/oxygen = MOLES_O2STANDARD,
/decl/material/gas/nitrogen = MOLES_N2STANDARD
)
exterior_atmos_temp = T20C
level_flags = (ZLEVEL_PLAYER|ZLEVEL_SEALED)
- take_starlight_ambience = FALSE // This is set up by the exoplanet object.
+ use_global_exterior_ambience = FALSE // This is set up by the exoplanet object.
-/obj/abstract/level_data/unit_test
+/datum/level_data/unit_test
level_flags = (ZLEVEL_CONTACT|ZLEVEL_PLAYER|ZLEVEL_SEALED)
-// Used to generate mining ores etc.
-/obj/abstract/level_data/mining_level
+/datum/level_data/overmap
+ name = "Sensor Display"
+ level_flags = ZLEVEL_SEALED
+ use_global_exterior_ambience = FALSE // Overmap doesn't care about ambient lighting
+
+//#TODO: This seems like it could be generalized in a much better way?
+// Used specifically by /turf/simulated/floor/asteroid, and some away sites to generate mining turfs
+/datum/level_data/mining_level
level_flags = (ZLEVEL_PLAYER|ZLEVEL_SEALED)
var/list/mining_turfs
-/obj/abstract/level_data/mining_level/Destroy()
+/datum/level_data/mining_level/Destroy()
mining_turfs = null
return ..()
-/obj/abstract/level_data/mining_level/asteroid
+/datum/level_data/mining_level/asteroid
base_turf = /turf/simulated/floor/asteroid
-/obj/abstract/level_data/mining_level/post_template_load()
- ..()
- new /datum/random_map/automata/cave_system(1, 1, my_z, world.maxx, world.maxy)
- new /datum/random_map/noise/ore(1, 1, my_z, world.maxx, world.maxy)
+/datum/level_data/mining_level/generate_level()
+ //#FIXME: This config option is very ambiguous. Most RNG stuff doesn't care about it. Might be worth removing?
+ if(!config.generate_map)
+ return
+ new /datum/random_map/automata/cave_system(1, 1, level_z, world.maxx, world.maxy)
+ new /datum/random_map/noise/ore(1, 1, level_z, world.maxx, world.maxy)
refresh_mining_turfs()
-/obj/abstract/level_data/mining_level/proc/refresh_mining_turfs()
+/datum/level_data/mining_level/proc/refresh_mining_turfs()
set waitfor = FALSE
for(var/turf/simulated/floor/asteroid/mining_turf as anything in mining_turfs)
mining_turf.updateMineralOverlays()
CHECK_TICK
mining_turfs = null
-
-// Used as a dummy z-level for the overmap.
-/obj/abstract/level_data/overmap
- name = "Sensor Display"
- take_starlight_ambience = FALSE // Overmap doesn't care about ambient lighting
diff --git a/code/modules/multiz/turf_mimic_edge.dm b/code/modules/multiz/turf_mimic_edge.dm
new file mode 100644
index 00000000000..b8f28194f42
--- /dev/null
+++ b/code/modules/multiz/turf_mimic_edge.dm
@@ -0,0 +1,366 @@
+#define MIMIC_EDGE_NAME "world's edge"
+#define MIMIC_EDGE_DESC "Flatearther's nightmare."
+
+////////////////////////////////
+// Mimic Edges
+////////////////////////////////
+
+///Dummy mouse-opaque overlay to prevent people turning/shooting towards ACTUAL location of vis_content thing
+/obj/effect/overlay/click_bait
+ name = "distant terrain"
+ desc = "You need to come over there to take a better look."
+ mouse_opacity = 2
+
+////////////////////////////////
+// Simulated Mimic Edges
+////////////////////////////////
+
+///Simulated turf meant to replicate the appearence of another.
+/turf/simulated/mimic_edge
+ name = MIMIC_EDGE_NAME
+ desc = MIMIC_EDGE_DESC
+ icon = null
+ icon_state = null
+ density = FALSE
+ permit_ao = FALSE //would need AO proxy
+ blocks_air = TRUE //would need air zone proxy
+ dynamic_lighting = FALSE //Would need lighting proxy
+
+ ///Mimicked turf's x position
+ var/mimic_x
+ ///Mimicked turf's y position
+ var/mimic_y
+ ///Mimicked turf's z position
+ var/mimic_z
+ ///Ref to the dummy overlay
+ var/obj/effect/overlay/click_bait/click_eater
+
+/turf/simulated/mimic_edge/Initialize(ml)
+ . = ..()
+ //Clear ourselves from the ambient queue
+ SSambience.queued -= src
+ //Need to put a mouse-opaque overlay there to prevent people turning/shooting towards ACTUAL location of vis_content things
+ click_eater = new(src)
+ setup_mimic()
+
+/turf/simulated/mimic_edge/Destroy()
+ QDEL_NULL(click_eater) //Make sure we get rid of it if the turf is somehow replaced by map gen to prevent them accumulating.
+ return ..()
+
+//Properly install itself, and allow overriding how the target turf is picked
+/turf/simulated/mimic_edge/proc/setup_mimic()
+ return
+
+/turf/simulated/mimic_edge/on_update_icon()
+ return
+
+/turf/simulated/mimic_edge/get_vis_contents_to_add()
+ . = ..()
+ var/turf/NT = mimic_x && mimic_y && mimic_z && locate(mimic_x, mimic_y, mimic_z)
+ if(NT)
+ opacity = NT.opacity
+ //log_debug("[src]([x],[y],[z]) mirroring [NT]([NT.x],[NT.y],[NT.z])")
+ LAZYADD(., NT)
+
+/turf/simulated/mimic_edge/proc/set_mimic_turf(var/_x, var/_y, var/_z)
+ mimic_z = _z? _z : z
+ mimic_x = _x
+ mimic_y = _y
+ refresh_vis_contents()
+
+//Prevent ambient completely, we're not a real turf
+/turf/simulated/mimic_edge/set_ambient_light(color, multiplier)
+ return
+/turf/simulated/mimic_edge/update_ambient_light(no_corner_update)
+ return
+/turf/simulated/mimic_edge/update_ambient_light_from_z()
+ return
+/turf/simulated/mimic_edge/lighting_build_overlay(now)
+ return
+
+////////////////////////////////
+// Unsimulated Mimic Edges
+////////////////////////////////
+
+///Unsimulated turf meant to replicate the appearence of another.
+/turf/unsimulated/mimic_edge
+ name = MIMIC_EDGE_NAME
+ desc = MIMIC_EDGE_DESC
+ icon = null
+ icon_state = null
+ density = FALSE
+ permit_ao = FALSE
+ blocks_air = TRUE
+ dynamic_lighting = FALSE
+
+ ///Mimicked turf's x position
+ var/mimic_x
+ ///Mimicked turf's y position
+ var/mimic_y
+ ///Mimicked turf's z position
+ var/mimic_z
+ ///Ref to the dummy overlay
+ var/obj/effect/overlay/click_bait/click_eater
+
+/turf/unsimulated/mimic_edge/Initialize(ml)
+ . = ..()
+ //Clear ourselves from the ambient queue
+ SSambience.queued -= src
+ //Need to put a mouse-opaque overlay there to prevent people turning/shooting towards ACTUAL location of vis_content things
+ click_eater = new(src)
+ setup_mimic()
+
+/turf/unsimulated/mimic_edge/Destroy()
+ QDEL_NULL(click_eater)
+ return ..()
+
+//Properly install itself, and allow overriding how the target turf is picked
+/turf/unsimulated/mimic_edge/proc/setup_mimic()
+ return
+
+/turf/unsimulated/mimic_edge/on_update_icon()
+ return
+
+/turf/unsimulated/mimic_edge/get_vis_contents_to_add()
+ . = ..()
+ var/turf/NT = mimic_x && mimic_y && mimic_z && locate(mimic_x, mimic_y, mimic_z)
+ if(NT)
+ opacity = NT.opacity
+ //log_debug("[src]([x],[y],[z]) mirroring [NT]([NT.x],[NT.y],[NT.z])")
+ LAZYADD(., NT)
+
+/turf/unsimulated/mimic_edge/proc/set_mimic_turf(var/_x, var/_y, var/_z)
+ mimic_z = _z? _z : z
+ mimic_x = _x
+ mimic_y = _y
+ refresh_vis_contents()
+
+//Prevent ambient completely, we're not a real turf
+/turf/unsimulated/mimic_edge/set_ambient_light(color, multiplier)
+ return
+/turf/unsimulated/mimic_edge/update_ambient_light(no_corner_update)
+ return
+/turf/unsimulated/mimic_edge/update_ambient_light_from_z()
+ return
+/turf/unsimulated/mimic_edge/lighting_build_overlay(now)
+ return
+
+////////////////////////////////
+// Exterior Mimic Edges
+////////////////////////////////
+
+///Exterior turf meant to replicate the appearence of another.
+/turf/exterior/mimic_edge
+ name = MIMIC_EDGE_NAME
+ desc = MIMIC_EDGE_DESC
+ icon = null
+ icon_state = null
+ density = FALSE
+ permit_ao = FALSE
+ blocks_air = TRUE
+ dynamic_lighting = FALSE
+
+ ///Mimicked turf's x position
+ var/mimic_x
+ ///Mimicked turf's y position
+ var/mimic_y
+ ///Mimicked turf's z position
+ var/mimic_z
+ ///Ref to the dummy overlay
+ var/obj/effect/overlay/click_bait/click_eater
+
+/turf/exterior/mimic_edge/Initialize(ml)
+ . = ..()
+ //Clear ourselves from the ambient queue
+ SSambience.queued -= src
+ //Need to put a mouse-opaque overlay there to prevent people turning/shooting towards ACTUAL location of vis_content things
+ click_eater = new(src)
+ setup_mimic()
+
+/turf/exterior/mimic_edge/Destroy()
+ QDEL_NULL(click_eater)
+ return ..()
+
+//Properly install itself, and allow overriding how the target turf is picked
+/turf/exterior/mimic_edge/proc/setup_mimic()
+ return
+
+/turf/exterior/mimic_edge/on_update_icon()
+ return
+
+/turf/exterior/mimic_edge/get_vis_contents_to_add()
+ . = ..()
+ var/turf/NT = mimic_x && mimic_y && mimic_z && locate(mimic_x, mimic_y, mimic_z)
+ if(NT)
+ opacity = NT.opacity
+ //log_debug("[src]([x],[y],[z]) mirroring [NT]([NT.x],[NT.y],[NT.z])")
+ LAZYADD(., NT)
+
+/turf/exterior/mimic_edge/proc/set_mimic_turf(var/_x, var/_y, var/_z)
+ mimic_z = _z? _z : z
+ mimic_x = _x
+ mimic_y = _y
+ refresh_vis_contents()
+
+//Prevent ambient completely, we're not a real turf
+/turf/exterior/mimic_edge/set_ambient_light(color, multiplier)
+ return
+/turf/exterior/mimic_edge/update_ambient_light(no_corner_update)
+ return
+/turf/exterior/mimic_edge/update_ambient_light_from_z()
+ return
+/turf/exterior/mimic_edge/lighting_build_overlay(now)
+ return
+
+////////////////////////////////
+// Transition Edges Shared
+////////////////////////////////
+
+///Returns the a cardinal direction for a turf on the map that's beyond the transition edge
+/proc/get_turf_transition_edge_direction(var/turf/T, var/datum/level_data/target_ldat)
+ var/within_west_transit = T.x < target_ldat.level_inner_min_x //Is the turf X within the west transition edge?
+ var/within_east_transit = T.x > target_ldat.level_inner_max_x //Is the turf X within the east transition edge?
+ var/within_south_transit = T.y < target_ldat.level_inner_min_y //Is the turf Y within the south transition edge?
+ var/within_north_transit = T.y > target_ldat.level_inner_max_y //Is the turf Y within the north transition edge?
+
+ //Filter out corners, since we can't mimic those properly
+ if(within_west_transit && !within_south_transit && !within_north_transit)
+ return WEST
+ if(within_east_transit && !within_south_transit && !within_north_transit)
+ return EAST
+ if(within_south_transit && !within_west_transit && !within_east_transit)
+ return SOUTH
+ if(within_north_transit && !within_west_transit && !within_east_transit)
+ return NORTH
+
+ //Corners return null
+ return null
+
+/// Returns the turf that's opposite to the specified turf, on the level specified.
+/proc/shared_transition_edge_get_coordinates_turf_to_mimic(var/turf/T, var/datum/level_data/target_ldat)
+ var/translate_from_dir = get_turf_transition_edge_direction(T, target_ldat)
+ if(isnull(translate_from_dir))
+ //In this case we're in the corners of the map. We shouldn't mimic.
+ log_warning("Transition turf '[T]' at ([T.x], [T.y], [T.z]) was in a corner of the map. That's likely a mistake, since we can't mimic corners properly!")
+ return list(T.x, T.y, T.z)
+
+ var/newx = T.x
+ var/newy = T.y
+ switch(translate_from_dir)
+ if(NORTH)
+ newy = (target_ldat.level_inner_min_y - 1) + (T.y - target_ldat.level_inner_max_y) //The level_inner coords are inclusive, so we need to +- 1
+ if(SOUTH)
+ newy = (target_ldat.level_inner_max_y + 1) - (target_ldat.level_inner_min_y - T.y)
+ if(EAST)
+ newx = (target_ldat.level_inner_min_x - 1) + (T.x - target_ldat.level_inner_max_x)
+ if(WEST)
+ newx = (target_ldat.level_inner_max_x + 1) - (target_ldat.level_inner_min_x - T.x)
+
+ return list(newx, newy, target_ldat.level_z)
+
+///Grab the connected level data for the level connected in the direction the 'T' turf is in.
+/proc/shared_transition_edge_get_valid_level_data(var/turf/T)
+ var/datum/level_data/LD = SSmapping.levels_by_z[T.z]
+ var/edge_dir = get_turf_transition_edge_direction(T, LD)
+ var/connected_lvl_id = LD.get_connected_level_id(edge_dir)
+ if(!connected_lvl_id)
+ var/dirname = dir2text(edge_dir)
+ CRASH("Got transition_edge turf '[T]' ([T.x], [T.y], [T.z]), in direction '[dirname]', but there is no connections in level_data '[LD]' for '[dirname]'!")
+ return SSmapping.levels_by_id[connected_lvl_id]
+
+///Handles teleporting an atom that touches a transition edge/loop edge.
+/proc/shared_transition_edge_bumped(var/turf/T, var/atom/movable/AM, var/mimic_z)
+ var/datum/level_data/LDsrc = SSmapping.levels_by_z[T.z]
+ var/datum/level_data/LDdst = SSmapping.levels_by_z[mimic_z]
+ var/new_x = AM.x
+ var/new_y = AM.y
+
+ //Get the position inside the destination level's bounds to teleport the thing to
+ if(T.x <= LDsrc.level_inner_min_x)
+ new_x = LDdst.level_inner_max_x
+ else if (T.x >= LDsrc.level_inner_max_x)
+ new_x = LDdst.level_inner_min_x
+ else if (T.y <= LDsrc.level_inner_min_y)
+ new_y = LDdst.level_inner_max_y
+ else if (T.y >= LDsrc.level_inner_max_y)
+ new_y = LDdst.level_inner_min_y
+ else
+ return //If we're teleporting into the same spot just quit early
+
+ //Teleport to the turf
+ var/turf/dest = locate(new_x, new_y, mimic_z)
+ if(!dest)
+ CRASH("Turf '[T]' failed to teleport '[AM]' to [new_x], [new_y], [mimic_z]. Couldn't locate turf!")
+ if(dest.density)
+ return //If the target turf is dense, just siltently do nothing.
+
+ AM.forceMove(dest)
+ //Move grabbed things
+ if(isliving(AM))
+ var/mob/living/L = AM
+ for(var/obj/item/grab/G in L.get_active_grabs())
+ G.affecting.forceMove(dest)
+
+////////////////////////////////
+// Transition Edges
+////////////////////////////////
+
+///When soemthing touches this turf, it gets transported to the connected level matching the direction of the edge on the map
+/turf/simulated/mimic_edge/transition/setup_mimic()
+ var/list/coord = shared_transition_edge_get_coordinates_turf_to_mimic(src, shared_transition_edge_get_valid_level_data(src))
+ set_mimic_turf(coord[1], coord[2], coord[3])
+/turf/simulated/mimic_edge/transition/Entered(atom/movable/AM, atom/old_loc)
+ . = ..()
+ if(!AM.simulated || AM.anchored || istype(AM, /obj/effect/overlay))
+ return
+ if(istype(AM, /obj/effect/projectile)) //#FIXME: Once we support projectiles going through levels properly remove this
+ return
+ shared_transition_edge_bumped(src, AM, mimic_z)
+
+/turf/unsimulated/mimic_edge/transition/setup_mimic()
+ var/list/coord = shared_transition_edge_get_coordinates_turf_to_mimic(src, shared_transition_edge_get_valid_level_data(src))
+ set_mimic_turf(coord[1], coord[2], coord[3])
+/turf/unsimulated/mimic_edge/transition/Entered(atom/movable/AM, atom/old_loc)
+ . = ..()
+ if(!AM.simulated || AM.anchored || istype(AM, /obj/effect/overlay))
+ return
+ if(istype(AM, /obj/effect/projectile)) //#FIXME: Once we support projectiles going through levels properly remove this
+ return
+ shared_transition_edge_bumped(src, AM, mimic_z)
+
+/turf/exterior/mimic_edge/transition/setup_mimic()
+ var/list/coord = shared_transition_edge_get_coordinates_turf_to_mimic(src, shared_transition_edge_get_valid_level_data(src))
+ set_mimic_turf(coord[1], coord[2], coord[3])
+/turf/exterior/mimic_edge/transition/Entered(atom/movable/AM, atom/old_loc)
+ . = ..()
+ if(!AM.simulated || AM.anchored || istype(AM, /obj/effect/overlay))
+ return
+ if(istype(AM, /obj/effect/projectile)) //#FIXME: Once we support projectiles going through levels properly remove this
+ return
+ shared_transition_edge_bumped(src, AM, mimic_z)
+
+////////////////////////////////
+// Loop Edges
+////////////////////////////////
+
+///When something touches this turf, it gets transported to the symmetrically opposite turf it's mimicking.
+/turf/simulated/mimic_edge/transition/loop/set_mimic_turf(_x, _y, _z)
+ . = ..(_x, _y)
+/turf/simulated/mimic_edge/transition/loop/setup_mimic()
+ var/list/coord = shared_transition_edge_get_coordinates_turf_to_mimic(src, SSmapping.levels_by_z[src.z])
+ set_mimic_turf(coord[1], coord[2], coord[3])
+
+/turf/unsimulated/mimic_edge/transition/loop/set_mimic_turf(_x, _y, _z)
+ . = ..(_x, _y)
+/turf/unsimulated/mimic_edge/transition/loop/setup_mimic()
+ var/list/coord = shared_transition_edge_get_coordinates_turf_to_mimic(src, SSmapping.levels_by_z[src.z])
+ set_mimic_turf(coord[1], coord[2], coord[3])
+
+/turf/exterior/mimic_edge/transition/loop/set_mimic_turf(_x, _y, _z)
+ . = ..(_x, _y)
+/turf/exterior/mimic_edge/transition/loop/setup_mimic()
+ var/list/coord = shared_transition_edge_get_coordinates_turf_to_mimic(src, SSmapping.levels_by_z[src.z])
+ set_mimic_turf(coord[1], coord[2], coord[3])
+
+#undef MIMIC_EDGE_NAME
+#undef MIMIC_EDGE_DESC
\ No newline at end of file
diff --git a/code/modules/overmap/_overmap.dm b/code/modules/overmap/_overmap.dm
index e13d9884286..bb91f801571 100644
--- a/code/modules/overmap/_overmap.dm
+++ b/code/modules/overmap/_overmap.dm
@@ -9,7 +9,7 @@
var/overmap_edge_type = /turf/unsimulated/map/edge
var/overmap_turf_type = /turf/unsimulated/map
var/overmap_area_type = /area/overmap
- var/empty_level_type = /obj/abstract/level_data/space
+ var/empty_level_type = /datum/level_data/space
var/list/valid_event_types
@@ -56,7 +56,7 @@
/datum/overmap/proc/generate_overmap()
testing("Building overmap [name]...")
- SSmapping.increment_world_z_size(/obj/abstract/level_data/overmap)
+ SSmapping.increment_world_z_size(/datum/level_data/overmap)
assigned_z = world.maxz
testing("Putting [name] on [assigned_z].")
populate_overmap()
@@ -143,8 +143,8 @@
return res
// Create a new one.
- var/obj/abstract/level_data/level = SSmapping.increment_world_z_size(empty_level_type)
- return new /obj/effect/overmap/visitable/sector/temporary(null, x, y, level.my_z)
+ var/datum/level_data/level = SSmapping.increment_world_z_size(empty_level_type)
+ return new /obj/effect/overmap/visitable/sector/temporary(null, x, y, level.level_z)
/datum/overmap/proc/discard_temporary_sector(var/obj/effect/overmap/visitable/sector/temporary/sector)
if(!length(cached_temporary_sectors[empty_level_type]))
diff --git a/code/modules/overmap/exoplanets/_exoplanet.dm b/code/modules/overmap/exoplanets/_exoplanet.dm
index de817dc4ee1..87fe9e379a9 100644
--- a/code/modules/overmap/exoplanets/_exoplanet.dm
+++ b/code/modules/overmap/exoplanets/_exoplanet.dm
@@ -110,7 +110,8 @@
var/planet_name = generate_planet_name()
SetName("[planet_name], \a [name]")
- planetary_area = new planetary_area()
+ if(ispath(planetary_area))
+ planetary_area = new planetary_area()
global.using_map.area_purity_test_exempt_areas += planetary_area.type
planetary_area.SetName("Surface of [planet_name]")
@@ -173,13 +174,13 @@
update_daynight()
/obj/effect/overmap/visitable/sector/exoplanet/proc/update_daynight()
- var/obj/abstract/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
var/light = 0.1
if(!night)
light = level_data.ambient_light_level
for(var/turf/exterior/T in block(locate(daycolumn,1,min(map_z)),locate(daycolumn,maxy,max(map_z))))
if (light)
- T.set_ambient_light(COLOR_WHITE, light)
+ T.set_ambient_light(COLOR_WHITE, light) //#FIXME: Use the ambient color from the level!!
else
T.clear_ambient_light()
daycolumn++
@@ -221,7 +222,7 @@
spawned_features = seed_ruins(map_z, features_budget, /area/exoplanet, possible_features, maxx, maxy)
/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_daycycle()
- var/obj/abstract/level_data/level_data = zlevels[1]
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
if(level_data.ambient_light_level)
night = FALSE //we start with a day if we have light.
@@ -264,8 +265,8 @@
/obj/effect/overmap/visitable/sector/exoplanet/get_scan_data(mob/user)
. = ..()
var/list/extra_data = list("
")
- var/obj/abstract/level_data/level_data = zlevels[1]
- var/datum/gas_mixture/atmosphere = level_data.exterior_atmosphere
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
+ var/datum/gas_mixture/atmosphere = level_data.get_exterior_atmosphere()
if(atmosphere)
if(user.skill_check(SKILL_SCIENCE, SKILL_EXPERT) || user.skill_check(SKILL_ATMOS, SKILL_EXPERT))
var/list/gases = list()
diff --git a/code/modules/overmap/exoplanets/exoplanet_atmosphere.dm b/code/modules/overmap/exoplanets/exoplanet_atmosphere.dm
index 1e715e9cc3a..9e5e68095e5 100644
--- a/code/modules/overmap/exoplanets/exoplanet_atmosphere.dm
+++ b/code/modules/overmap/exoplanets/exoplanet_atmosphere.dm
@@ -10,13 +10,13 @@
//Skip fun gas gen for perfect terran worlds
if(habitability_class == HABITABILITY_IDEAL)
- for(var/obj/abstract/level_data/level_data in zlevels)
+ for(var/datum/level_data/level_data in zlevels)
level_data.exterior_atmos_temp = target_temp
level_data.exterior_atmosphere = list(
/decl/material/gas/oxygen = MOLES_O2STANDARD,
/decl/material/gas/nitrogen = MOLES_N2STANDARD
)
- level_data.setup_level_data()
+ level_data.setup_level_data() //#FIXME: That's not very nice! Calling this again, when it should have been called before?
return
var/total_moles = MOLES_CELLSTANDARD
@@ -90,7 +90,7 @@
for(var/g in gas_list)
var/adjusted_moles = gas_list[g] * target_moles / MOLES_CELLSTANDARD
set_gasmix[g] = adjusted_moles
- for(var/obj/abstract/level_data/level_data in zlevels)
+ for(var/datum/level_data/level_data in zlevels)
level_data.exterior_atmos_temp = target_temp
level_data.exterior_atmosphere = set_gasmix.Copy()
level_data.setup_level_data()
diff --git a/code/modules/overmap/exoplanets/exoplanet_fauna.dm b/code/modules/overmap/exoplanets/exoplanet_fauna.dm
index 2ede9f2f265..d3dac597b79 100644
--- a/code/modules/overmap/exoplanets/exoplanet_fauna.dm
+++ b/code/modules/overmap/exoplanets/exoplanet_fauna.dm
@@ -29,8 +29,8 @@
A.SetName("alien creature")
A.real_name = "alien creature"
A.verbs |= /mob/living/simple_animal/proc/name_species
- var/obj/abstract/level_data/level_data = zlevels[1]
- if(level_data.exterior_atmosphere)
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
+ if(level_data.get_exterior_atmosphere()) //Generates the atmos if uninitialized
//Set up gases for living things
var/list/all_gasses = decls_repository.get_decl_paths_of_subtype(/decl/material/gas)
if(!LAZYLEN(breathgas))
diff --git a/code/modules/overmap/exoplanets/exoplanet_flora.dm b/code/modules/overmap/exoplanets/exoplanet_flora.dm
index 2b5bed796ad..cc27c7fefe3 100644
--- a/code/modules/overmap/exoplanets/exoplanet_flora.dm
+++ b/code/modules/overmap/exoplanets/exoplanet_flora.dm
@@ -1,9 +1,9 @@
//Generates initial generic alien plants
/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_flora()
- var/obj/abstract/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
- var/datum/gas_mixture/atmosphere = level_data?.get_exterior_atmosphere()
- var/temperature = atmosphere?.temperature || T20C
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
+ var/datum/gas_mixture/atmos = level_data.get_exterior_atmosphere() //#FIXME: Replace once exoplanet gen is merged
+ var/temperature = atmos?.temperature || T20C
for(var/i = 1 to flora_diversity)
var/datum/seed/S = new()
@@ -44,8 +44,8 @@
//Adapts seeds to this planet's atmopshere. Any special planet-speicific adaptations should go here too
/obj/effect/overmap/visitable/sector/exoplanet/proc/adapt_seed(var/datum/seed/S)
- var/obj/abstract/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
- var/datum/gas_mixture/atmosphere = level_data?.get_exterior_atmosphere()
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
+ var/datum/gas_mixture/atmosphere = level_data?.get_exterior_atmosphere() //#FIXME: Replace once exoplanet gen is merged
var/atmosphere_temperature = atmosphere?.temperature || T20C
var/atmosphere_pressure = atmosphere?.return_pressure() || 0
diff --git a/code/modules/overmap/exoplanets/exoplanet_skybox.dm b/code/modules/overmap/exoplanets/exoplanet_skybox.dm
index cd4f02c22b2..76b5ad99ce1 100644
--- a/code/modules/overmap/exoplanets/exoplanet_skybox.dm
+++ b/code/modules/overmap/exoplanets/exoplanet_skybox.dm
@@ -21,9 +21,9 @@
water.transform = water.transform.Turn(rand(0,360))
skybox_image.overlays += water
- var/obj/abstract/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
- var/datum/gas_mixture/atmosphere = level_data?.get_exterior_atmosphere()
- if(atmosphere?.return_pressure() > SOUND_MINIMUM_PRESSURE)
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
+ var/datum/gas_mixture/atmos = level_data.get_exterior_atmosphere()
+ if(atmos?.return_pressure() > SOUND_MINIMUM_PRESSURE)
var/atmo_color = get_atmosphere_color()
if(!atmo_color)
@@ -64,9 +64,9 @@
/obj/effect/overmap/visitable/sector/exoplanet/proc/get_atmosphere_color()
var/list/colors = list()
- for(var/Z in map_z)
- var/obj/abstract/level_data/level_data = SSmapping.levels_by_z[Z]
- for(var/g in level_data.exterior_atmosphere?.gas)
+ for(var/datum/level_data/level_data in zlevels)
+ var/datum/gas_mixture/atmos = level_data.get_exterior_atmosphere()
+ for(var/g in atmos?.gas)
var/decl/material/mat = GET_DECL(g)
colors += mat.color
if(colors.len)
diff --git a/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm b/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm
index 3ac6e115cbf..0d97a94343d 100644
--- a/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm
+++ b/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm
@@ -3,7 +3,7 @@
/datum/exoplanet_theme/radiation_bombing/adjust_atmosphere(obj/effect/overmap/visitable/sector/exoplanet/E)
var/add_temp = rand(20, 100)
- for(var/obj/abstract/level_data/level_data in E.zlevels)
+ for(var/datum/level_data/level_data in E.zlevels)
level_data.exterior_atmos_temp += add_temp
if(level_data.exterior_atmosphere)
level_data.exterior_atmosphere.temperature = level_data.exterior_atmos_temp
diff --git a/code/modules/overmap/exoplanets/planet_types/chlorine.dm b/code/modules/overmap/exoplanets/planet_types/chlorine.dm
index 958e6bfa843..e0e251580fb 100644
--- a/code/modules/overmap/exoplanets/planet_types/chlorine.dm
+++ b/code/modules/overmap/exoplanets/planet_types/chlorine.dm
@@ -23,7 +23,7 @@
return "#e5f2bd"
/obj/effect/overmap/visitable/sector/exoplanet/chlorine/generate_map()
- var/obj/abstract/level_data/level_data = zlevels[1]
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
if(prob(50))
level_data.ambient_light_level = rand(7,10)/10 //It could be night.
else
diff --git a/code/modules/overmap/exoplanets/planet_types/desert.dm b/code/modules/overmap/exoplanets/planet_types/desert.dm
index 63fab9ef8a1..d6097859d37 100644
--- a/code/modules/overmap/exoplanets/planet_types/desert.dm
+++ b/code/modules/overmap/exoplanets/planet_types/desert.dm
@@ -18,7 +18,7 @@
/obj/effect/overmap/visitable/sector/exoplanet/desert/generate_map()
if(prob(70))
- var/obj/abstract/level_data/level_data = zlevels[1]
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
level_data.ambient_light_level = rand(5,10)/10 //deserts are usually :lit:
..()
diff --git a/code/modules/overmap/exoplanets/planet_types/grass.dm b/code/modules/overmap/exoplanets/planet_types/grass.dm
index cef84c64384..c4a3b23e5be 100644
--- a/code/modules/overmap/exoplanets/planet_types/grass.dm
+++ b/code/modules/overmap/exoplanets/planet_types/grass.dm
@@ -12,7 +12,7 @@
/obj/effect/overmap/visitable/sector/exoplanet/grass/generate_map()
if(prob(40))
- var/obj/abstract/level_data/level_data = zlevels[1]
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
level_data.ambient_light_level = rand(1,7)/10 //give a chance of twilight jungle
..()
diff --git a/code/modules/overmap/exoplanets/planet_types/meat.dm b/code/modules/overmap/exoplanets/planet_types/meat.dm
index d2043b862b9..dbda6ece5ac 100644
--- a/code/modules/overmap/exoplanets/planet_types/meat.dm
+++ b/code/modules/overmap/exoplanets/planet_types/meat.dm
@@ -19,7 +19,7 @@
spawn_weight = 10 // meat
/obj/effect/overmap/visitable/sector/exoplanet/meat/generate_map()
- var/obj/abstract/level_data/level_data = zlevels[1]
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
level_data.ambient_light_level = rand(1,7)/10
..()
diff --git a/code/modules/overmap/exoplanets/planet_types/shrouded.dm b/code/modules/overmap/exoplanets/planet_types/shrouded.dm
index 2e5bb86845d..0d722680658 100644
--- a/code/modules/overmap/exoplanets/planet_types/shrouded.dm
+++ b/code/modules/overmap/exoplanets/planet_types/shrouded.dm
@@ -20,7 +20,7 @@
// TODO check if ambient lighting handles negatives
/obj/effect/overmap/visitable/sector/exoplanet/meat/generate_map()
- var/obj/abstract/level_data/level_data = zlevels[1]
+ var/datum/level_data/level_data = SSmapping.levels_by_z[map_z[1]]
level_data.ambient_light_level = -0.15
..()
diff --git a/code/modules/overmap/exoplanets/random_map.dm b/code/modules/overmap/exoplanets/random_map.dm
index d95a3c36c78..64fa3ada0e5 100644
--- a/code/modules/overmap/exoplanets/random_map.dm
+++ b/code/modules/overmap/exoplanets/random_map.dm
@@ -37,7 +37,6 @@
plantcolors = _plant_colors
..()
- SSmapping.base_turf_by_z[tz] = land_type
/datum/random_map/noise/exoplanet/get_map_char(var/value)
if(water_type && noise2value(value) < water_level)
diff --git a/code/modules/overmap/ships/landable.dm b/code/modules/overmap/ships/landable.dm
index d0e2689fa6d..ae526becd47 100644
--- a/code/modules/overmap/ships/landable.dm
+++ b/code/modules/overmap/ships/landable.dm
@@ -9,7 +9,7 @@
var/use_mapped_z_levels = FALSE // If true, it will use the z level block on which it's mapped as the "Open Space" block; if false it creates a new block for that.
// If you use this, use /obj/effect/shuttle_landmark/ship as the landmark (set the landmark tag to match on the shuttle; no other setup needed)
var/status = SHIP_STATUS_LANDED
- var/level_type = /obj/abstract/level_data/space
+ var/level_type = /datum/level_data/space
icon_state = "shuttle"
moving_state = "shuttle_moving"
diff --git a/code/modules/power/geothermal/_geothermal.dm b/code/modules/power/geothermal/_geothermal.dm
index f6db7a6e433..9cad5e8ccd0 100644
--- a/code/modules/power/geothermal/_geothermal.dm
+++ b/code/modules/power/geothermal/_geothermal.dm
@@ -1,24 +1,86 @@
var/global/const/GEOTHERMAL_EFFICIENCY_MOD = 0.2
var/global/const/GEOTHERMAL_PRESSURE_LOSS = 0.3
-var/global/const/GEOTHERMAL_PRESSURE_CONSUMED_PER_TICK = 0.5
-var/global/const/GEOTHERMAL_PRESSURE_TO_POWER = 100
-var/global/const/MAX_GEOTHERMAL_PRESSURE = 2000
+var/global/const/GEOTHERMAL_PRESSURE_CONSUMED_PER_TICK = 0.05
+var/global/const/GEOTHERMAL_PRESSURE_TO_POWER = 800
+var/global/const/MAX_GEOTHERMAL_PRESSURE = 12000
+//////////////////////////////////////////////////////////////////////
+// Geyser Steam Particle Emitter
+//////////////////////////////////////////////////////////////////////
+
+///Particle emitter that emits a ~64 pixels by ~192 pixels high column of steam while active.
+/particles/geyser_steam
+ icon_state = "smallsmoke"
+ icon = 'icons/effects/effects.dmi'
+ width = WORLD_ICON_SIZE * 2 //Particles expand a bit as they climb, so need a bit of space on the width
+ height = WORLD_ICON_SIZE * 6 //Needs to be really tall, because particles stop being drawn outside of the canvas.
+ count = 64
+ spawning = 5
+ lifespan = generator("num", 1 SECOND, 2.5 SECONDS, LINEAR_RAND)
+ fade = 3 SECONDS
+ fadein = 0.25 SECONDS
+ grow = 0.1
+ velocity = generator("vector", list(0, 0), list(0, 0.2))
+ position = generator("circle", -6, 6, NORMAL_RAND)
+ gravity = list(0, 0.40)
+ scale = generator("vector", list(0.3, 0.3), list(1,1), NORMAL_RAND)
+ rotation = generator("num", -45, 45)
+ spin = generator("num", -20, 20)
+
+//////////////////////////////////////////////////////////////////////
+// Geyser Object
+//////////////////////////////////////////////////////////////////////
+
+///A prop that periodically emit steam spouts and can have a geothermal generator placed on top to generate power.
/obj/effect/geyser
- name = "geothermal vent"
- desc = "A crack in the ocean floor that occasionally vents gouts of superheated water and steam."
- icon = 'icons/effects/geyser.dmi'
+ name = "geothermal vent"
+ desc = "A vent leading to an underground geothermally heated reservoir, which periodically spews superheated liquid."
+ icon = 'icons/effects/geyser.dmi'
icon_state = "geyser"
- anchored = TRUE
- layer = TURF_LAYER + 0.01
+ anchored = TRUE
+ layer = TURF_LAYER + 0.01
+ level = 1 //Goes under floor/plating
+ ///The particle emitter that will generate the steam column effect for this geyser
+ var/particles/geyser_steam/steamfx
-/obj/effect/geyser/Initialize()
+/obj/effect/geyser/Initialize(ml)
. = ..()
if(prob(50))
var/matrix/M = matrix()
M.Scale(-1, 1)
transform = M
set_extension(src, /datum/extension/geothermal_vent)
+ steamfx = new //Prepare our FX
+
+///Async proc that enables the particle emitter for the steam column for a few seconds
+/obj/effect/geyser/proc/do_spout()
+ set waitfor = FALSE
+ particles = steamfx
+ particles.spawning = initial(particles.spawning)
+ sleep(6 SECONDS)
+ particles.spawning = 0
+
+/obj/effect/geyser/explosion_act(severity)
+ . = ..()
+ if(!QDELETED(src) && prob(100 - (25 * severity)))
+ physically_destroyed()
+
+/obj/effect/geyser/hide(hide)
+ var/datum/extension/geothermal_vent/E = get_extension(src, /datum/extension/geothermal_vent)
+ if(istype(E))
+ E.set_obstructed(hide)
+ . = ..()
+ update_icon()
+
+//////////////////////////////////////////////////////////////////////
+// Underwater Geyser Variant
+//////////////////////////////////////////////////////////////////////
+
+/obj/effect/geyser/underwater
+ desc = "A crack in the ocean floor that occasionally vents gouts of superheated water and steam."
+
+/obj/effect/geyser/underwater/Initialize(ml)
+ . = ..()
for(var/turf/exterior/seafloor/T in RANGE_TURFS(loc, 5))
var/dist = get_dist(loc, T)-1
if(prob(100 - (dist * 20)))
@@ -26,43 +88,125 @@ var/global/const/MAX_GEOTHERMAL_PRESSURE = 2000
if(prob(50 - (dist * 10)))
new /obj/random/seaweed(T)
-/obj/effect/geyser/explosion_act(severity)
- . = ..()
- if(!QDELETED(src) && prob(100 - (25 * severity)))
- physically_destroyed()
+/obj/effect/geyser/underwater/do_spout()
+ set waitfor = FALSE
+ var/turf/T = get_turf(src)
+ T.show_bubbles()
+//////////////////////////////////////////////////////////////////////
+// Geothermal Generator
+//////////////////////////////////////////////////////////////////////
+
+///A power generator that can create power from being placed on top of a geyser.
/obj/machinery/geothermal
- icon = 'icons/obj/machines/power/geothermal.dmi'
- icon_state = "geothermal-base"
- var/tmp/neighbors = 0
- var/tmp/current_pressure = 0
- var/efficiency = 0.5
+ name = "geothermal generator"
+ icon = 'icons/obj/machines/power/geothermal.dmi'
+ icon_state = "geothermal-base"
+ density = TRUE
+ anchored = TRUE
+ waterproof = TRUE
+ interact_offline = TRUE
+ stat_immune = NOSCREEN | NOINPUT | NOPOWER
+ core_skill = SKILL_ENGINES
+ required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES
+ construct_state = /decl/machine_construction/default/panel_closed
+ uncreated_component_parts = list(
+ /obj/item/stock_parts/power/terminal,
+ )
+ stock_part_presets = list(
+ /decl/stock_part_preset/terminal_setup/offset_dir,
+ )
+ var/tmp/neighbors = 0
+ var/tmp/current_pressure = 0
+ var/tmp/efficiency = 0.5
+ var/tmp/last_generated = 0
+ var/tmp/datum/extension/geothermal_vent/vent
+ var/tmp/obj/item/stock_parts/power/terminal/connector
+ var/tmp/image/glow
+ var/tmp/list/neighbor_connectors
+ var/tmp/list/neighbor_connectors_glow
+
+//#TODO: Maybe should cache neighbors and put listeners on them?
+
+/obj/machinery/geothermal/Initialize(mapload, d, populate_parts = TRUE)
+ . = ..()
+ if(get_turf(loc))
+ refresh_neighbors()
+ propagate_refresh_neighbors()
+ STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF)
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/machinery/geothermal/LateInitialize()
+ . = ..()
+ setup_vent()
+
+/obj/machinery/geothermal/Destroy()
+ var/atom/last_loc = loc
+ unset_vent()
+ . = ..()
+ if(istype(last_loc))
+ propagate_refresh_neighbors(last_loc)
+
+///Tell all neighbors of the center atom to call update neighbors
+/obj/machinery/geothermal/proc/propagate_refresh_neighbors(var/atom/center = src)
+ for(var/adir in global.alldirs)
+ var/obj/machinery/geothermal/G = locate(/obj/machinery/geothermal) in get_step(center, adir)
+ if(G?.anchored)
+ G.refresh_neighbors()
+
+/obj/machinery/geothermal/examine(mob/user, distance)
+ . = ..()
+ if(distance < 2)
+ to_chat(user, SPAN_INFO("Pressure: [current_pressure]kPa"))
+ to_chat(user, SPAN_INFO("Output: [last_generated]W"))
+
+///Attempts to connect to any existing geothermal vents in our turf.
+/obj/machinery/geothermal/proc/setup_vent()
+ var/turf/T = get_turf(src)
+ for(var/obj/O in T)
+ var/datum/extension/geothermal_vent/GV = get_extension(O, /datum/extension/geothermal_vent)
+ if(!GV || QDELETED(GV))
+ continue
+ vent = GV
+ vent.set_my_generator(src)
+ return TRUE
+
+///Disconnect from any geothermal vents we may be connected to
+/obj/machinery/geothermal/proc/unset_vent()
+ if(QDELETED(vent))
+ return
+ vent.set_my_generator(null)
+ vent = null
/obj/machinery/geothermal/RefreshParts()
..()
efficiency = clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor) * GEOTHERMAL_EFFICIENCY_MOD, GEOTHERMAL_EFFICIENCY_MOD, 1)
+ connector = get_component_of_type(/obj/item/stock_parts/power/terminal)
/obj/machinery/geothermal/proc/add_pressure(var/pressure)
current_pressure = clamp(current_pressure + pressure, 0, MAX_GEOTHERMAL_PRESSURE)
- if(!is_processing)
- START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF)
+ var/leftover = round(pressure - current_pressure)
+ if(leftover > 0)
+ addtimer(CALLBACK(src, .proc/propagate_pressure, leftover), 5)
+ update_icon()
+ START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF)
/obj/machinery/geothermal/Process()
- if(anchored && !(stat & BROKEN) && loc)
+ if(loc && anchored && !(stat & BROKEN))
var/consumed_pressure = current_pressure * GEOTHERMAL_PRESSURE_CONSUMED_PER_TICK
current_pressure -= consumed_pressure
var/remaining_pressure = consumed_pressure
- consumed_pressure = round(consumed_pressure * efficiency)
+ consumed_pressure = round(consumed_pressure * efficiency, 0.01)
remaining_pressure -= consumed_pressure
- var/generated_power = round(consumed_pressure * GEOTHERMAL_PRESSURE_TO_POWER)
- if(generated_power)
- generate_power(generated_power)
+ last_generated = round(consumed_pressure * GEOTHERMAL_PRESSURE_TO_POWER, 0.01)
+ if(last_generated)
+ generate_power(last_generated)
remaining_pressure = round(remaining_pressure * GEOTHERMAL_PRESSURE_LOSS)
if(remaining_pressure)
addtimer(CALLBACK(src, .proc/propagate_pressure, remaining_pressure), 5)
update_icon()
- if(current_pressure <= 10)
+ if(current_pressure <= 1)
return PROCESS_KILL
/obj/machinery/geothermal/proc/propagate_pressure(var/remaining_pressure)
@@ -86,46 +230,41 @@ var/global/const/MAX_GEOTHERMAL_PRESSURE = 2000
if(last_neighbors != neighbors)
update_icon()
-/obj/machinery/geothermal/Initialize()
- . = ..()
- refresh_neighbors()
- for(var/turf/T as anything in RANGE_TURFS(loc, 1))
- for(var/obj/machinery/geothermal/neighbor in T)
- neighbor.refresh_neighbors()
- STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF)
-
-/obj/machinery/geothermal/Destroy()
- var/atom/last_loc = loc
- . = ..()
- if(istype(last_loc))
- for(var/turf/T as anything in RANGE_TURFS(last_loc, 1))
- for(var/obj/machinery/geothermal/neighbor in T)
- neighbor.refresh_neighbors()
-
/obj/machinery/geothermal/on_update_icon()
-
- . = ..()
-
cut_overlays()
+ var/output_ratio = current_pressure / 3000
+ var/glow_alpha = clamp(round((current_pressure / MAX_GEOTHERMAL_PRESSURE) * 255), 10, 255)
+ if(!glow)
+ glow = emissive_overlay(icon, "geothermal-glow")
+ if(!length(neighbor_connectors))
+ for(var/neighbordir in global.cardinal)
+ LAZYSET(neighbor_connectors, "[neighbordir]", image(icon, "geothermal-connector", dir = neighbordir))
+ LAZYSET(neighbor_connectors_glow, "[neighbordir]", image(icon, "geothermal-connector-glow", dir = neighbordir))
if(neighbors)
for(var/neighbordir in global.cardinal)
if(neighbors & neighbordir)
- add_overlay(image(icon, "geothermal-connector", dir = neighbordir))
-
- if(current_pressure > 0)
- set_light(2, 0.5, COLOR_RED)
- add_overlay(image(icon, "geothermal-turbine-[clamp(round(current_pressure / 200), 0, 3)]"))
- var/glow_alpha = clamp(round((current_pressure / 500) * 255), 20, 255)
- var/image/I = emissive_overlay(icon, "geothermal-glow")
- I.alpha = glow_alpha
- add_overlay(I)
- if(neighbors)
- for(var/neighbordir in global.cardinal)
- if(neighbors & neighbordir)
- // emissive_overlay is not setting dir and setting plane/layer directly also causes dir to break :(
- I = image(icon, "geothermal-connector-glow", dir = neighbordir)
- I.alpha = glow_alpha
- add_overlay(I)
- else
+ add_overlay(neighbor_connectors["[neighbordir]"])
+ // emissive_overlay is not setting dir and setting plane/layer directly also causes dir to break :(
+ var/image/neighborglow = neighbor_connectors_glow["[neighbordir]"]
+ neighborglow.alpha = glow_alpha
+ add_overlay(neighborglow)
+
+ if(round(current_pressure, 0.1) <= 0)
set_light(0)
+ return
+
+ set_light(1, clamp(output_ratio, 0.2, 1.0), COLOR_RED)
+ add_overlay("geothermal-turbine-[clamp(round(output_ratio * 3), 0, 3)]")
+ glow.alpha = glow_alpha
+ add_overlay(glow)
+
+/obj/machinery/geothermal/dismantle()
+ . = ..()
+ unset_vent()
+
+/obj/machinery/geothermal/get_powernet()
+ return connector?.terminal?.get_powernet()
+
+/obj/machinery/geothermal/drain_power()
+ return -1
\ No newline at end of file
diff --git a/code/modules/power/geothermal/geothermal_circuit.dm b/code/modules/power/geothermal/geothermal_circuit.dm
index 2b34cbf2224..07d451d68fa 100644
--- a/code/modules/power/geothermal/geothermal_circuit.dm
+++ b/code/modules/power/geothermal/geothermal_circuit.dm
@@ -1,5 +1,5 @@
/obj/item/stock_parts/circuitboard/geothermal
- name = "circuitboard (geothermal turbine)"
+ name = "circuitboard (geothermal generator)"
build_path = /obj/machinery/geothermal
board_type = "machine"
origin_tech = "{'magnets':3,'powerstorage':3}"
@@ -8,3 +8,4 @@
/obj/item/stock_parts/manipulator = 2,
/obj/item/stack/cable_coil = 5
)
+ additional_spawn_components = null
diff --git a/code/modules/power/geothermal/geothermal_extension.dm b/code/modules/power/geothermal/geothermal_extension.dm
index 3eef52c7075..0d734d38116 100644
--- a/code/modules/power/geothermal/geothermal_extension.dm
+++ b/code/modules/power/geothermal/geothermal_extension.dm
@@ -1,34 +1,45 @@
/datum/extension/geothermal_vent
base_type = /datum/extension/geothermal_vent
- expected_type = /atom
+ expected_type = /obj/effect/geyser
flags = EXTENSION_FLAG_IMMEDIATE
var/pressure_min = 1000
var/pressure_max = 2000
- var/steam_min = 30 SECONDS
- var/steam_max = 1 MINUTE
+ var/steam_min = 20 SECONDS
+ var/steam_max = 60 SECONDS
var/tmp/next_steam = 0
- var/datum/effect/effect/system/steam_spread/steam
+ var/tmp/obstructed = FALSE
+ var/obj/machinery/geothermal/my_machine
+ var/obj/effect/geyser/my_vent
-/datum/extension/geothermal_vent/New()
+/datum/extension/geothermal_vent/New(datum/holder)
..()
START_PROCESSING(SSprocessing, src)
+ my_vent = holder
/datum/extension/geothermal_vent/Destroy()
+ my_machine = null
+ my_vent = null
. = ..()
STOP_PROCESSING(SSprocessing, src)
-
+
+/datum/extension/geothermal_vent/proc/set_my_generator(var/obj/machinery/geothermal/G)
+ my_machine = G
+
+/datum/extension/geothermal_vent/proc/set_obstructed(var/state)
+ obstructed = state
+ if(obstructed)
+ STOP_PROCESSING(SSprocessing, src)
+ else
+ START_PROCESSING(SSprocessing, src)
+
/datum/extension/geothermal_vent/Process()
- ..()
+ if(obstructed && !my_machine) //If we have a machine, don't care about obstruction, or it might cause problems
+ return PROCESS_KILL
+
if(world.time >= next_steam)
next_steam = world.time + rand(steam_min, steam_max)
- var/turf/T = get_turf(holder)
- if(!istype(T))
- return
- var/obj/machinery/geothermal/geothermal = locate() in T
- if(geothermal?.anchored)
- geothermal.add_pressure(rand(pressure_min, pressure_max))
- return
- if(!steam)
- steam = new
- steam.set_up(5, 0, holder)
- steam.start()
+ //If we cached something, make it work
+ if(my_machine?.anchored)
+ my_machine.add_pressure(rand(pressure_min, pressure_max))
+ else
+ my_vent.do_spout() //Let the holder decide what to do when spewing steam
diff --git a/code/modules/projectiles/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm
index 090bd283b74..9eee66308bf 100644
--- a/code/modules/projectiles/ammunition/boxes.dm
+++ b/code/modules/projectiles/ammunition/boxes.dm
@@ -148,6 +148,10 @@
labels = list("flash")
ammo_type = /obj/item/ammo_casing/pistol/flash
+/obj/item/ammo_magazine/pistol/emp
+ labels = list("haywire")
+ ammo_type = /obj/item/ammo_casing/pistol/emp
+
/obj/item/ammo_magazine/pistol/small
icon_state = "holdout"
material = /decl/material/solid/metal/steel
@@ -243,6 +247,14 @@
max_ammo = 7
multiple_sprites = 1
+/obj/item/ammo_magazine/speedloader/rubber
+ labels = list("rubber")
+ ammo_type = /obj/item/ammo_casing/pistol/magnum/rubber
+
+/obj/item/ammo_magazine/speedloader/practice
+ labels = list("practice")
+ ammo_type = /obj/item/ammo_casing/pistol/magnum/practice
+
/obj/item/ammo_magazine/speedloader/laser_revolver
caliber = CALIBER_PISTOL_LASBULB
ammo_type = /obj/item/ammo_casing/lasbulb
diff --git a/code/modules/projectiles/ammunition/bullets.dm b/code/modules/projectiles/ammunition/bullets.dm
index 8f727a8132a..54f6374aecf 100644
--- a/code/modules/projectiles/ammunition/bullets.dm
+++ b/code/modules/projectiles/ammunition/bullets.dm
@@ -63,6 +63,28 @@
projectile_type = /obj/item/projectile/bullet/pistol/strong
icon = 'icons/obj/ammo/casings/magnum.dmi'
+/obj/item/ammo_casing/pistol/magnum/rubber
+ desc = "A rubber bullet casing."
+ projectile_type = /obj/item/projectile/bullet/pistol/rubber/strong
+ bullet_color = COLOR_GRAY40
+
+/obj/item/ammo_casing/pistol/magnum/practice
+ desc = "A practice bullet casing."
+ projectile_type = /obj/item/projectile/bullet/pistol/practice
+ bullet_color = COLOR_OFF_WHITE
+ marking_color = COLOR_SUN
+
+/obj/item/ammo_casing/pistol/magnum/stun
+ name = "stun round"
+ desc = "An energy stun cartridge."
+ icon_state = "stunshell"
+ spent_icon = "stunshell-spent"
+ projectile_type = /obj/item/projectile/energy/electrode/stunshot
+ leaves_residue = 0
+ material = /decl/material/solid/metal/steel
+ matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT)
+ origin_tech = "{'combat':3,'materials':3}"
+
/obj/item/ammo_casing/shotgun
name = "shotgun slug"
desc = "A shotgun slug."
diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm
index 6122670a859..71f69f05964 100644
--- a/code/modules/projectiles/guns/projectile/pistol.dm
+++ b/code/modules/projectiles/guns/projectile/pistol.dm
@@ -12,6 +12,9 @@
/obj/item/gun/projectile/pistol/rubber
magazine_type = /obj/item/ammo_magazine/pistol/rubber
+/obj/item/gun/projectile/pistol/emp
+ magazine_type = /obj/item/ammo_magazine/pistol/emp
+
/obj/item/gun/projectile/pistol/update_base_icon()
var/base_state = get_world_inventory_state()
if(!length(ammo_magazine?.stored_ammo) && check_state_in_icon("[base_state]-e", icon))
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index 71ed2ce36a3..2fdf3b7c45e 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -41,6 +41,9 @@
chamber_offset = 0
return ..()
+/obj/item/gun/projectile/revolver/stun
+ ammo_type = /obj/item/ammo_casing/pistol/magnum/stun
+
/obj/item/gun/projectile/revolver/capgun
name = "cap gun"
desc = "Looks almost like the real thing! Ages 8 and up."
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 8b00d325258..c431df0db47 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -91,6 +91,10 @@
agony = 30
embed = 0
+/obj/item/projectile/bullet/pistol/rubber/strong
+ damage = 8
+ agony = 38
+
/obj/item/projectile/bullet/pistol/rubber/holdout
agony = 20
diff --git a/code/modules/shuttles/docking_beacon.dm b/code/modules/shuttles/docking_beacon.dm
index 37dcaa79577..abaac314379 100644
--- a/code/modules/shuttles/docking_beacon.dm
+++ b/code/modules/shuttles/docking_beacon.dm
@@ -312,13 +312,13 @@
break
area_turf = get_step(area_turf, dir)
- // Otherwise, use the planetary or world area.
+ // Otherwise, use the level or world area.
if(!base_area)
- var/obj/effect/overmap/visitable/sector/exoplanet/planet = global.overmap_sectors[num2text(z)]
- if(istype(planet))
- base_area = ispath(planet.planetary_area) ? planet.planetary_area : planet.planetary_area.type
+ var/datum/level_data/LD = SSmapping.levels_by_z[z]
+ if(istype(LD))
+ base_area = LD.get_base_area_instance()
else
- base_area = world.area
+ base_area = locate(world.area)
var/turf/center_turf
switch(dir)
diff --git a/code/unit_tests/atmospherics_tests.dm b/code/unit_tests/atmospherics_tests.dm
index 4dd84f63b92..20ab46c5c9a 100644
--- a/code/unit_tests/atmospherics_tests.dm
+++ b/code/unit_tests/atmospherics_tests.dm
@@ -381,7 +381,7 @@
var/fail = FALSE
// make a place to test
- SSmapping.increment_world_z_size(/obj/abstract/level_data/unit_test)
+ SSmapping.increment_world_z_size(/datum/level_data/unit_test)
for(var/turf/T in block(locate(1, 1, world.maxz), locate(3, 3, world.maxz)))
T.ChangeTurf(/turf/simulated/floor)
var/turf/T = locate(2, 2, world.maxz)
diff --git a/code/unit_tests/del_the_world.dm b/code/unit_tests/del_the_world.dm
index 6beea4343c7..bbe1cc41271 100644
--- a/code/unit_tests/del_the_world.dm
+++ b/code/unit_tests/del_the_world.dm
@@ -26,6 +26,8 @@
// Not valid when spawned manually.
/obj/effect/overmap,
/obj/effect/shuttle_landmark,
+ // Docking controllers can only exist once with a given id_tag in the world. And some subtypes are defined with an id_tag
+ /obj/machinery/embedded_controller/radio/simple_docking_controller,
) + list(
// Exclude only this type, since it's not meant to be spawned but its subtypes are.
// TODO: Consider whether this warrants abstract_type?
diff --git a/code/unit_tests/zlevel_tests.dm b/code/unit_tests/zlevel_tests.dm
index 0b33829fc27..5c6829802b0 100644
--- a/code/unit_tests/zlevel_tests.dm
+++ b/code/unit_tests/zlevel_tests.dm
@@ -4,7 +4,7 @@
/datum/unit_test/all_zlevels_will_have_a_non_filler_data_object/start_test()
var/list/failures = list()
for(var/z = 1 to world.maxz)
- var/obj/abstract/level_data/level_data = SSmapping.levels_by_z[z]
+ var/datum/level_data/level_data = SSmapping.levels_by_z[z]
if(!level_data)
failures += "z[z] has no level data object"
if(length(failures))
diff --git a/code/unit_tests/~unit_test_subsystems.dm b/code/unit_tests/~unit_test_subsystems.dm
index 57d1f69a19e..e199cb31454 100644
--- a/code/unit_tests/~unit_test_subsystems.dm
+++ b/code/unit_tests/~unit_test_subsystems.dm
@@ -44,6 +44,9 @@ SUBSYSTEM_DEF(unit_tests)
if(MAP_TEMPLATE_CATEGORY_AWAYSITE in map_template.template_categories)
report_progress("Skipping template '[map_template]' ([map_template.type]): Is an Away Site")
continue
+ if(MAP_TEMPLATE_CATEGORY_MAIN_SITE in map_template.template_categories)
+ report_progress("Skipping template '[map_template]' ([map_template.type]): Is a main site template.")
+ continue
load_template(map_template)
if(map_template.template_flags & TEMPLATE_FLAG_TEST_DUPLICATES)
load_template(map_template)
@@ -52,7 +55,7 @@ SUBSYSTEM_DEF(unit_tests)
/datum/controller/subsystem/unit_tests/proc/load_template(datum/map_template/map_template)
// Suggestion: Do smart things here to squeeze as many templates as possible into the same Z-level
if(map_template.tallness == 1)
- SSmapping.increment_world_z_size(/obj/abstract/level_data/unit_test)
+ SSmapping.increment_world_z_size(/datum/level_data/unit_test)
var/corner = locate(world.maxx/2, world.maxy/2, world.maxz)
log_unit_test("Loading template '[map_template]' ([map_template.type]) at [log_info_line(corner)]")
map_template.load(corner)
diff --git a/html/changelog.html b/html/changelog.html
index 90c8145dcd1..4aa45b15d62 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -88,6 +88,42 @@