diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 49b83b2d93..b16039568f 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -290,7 +290,14 @@
/atom/movable/proc/adjust_rotation(new_rotation)
icon_rotation = new_rotation
+<<<<<<< HEAD
update_transform()
+=======
+ update_transform()
+
+// Called when touching a lava tile.
+/atom/movable/proc/lava_act()
+ fire_act(null, 10000, 1000)
// Called when something changes z-levels.
/atom/movable/proc/on_z_change(old_z, new_z)
@@ -298,3 +305,4 @@
for(var/item in src) // Notify contents of Z-transition. This can be overriden IF we know the items contents do not care.
var/atom/movable/AM = item
AM.on_z_change(old_z, new_z)
+>>>>>>> afa149c... Adds New PoI Features + Bonus PoI (#5796)
diff --git a/code/game/objects/effects/map_effects/effect_emitter.dm b/code/game/objects/effects/map_effects/effect_emitter.dm
index 441ba957dd..d7086dafa6 100644
--- a/code/game/objects/effects/map_effects/effect_emitter.dm
+++ b/code/game/objects/effects/map_effects/effect_emitter.dm
@@ -1,78 +1,78 @@
-// Creates effects like smoke clouds every so often.
-/obj/effect/map_effect/interval/effect_emitter
- var/datum/effect/effect/system/effect_system = null
- var/effect_system_type = null // Which effect system to attach.
-
- var/effect_amount = 10 // How many effect objects to create on each interval. Note that there's a hard cap on certain effect_systems.
- var/effect_cardinals_only = FALSE // If true, effects only move in cardinal directions.
- var/effect_forced_dir = null // If set, effects emitted will always move in this direction.
-
-/obj/effect/map_effect/interval/effect_emitter/Initialize()
- effect_system = new effect_system_type()
- effect_system.attach(src)
- configure_effects()
- return ..()
-
-/obj/effect/map_effect/interval/effect_emitter/interval/Destroy()
- QDEL_NULL(effect_system)
- return ..()
-
-/obj/effect/map_effect/interval/effect_emitter/proc/configure_effects()
- effect_system.set_up(effect_amount, effect_cardinals_only, usr.loc, effect_forced_dir)
-
-/obj/effect/map_effect/interval/effect_emitter/trigger()
- configure_effects() // We do this every interval in case it changes.
- effect_system.start()
- ..()
-
-
-// Creates smoke clouds every so often.
-/obj/effect/map_effect/interval/effect_emitter/smoke
- name = "smoke emitter"
- icon_state = "smoke_emitter"
- effect_system_type = /datum/effect/effect/system/smoke_spread
-
- interval_lower_bound = 1 SECOND
- interval_upper_bound = 1 SECOND
- effect_amount = 2
-
-/obj/effect/map_effect/interval/effect_emitter/smoke/bad
- name = "bad smoke emitter"
- effect_system_type = /datum/effect/effect/system/smoke_spread/bad
-
-/obj/effect/map_effect/interval/effect_emitter/smoke/fire
- name = "fire smoke emitter"
- effect_system_type = /datum/effect/effect/system/smoke_spread/fire
-
-/obj/effect/map_effect/interval/effect_emitter/smoke/frost
- name = "frost smoke emitter"
- effect_system_type = /datum/effect/effect/system/smoke_spread/frost
-
-/obj/effect/map_effect/interval/effect_emitter/smoke/shock
- name = "shock smoke emitter"
- effect_system_type = /datum/effect/effect/system/smoke_spread/shock
-
-/obj/effect/map_effect/interval/effect_emitter/smoke/mist
- name = "mist smoke emitter"
- effect_system_type = /datum/effect/effect/system/smoke_spread/mist
-
-
-// Makes sparks.
-/obj/effect/map_effect/interval/effect_emitter/sparks
- name = "spark emitter"
- icon_state = "spark_emitter"
- effect_system_type = /datum/effect/effect/system/spark_spread
-
- interval_lower_bound = 3 SECONDS
- interval_upper_bound = 7 SECONDS
-
-/obj/effect/map_effect/interval/effect_emitter/sparks/frequent
- effect_amount = 4 // Otherwise it caps out fast.
- interval_lower_bound = 1
- interval_upper_bound = 3 SECONDS
-
-// Makes ""steam"" that looks like fire extinguisher water except it does nothing.
-/obj/effect/map_effect/interval/effect_emitter/steam
- name = "steam emitter"
- icon_state = "smoke_emitter"
- effect_system_type = /datum/effect/effect/system/steam_spread
+// Creates effects like smoke clouds every so often.
+/obj/effect/map_effect/interval/effect_emitter
+ var/datum/effect/effect/system/effect_system = null
+ var/effect_system_type = null // Which effect system to attach.
+
+ var/effect_amount = 10 // How many effect objects to create on each interval. Note that there's a hard cap on certain effect_systems.
+ var/effect_cardinals_only = FALSE // If true, effects only move in cardinal directions.
+ var/effect_forced_dir = null // If set, effects emitted will always move in this direction.
+
+/obj/effect/map_effect/interval/effect_emitter/Initialize()
+ effect_system = new effect_system_type()
+ effect_system.attach(src)
+ configure_effects()
+ return ..()
+
+/obj/effect/map_effect/interval/effect_emitter/interval/Destroy()
+ QDEL_NULL(effect_system)
+ return ..()
+
+/obj/effect/map_effect/interval/effect_emitter/proc/configure_effects()
+ effect_system.set_up(effect_amount, effect_cardinals_only, src.loc, effect_forced_dir)
+
+/obj/effect/map_effect/interval/effect_emitter/trigger()
+ configure_effects() // We do this every interval in case it changes.
+ effect_system.start()
+ ..()
+
+
+// Creates smoke clouds every so often.
+/obj/effect/map_effect/interval/effect_emitter/smoke
+ name = "smoke emitter"
+ icon_state = "smoke_emitter"
+ effect_system_type = /datum/effect/effect/system/smoke_spread
+
+ interval_lower_bound = 1 SECOND
+ interval_upper_bound = 1 SECOND
+ effect_amount = 2
+
+/obj/effect/map_effect/interval/effect_emitter/smoke/bad
+ name = "bad smoke emitter"
+ effect_system_type = /datum/effect/effect/system/smoke_spread/bad
+
+/obj/effect/map_effect/interval/effect_emitter/smoke/fire
+ name = "fire smoke emitter"
+ effect_system_type = /datum/effect/effect/system/smoke_spread/fire
+
+/obj/effect/map_effect/interval/effect_emitter/smoke/frost
+ name = "frost smoke emitter"
+ effect_system_type = /datum/effect/effect/system/smoke_spread/frost
+
+/obj/effect/map_effect/interval/effect_emitter/smoke/shock
+ name = "shock smoke emitter"
+ effect_system_type = /datum/effect/effect/system/smoke_spread/shock
+
+/obj/effect/map_effect/interval/effect_emitter/smoke/mist
+ name = "mist smoke emitter"
+ effect_system_type = /datum/effect/effect/system/smoke_spread/mist
+
+
+// Makes sparks.
+/obj/effect/map_effect/interval/effect_emitter/sparks
+ name = "spark emitter"
+ icon_state = "spark_emitter"
+ effect_system_type = /datum/effect/effect/system/spark_spread
+
+ interval_lower_bound = 3 SECONDS
+ interval_upper_bound = 7 SECONDS
+
+/obj/effect/map_effect/interval/effect_emitter/sparks/frequent
+ effect_amount = 4 // Otherwise it caps out fast.
+ interval_lower_bound = 1
+ interval_upper_bound = 3 SECONDS
+
+// Makes ""steam"" that looks like fire extinguisher water except it does nothing.
+/obj/effect/map_effect/interval/effect_emitter/steam
+ name = "steam emitter"
+ icon_state = "smoke_emitter"
+ effect_system_type = /datum/effect/effect/system/steam_spread
diff --git a/code/game/objects/effects/map_effects/map_effects.dm b/code/game/objects/effects/map_effects/map_effects.dm
index 5cd79f1b0c..9e2986072d 100644
--- a/code/game/objects/effects/map_effects/map_effects.dm
+++ b/code/game/objects/effects/map_effects/map_effects.dm
@@ -1,71 +1,72 @@
-// These are objects you can use inside special maps (like PoIs), or for adminbuse.
-// Players cannot see or interact with these.
-/obj/effect/map_effect
- anchored = TRUE
- invisibility = 99 // So a badmin can go view these by changing their see_invisible.
- icon = 'icons/effects/map_effects.dmi'
-
- // Below vars concern check_for_player_proximity() and is used to not waste effort if nobody is around to appreciate the effects.
- var/always_run = FALSE // If true, the game will not try to suppress this from firing if nobody is around to see it.
- var/proximity_needed = 12 // How many tiles a mob with a client must be for this to run.
- var/ignore_ghosts = FALSE // If true, ghosts won't satisfy the above requirement.
- var/ignore_afk = TRUE // If true, AFK people (5 minutes) won't satisfy it as well.
- var/retry_delay = 3 SECONDS // How long until we check for players again.
-
-/obj/effect/map_effect/ex_act()
- return
-
-/obj/effect/map_effect/singularity_pull()
- return
-
-/obj/effect/map_effect/singularity_act()
- return
-
-// Base type for effects that run on variable intervals.
-/obj/effect/map_effect/interval
- var/interval_lower_bound = 5 SECONDS // Lower number for how often the map_effect will trigger.
- var/interval_upper_bound = 5 SECONDS // Higher number for above.
- var/halt = FALSE // Set to true to stop the loop when it reaches the next iteration.
-
-/obj/effect/map_effect/interval/Initialize()
- handle_interval_delay()
- return ..()
-
-/obj/effect/map_effect/interval/Destroy()
- halt = TRUE // Shouldn't need it to GC but just in case.
- return ..()
-
-// Override this for the specific thing to do. Be sure to call parent to keep looping.
-/obj/effect/map_effect/interval/proc/trigger()
- handle_interval_delay()
-
-// Handles the delay and making sure it doesn't run when it would be bad.
-/obj/effect/map_effect/interval/proc/handle_interval_delay()
- // Check to see if we're useful first.
- if(halt)
- return // Do not pass .(), do not recursively collect 200 thaler.
-
- if(!always_run && !check_for_player_proximity(src, proximity_needed, ignore_ghosts, ignore_afk))
- spawn(retry_delay) // Maybe someday we'll have fancy TG timers/schedulers.
- if(!QDELETED(src))
- .()
-
- var/next_interval = rand(interval_lower_bound, interval_upper_bound)
- spawn(next_interval)
- if(!QDELETED(src))
- trigger()
-
-// Helper proc to optimize the use of effects by making sure they do not run if nobody is around to perceive it.
-/proc/check_for_player_proximity(var/atom/proximity_to, var/radius = 12, var/ignore_ghosts = FALSE, var/ignore_afk = TRUE)
- if(!proximity_to)
- return FALSE
-
- for(var/thing in player_list)
- var/mob/M = thing // Avoiding typechecks for more speed, player_list will only contain mobs anyways.
- if(ignore_ghosts && isobserver(M))
- continue
- if(ignore_afk && M.client && M.client.is_afk(5 MINUTES))
- continue
- if(M.z == proximity_to.z && get_dist(M, proximity_to) <= radius)
- return TRUE
+// These are objects you can use inside special maps (like PoIs), or for adminbuse.
+// Players cannot see or interact with these.
+/obj/effect/map_effect
+ anchored = TRUE
+ invisibility = 99 // So a badmin can go view these by changing their see_invisible.
+ icon = 'icons/effects/map_effects.dmi'
+
+ // Below vars concern check_for_player_proximity() and is used to not waste effort if nobody is around to appreciate the effects.
+ var/always_run = FALSE // If true, the game will not try to suppress this from firing if nobody is around to see it.
+ var/proximity_needed = 12 // How many tiles a mob with a client must be for this to run.
+ var/ignore_ghosts = FALSE // If true, ghosts won't satisfy the above requirement.
+ var/ignore_afk = TRUE // If true, AFK people (5 minutes) won't satisfy it as well.
+ var/retry_delay = 3 SECONDS // How long until we check for players again.
+
+/obj/effect/map_effect/ex_act()
+ return
+
+/obj/effect/map_effect/singularity_pull()
+ return
+
+/obj/effect/map_effect/singularity_act()
+ return
+
+// Base type for effects that run on variable intervals.
+/obj/effect/map_effect/interval
+ var/interval_lower_bound = 5 SECONDS // Lower number for how often the map_effect will trigger.
+ var/interval_upper_bound = 5 SECONDS // Higher number for above.
+ var/halt = FALSE // Set to true to stop the loop when it reaches the next iteration.
+
+/obj/effect/map_effect/interval/Initialize()
+ handle_interval_delay()
+ return ..()
+
+/obj/effect/map_effect/interval/Destroy()
+ halt = TRUE // Shouldn't need it to GC but just in case.
+ return ..()
+
+// Override this for the specific thing to do. Be sure to call parent to keep looping.
+/obj/effect/map_effect/interval/proc/trigger()
+ handle_interval_delay()
+
+// Handles the delay and making sure it doesn't run when it would be bad.
+/obj/effect/map_effect/interval/proc/handle_interval_delay()
+ // Check to see if we're useful first.
+ if(halt)
+ return // Do not pass .(), do not recursively collect 200 thaler.
+
+ if(!always_run && !check_for_player_proximity(src, proximity_needed, ignore_ghosts, ignore_afk))
+ spawn(retry_delay) // Maybe someday we'll have fancy TG timers/schedulers.
+ if(!QDELETED(src))
+ .()
+ return
+
+ var/next_interval = rand(interval_lower_bound, interval_upper_bound)
+ spawn(next_interval)
+ if(!QDELETED(src))
+ trigger()
+
+// Helper proc to optimize the use of effects by making sure they do not run if nobody is around to perceive it.
+/proc/check_for_player_proximity(var/atom/proximity_to, var/radius = 12, var/ignore_ghosts = FALSE, var/ignore_afk = TRUE)
+ if(!proximity_to)
+ return FALSE
+
+ for(var/thing in player_list)
+ var/mob/M = thing // Avoiding typechecks for more speed, player_list will only contain mobs anyways.
+ if(ignore_ghosts && isobserver(M))
+ continue
+ if(ignore_afk && M.client && M.client.is_afk(5 MINUTES))
+ continue
+ if(M.z == proximity_to.z && get_dist(M, proximity_to) <= radius)
+ return TRUE
return FALSE
\ No newline at end of file
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index 9ea690318b..87af3ec90b 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -10,6 +10,7 @@
var/mineitemtype = /obj/item/weapon/mine
var/panel_open = 0
var/datum/wires/mines/wires = null
+ register_as_dangerous_object = TRUE
/obj/effect/mine/New()
icon_state = "uglyminearmed"
@@ -271,4 +272,10 @@
/obj/item/weapon/mine/incendiary
name = "incendiary mine"
desc = "A small explosive mine with a fire symbol on the side."
- minetype = /obj/effect/mine/incendiary
\ No newline at end of file
+ minetype = /obj/effect/mine/incendiary
+
+// This tells AI mobs to not be dumb and step on mines willingly.
+/obj/item/weapon/mine/is_safe_to_step(mob/living/L)
+ if(!L.hovering)
+ return FALSE
+ return ..()
\ No newline at end of file
diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm
index 2ede69f232..f6c3bf1b01 100644
--- a/code/game/objects/effects/step_triggers.dm
+++ b/code/game/objects/effects/step_triggers.dm
@@ -3,7 +3,8 @@
/obj/effect/step_trigger
var/affect_ghosts = 0
var/stopper = 1 // stops throwers
- invisibility = 101 // nope cant see this shit
+ invisibility = 99 // nope cant see this shit
+ plane = ABOVE_PLANE
anchored = 1
/obj/effect/step_trigger/proc/Trigger(var/atom/movable/A)
@@ -93,21 +94,56 @@
var/teleport_y = 0
var/teleport_z = 0
- Trigger(var/atom/movable/A)
- if(teleport_x && teleport_y && teleport_z)
- var/turf/T = locate(teleport_x, teleport_y, teleport_z)
- if(isliving(A))
- var/mob/living/L = A
- if(L.pulling)
- var/atom/movable/P = L.pulling
- L.stop_pulling()
- P.forceMove(T)
- L.forceMove(T)
- L.start_pulling(P)
- else
- A.forceMove(T)
- else
- A.forceMove(T)
+/obj/effect/step_trigger/teleporter/Trigger(atom/movable/AM)
+ if(teleport_x && teleport_y && teleport_z)
+ var/turf/T = locate(teleport_x, teleport_y, teleport_z)
+ move_object(AM, T)
+
+
+/obj/effect/step_trigger/teleporter/proc/move_object(atom/movable/AM, turf/T)
+ if(AM.anchored)
+ return
+
+ if(isliving(AM))
+ var/mob/living/L = AM
+ if(L.pulling)
+ var/atom/movable/P = L.pulling
+ L.stop_pulling()
+ P.forceMove(T)
+ L.forceMove(T)
+ L.start_pulling(P)
+ else
+ L.forceMove(T)
+ else
+ AM.forceMove(T)
+
+/* Moves things by an offset, useful for 'Bridges'. Uses dir and a distance var to work with maploader direction changes. */
+/obj/effect/step_trigger/teleporter/offset
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "arrow"
+ var/distance = 3
+
+/obj/effect/step_trigger/teleporter/offset/north
+ dir = NORTH
+
+/obj/effect/step_trigger/teleporter/offset/south
+ dir = SOUTH
+
+/obj/effect/step_trigger/teleporter/offset/east
+ dir = EAST
+
+/obj/effect/step_trigger/teleporter/offset/west
+ dir = WEST
+
+/obj/effect/step_trigger/teleporter/offset/Trigger(atom/movable/AM)
+ var/turf/T = get_turf(src)
+ for(var/i = 1 to distance)
+ T = get_step(T, dir)
+ if(!istype(T))
+ return
+ move_object(AM, T)
+
+
/* Random teleporter, teleports atoms to locations ranging from teleport_x - teleport_x_offset, etc */
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index fd48ab1837..999b5fca99 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -18,11 +18,29 @@
var/can_speak = 0 //For MMIs and admin trickery. If an object has a brainmob in its contents, set this to 1 to allow it to speak.
var/show_examine = TRUE // Does this pop up on a mob when the mob is examined?
+ var/register_as_dangerous_object = FALSE // Should this tell its turf that it is dangerous automatically?
+
+/obj/Initialize()
+ if(register_as_dangerous_object)
+ register_dangerous_to_step()
+ return ..()
/obj/Destroy()
STOP_PROCESSING(SSobj, src)
+ if(register_as_dangerous_object)
+ unregister_dangerous_to_step()
return ..()
+/obj/Moved(atom/oldloc)
+ . = ..()
+ if(register_as_dangerous_object)
+ var/turf/old_turf = get_turf(oldloc)
+ var/turf/new_turf = get_turf(src)
+
+ if(old_turf != new_turf)
+ old_turf.unregister_dangerous_object(src)
+ new_turf.register_dangerous_object(src)
+
/obj/Topic(href, href_list, var/datum/topic_state/state = default_state)
if(usr && ..())
return 1
@@ -161,4 +179,19 @@
return
/obj/proc/get_cell()
- return
\ No newline at end of file
+ return
+
+// Used to mark a turf as containing objects that are dangerous to step onto.
+/obj/proc/register_dangerous_to_step()
+ var/turf/T = get_turf(src)
+ if(T)
+ T.register_dangerous_object(src)
+
+/obj/proc/unregister_dangerous_to_step()
+ var/turf/T = get_turf(src)
+ if(T)
+ T.unregister_dangerous_object(src)
+
+// Test for if stepping on a tile containing this obj is safe to do, used for things like landmines and cliffs.
+/obj/proc/is_safe_to_step(mob/living/L)
+ return TRUE
\ No newline at end of file
diff --git a/code/game/objects/random/unidentified/medicine.dm b/code/game/objects/random/unidentified/medicine.dm
index 4cd2d5652c..f779d75a0f 100644
--- a/code/game/objects/random/unidentified/medicine.dm
+++ b/code/game/objects/random/unidentified/medicine.dm
@@ -1,149 +1,149 @@
-/*
-Semi-randomized loot for PoIs involving medicine.
-Note that most of these include both 'good' and 'bad' results, with the bad results often being
-much more likely to show up. This is done for several purposes;
-
- * A large influx of valuable medicine makes medical/SAR less needed for explorers, which is something we want to avoid.
- * Blindly using autoinjectors should be risky, and to accomplish that, it needs to be more likely to get a bad effect.
- * A large amount of bad loot helps make the good loot feel better to acquire.
-
-*/
-
-// This one makes a purely random hypo. Not recommended for PoIs since it will produce nonsensical results for a PoI's theme.
-// It's more of a thing to help pick specific hypos for the other lists.
-/obj/random/unidentified_medicine
- name = "unidentified medicine"
- desc = "This will make a random hypo."
- icon = 'icons/obj/syringe.dmi'
- item_state = "hypo"
-
-/obj/random/unidentified_medicine/item_to_spawn()
- return pick(
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/stimm/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/space_drugs/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/serotrotium/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cryptobiolin/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mindbreaker/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/psilocybin/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/impedrezene/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites/unidentified,
- /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified)
-
-// Produces things you might find in an old medicine cabinet in a PoI.
-// Old cabinets are typical of ruins and abandoned buildings in the plains, meaning they're usually easier to reach, and as such, inferior loot.
-/obj/random/unidentified_medicine/old_medicine/item_to_spawn()
- // 30 Good, 70 Bad. 30% to get something good.
- // Poor odds, but these are fairly easy to reach as they're in abandoned areas.
- return pick(
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified,
- prob(65);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified)
-
-// Medicine belonging to a place still being occupied (or was recently), meaning the goods might still be fresh, and better.
-/obj/random/unidentified_medicine/fresh_medicine/item_to_spawn()
- // More likely to get something good, and a chance to get rare medicines.
- // 75 Good, 25 Bad. 75% chance of getting something good.
- // Good odds, but the contents aren't super great unless someone gets lucky.
- return pick(
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified,
- prob(25);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified)
-
-// For military PoIs like BSD. High odds of good loot since those PoIs are really hard.
-/obj/random/unidentified_medicine/combat_medicine/item_to_spawn()
- // More likely to get something good, and a chance to get rare medicines.
- // 75 Good, 30 Bad, roughly 71.4% chance to get something good.
- // Very high but very hard to reach and still has a chance of ending poorly if injecting blind.
- return pick(
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified,
- prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific/unidentified,
- prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified)
-
-// Hyposprays found inside various illicit places.
-/obj/random/unidentified_medicine/drug_den/item_to_spawn()
- // Combat stims are common, but so are nasty drugs.
- // 65 Good, 160 Bad, roughly 28.8% to get something good.
- // Poor odds, but there are a lot of these scattered in the drug dens and illegal chem labs.
- return pick(
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified,
- prob(40);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified,
- prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/stimm/unidentified,
- prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/space_drugs/unidentified,
- prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/serotrotium/unidentified,
- prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cryptobiolin/unidentified,
- prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mindbreaker/unidentified,
- prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/psilocybin/unidentified,
- prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/impedrezene/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified)
-
-// Medicine made FOR SCIENCE.
-/obj/random/unidentified_medicine/scientific/item_to_spawn()
- // Potential for amazing loot, also potential for very nasty consequences if injecting blind.
- // 45 Good, 45 Bad, 50% chance to get something good.
- // Do you feel lucky?
- return pick(
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites/unidentified,
- prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen/unidentified,
- prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites/unidentified)
-
-// Nanomachines, son. Found in very advanced places such as the Crashed UFO.
-/obj/random/unidentified_medicine/nanites/item_to_spawn()
- // You better identify this if you value your life.
- // 30 Good, 70 Bad. 30% of getting a good outcome.
- return pick(
- prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites/unidentified,
- prob(70);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites/unidentified)
-
-// Found in virus-related areas like the Quarantined Shuttle.
-/obj/random/unidentified_medicine/viral/item_to_spawn()
- // Another one where's its important to identify the hypo.
- // 30 Good, 70 Bad. 30% of getting a good outcome.
- return pick(
- prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified,
- prob(40);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified,
- prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen/unidentified,
+/*
+Semi-randomized loot for PoIs involving medicine.
+Note that most of these include both 'good' and 'bad' results, with the bad results often being
+much more likely to show up. This is done for several purposes;
+
+ * A large influx of valuable medicine makes medical/SAR less needed for explorers, which is something we want to avoid.
+ * Blindly using autoinjectors should be risky, and to accomplish that, it needs to be more likely to get a bad effect.
+ * A large amount of bad loot helps make the good loot feel better to acquire.
+
+*/
+
+// This one makes a purely random hypo. Not recommended for PoIs since it will produce nonsensical results for a PoI's theme.
+// It's more of a thing to help pick specific hypos for the other lists.
+/obj/random/unidentified_medicine
+ name = "unidentified medicine"
+ desc = "This will make a random hypo."
+ icon = 'icons/obj/syringe.dmi'
+ icon_state = "autoinjector1"
+
+/obj/random/unidentified_medicine/item_to_spawn()
+ return pick(
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/stimm/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/space_drugs/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/serotrotium/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cryptobiolin/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mindbreaker/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/psilocybin/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/impedrezene/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites/unidentified,
+ /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified)
+
+// Produces things you might find in an old medicine cabinet in a PoI.
+// Old cabinets are typical of ruins and abandoned buildings in the plains, meaning they're usually easier to reach, and as such, inferior loot.
+/obj/random/unidentified_medicine/old_medicine/item_to_spawn()
+ // 30 Good, 70 Bad. 30% to get something good.
+ // Poor odds, but these are fairly easy to reach as they're in abandoned areas.
+ return pick(
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified,
+ prob(65);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified)
+
+// Medicine belonging to a place still being occupied (or was recently), meaning the goods might still be fresh, and better.
+/obj/random/unidentified_medicine/fresh_medicine/item_to_spawn()
+ // More likely to get something good, and a chance to get rare medicines.
+ // 75 Good, 25 Bad. 75% chance of getting something good.
+ // Good odds, but the contents aren't super great unless someone gets lucky.
+ return pick(
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified,
+ prob(25);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified)
+
+// For military PoIs like BSD. High odds of good loot since those PoIs are really hard.
+/obj/random/unidentified_medicine/combat_medicine/item_to_spawn()
+ // More likely to get something good, and a chance to get rare medicines.
+ // 75 Good, 30 Bad, roughly 71.4% chance to get something good.
+ // Very high but very hard to reach and still has a chance of ending poorly if injecting blind.
+ return pick(
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified,
+ prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific/unidentified,
+ prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified)
+
+// Hyposprays found inside various illicit places.
+/obj/random/unidentified_medicine/drug_den/item_to_spawn()
+ // Combat stims are common, but so are nasty drugs.
+ // 65 Good, 160 Bad, roughly 28.8% to get something good.
+ // Poor odds, but there are a lot of these scattered in the drug dens and illegal chem labs.
+ return pick(
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified,
+ prob(40);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified,
+ prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/stimm/unidentified,
+ prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/space_drugs/unidentified,
+ prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/serotrotium/unidentified,
+ prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cryptobiolin/unidentified,
+ prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mindbreaker/unidentified,
+ prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/psilocybin/unidentified,
+ prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/impedrezene/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified)
+
+// Medicine made FOR SCIENCE.
+/obj/random/unidentified_medicine/scientific/item_to_spawn()
+ // Potential for amazing loot, also potential for very nasty consequences if injecting blind.
+ // 45 Good, 45 Bad, 50% chance to get something good.
+ // Do you feel lucky?
+ return pick(
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites/unidentified,
+ prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen/unidentified,
+ prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites/unidentified)
+
+// Nanomachines, son. Found in very advanced places such as the Crashed UFO.
+/obj/random/unidentified_medicine/nanites/item_to_spawn()
+ // You better identify this if you value your life.
+ // 30 Good, 70 Bad. 30% of getting a good outcome.
+ return pick(
+ prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites/unidentified,
+ prob(70);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites/unidentified)
+
+// Found in virus-related areas like the Quarantined Shuttle.
+/obj/random/unidentified_medicine/viral/item_to_spawn()
+ // Another one where's its important to identify the hypo.
+ // 30 Good, 70 Bad. 30% of getting a good outcome.
+ return pick(
+ prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified,
+ prob(40);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified,
+ prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen/unidentified,
prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified)
\ No newline at end of file
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index 370b9b866e..4d0eb2b9ee 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -3,9 +3,11 @@
w_class = ITEMSIZE_NO_CONTAINER
var/climbable
+ var/climb_delay = 3.5 SECONDS
var/breakable
var/parts
var/list/climbers = list()
+ var/block_turf_edges = FALSE // If true, turf edge icons will not be made on the turf this occupies.
/obj/structure/Destroy()
if(parts)
@@ -99,7 +101,7 @@
usr.visible_message("[user] starts climbing onto \the [src]!")
climbers |= user
- if(!do_after(user,(issmall(user) ? 20 : 34)))
+ if(!do_after(user,(issmall(user) ? climb_delay * 0.6 : climb_delay)))
climbers -= user
return
diff --git a/code/game/objects/structures/cliff.dm b/code/game/objects/structures/cliff.dm
new file mode 100644
index 0000000000..0d197b2a22
--- /dev/null
+++ b/code/game/objects/structures/cliff.dm
@@ -0,0 +1,239 @@
+GLOBAL_LIST_EMPTY(cliff_icon_cache)
+
+/*
+Cliffs give a visual illusion of depth by seperating two places while presenting a 'top' and 'bottom' side.
+
+Mobs moving into a cliff from the bottom side will simply bump into it and be denied moving into the tile,
+where as mobs moving into a cliff from the top side will 'fall' off the cliff, forcing them to the bottom, causing significant damage and stunning them.
+
+Mobs can climb this while wearing climbing equipment by clickdragging themselves onto a cliff, as if it were a table.
+
+Flying mobs can pass over all cliffs with no risk of falling.
+
+Projectiles and thrown objects can pass, however if moving upwards, there is a chance for it to be stopped by the cliff.
+This makes fighting something that is on top of a cliff more challenging.
+
+As a note, dir points upwards, e.g. pointing WEST means the left side is 'up', and the right side is 'down'.
+
+When mapping these in, be sure to give at least a one tile clearance, as NORTH facing cliffs expand to
+two tiles on initialization, and which way a cliff is facing may change during maploading.
+*/
+
+/obj/structure/cliff
+ name = "cliff"
+ desc = "A steep rock ledge. You might be able to climb it if you feel bold enough."
+ description_info = "Walking off the edge of a cliff while on top will cause you to fall off, causing severe injury.
\
+ You can climb this cliff if wearing special climbing equipment, by click-dragging yourself onto the cliff.
\
+ Projectiles traveling up a cliff may hit the cliff instead, making it more difficult to fight something \
+ on top."
+ icon = 'icons/obj/flora/rocks.dmi'
+
+ anchored = TRUE
+ density = TRUE
+ opacity = FALSE
+ climbable = TRUE
+ climb_delay = 10 SECONDS
+ block_turf_edges = TRUE // Don't want turf edges popping up from the cliff edge.
+ register_as_dangerous_object = TRUE
+
+ var/icon_variant = null // Used to make cliffs less repeative by having a selection of sprites to display.
+ var/corner = FALSE // Used for icon things.
+ var/ramp = FALSE // Ditto.
+ var/bottom = FALSE // Used for 'bottom' typed cliffs, to avoid infinite cliffs, and for icons.
+
+ var/is_double_cliff = FALSE // Set to true when making the two-tile cliffs, used for projectile checks.
+ var/uphill_penalty = 30 // Odds of a projectile not making it up the cliff.
+
+// These arrange their sprites at runtime, as opposed to being statically placed in the map file.
+/obj/structure/cliff/automatic
+ icon_state = "cliffbuilder"
+ dir = NORTH
+
+/obj/structure/cliff/automatic/corner
+ icon_state = "cliffbuilder-corner"
+ dir = NORTHEAST
+ corner = TRUE
+
+// Tiny part that doesn't block, used for making 'ramps'.
+/obj/structure/cliff/automatic/ramp
+ icon_state = "cliffbuilder-ramp"
+ dir = NORTHEAST
+ density = FALSE
+ ramp = TRUE
+
+// Made automatically as needed by automatic cliffs.
+/obj/structure/cliff/bottom
+ bottom = TRUE
+
+/obj/structure/cliff/automatic/Initialize()
+ ..()
+ return INITIALIZE_HINT_LATELOAD
+
+// Paranoid about the maploader, direction is very important to cliffs, since they may get bigger if initialized while facing NORTH.
+/obj/structure/cliff/automatic/LateInitialize()
+ if(dir in GLOB.cardinal)
+ icon_variant = pick("a", "b", "c")
+
+ if(dir & NORTH && !bottom) // North-facing cliffs require more cliffs to be made.
+ make_bottom()
+
+ update_icon()
+
+/obj/structure/cliff/proc/make_bottom()
+ // First, make sure there's room to put the bottom side.
+ var/turf/T = locate(x, y - 1, z)
+ if(!istype(T))
+ return FALSE
+
+ // Now make the bottom cliff have mostly the same variables.
+ var/obj/structure/cliff/bottom/bottom = new(T)
+ is_double_cliff = TRUE
+ climb_delay /= 2 // Since there are two cliffs to climb when going north, both take half the time.
+
+ bottom.dir = dir
+ bottom.is_double_cliff = TRUE
+ bottom.climb_delay = climb_delay
+ bottom.icon_variant = icon_variant
+ bottom.corner = corner
+ bottom.ramp = ramp
+ bottom.layer = layer - 0.1
+ bottom.density = density
+ bottom.update_icon()
+
+/obj/structure/cliff/set_dir(new_dir)
+ ..()
+ update_icon()
+
+/obj/structure/cliff/update_icon()
+ icon_state = "cliff-[dir][icon_variant][bottom ? "-bottom" : ""][corner ? "-corner" : ""][ramp ? "-ramp" : ""]"
+
+ // Now for making the top-side look like a different turf.
+ var/turf/T = get_step(src, dir)
+ if(!istype(T))
+ return
+
+ var/subtraction_icon_state = "[icon_state]-subtract"
+ var/cache_string = "[icon_state]_[T.icon]_[T.icon_state]"
+ if(T && subtraction_icon_state in icon_states(icon))
+ cut_overlays()
+ // If we've made the same icon before, just recycle it.
+ if(cache_string in GLOB.cliff_icon_cache)
+ add_overlay(GLOB.cliff_icon_cache[cache_string])
+
+ else // Otherwise make a new one, but only once.
+ var/icon/underlying_ground = icon(T.icon, T.icon_state, T.dir)
+ var/icon/subtract = icon(icon, subtraction_icon_state)
+ underlying_ground.Blend(subtract, ICON_SUBTRACT)
+ var/image/final = image(underlying_ground)
+ final.layer = src.layer - 0.2
+ GLOB.cliff_icon_cache[cache_string] = final
+ add_overlay(final)
+
+
+// Movement-related code.
+
+/obj/structure/cliff/CanPass(atom/movable/mover, turf/target, height = 0, air_group = 0)
+ if(air_group || height == 0)
+ return TRUE // Airflow can always pass.
+
+ else if(isliving(mover))
+ var/mob/living/L = mover
+ if(L.hovering) // Flying mobs can always pass.
+ return TRUE
+ return ..()
+
+ // Projectiles and objects flying 'upward' have a chance to hit the cliff instead, wasting the shot.
+ else if(istype(mover, /obj))
+ var/obj/O = mover
+ if(check_shield_arc(src, dir, O)) // This is actually for mobs but it will work for our purposes as well.
+ if(prob(uphill_penalty / (1 + is_double_cliff) )) // Firing upwards facing NORTH means it will likely have to pass through two cliffs, so the chance is halved.
+ return FALSE
+ return TRUE
+
+/obj/structure/cliff/Bumped(atom/A)
+ if(isliving(A))
+ var/mob/living/L = A
+ if(should_fall(L))
+ fall_off_cliff(L)
+ return
+ ..()
+
+/obj/structure/cliff/proc/should_fall(mob/living/L)
+ if(L.hovering)
+ return FALSE
+
+ var/turf/T = get_turf(L)
+ if(T && get_dir(T, loc) & reverse_dir[dir]) // dir points 'up' the cliff, e.g. cliff pointing NORTH will cause someone to fall if moving SOUTH into it.
+ return TRUE
+ return FALSE
+
+/obj/structure/cliff/proc/fall_off_cliff(mob/living/L)
+ if(!istype(L))
+ return FALSE
+ var/turf/T = get_step(src, reverse_dir[dir])
+ var/displaced = FALSE
+
+ if(dir in list(EAST, WEST)) // Apply an offset if flying sideways, to help maintain the illusion of depth.
+ for(var/i = 1 to 2)
+ var/turf/new_T = locate(T.x, T.y - i, T.z)
+ if(!new_T || locate(/obj/structure/cliff) in new_T)
+ break
+ T = new_T
+ displaced = TRUE
+
+ if(istype(T))
+ visible_message(span("danger", "\The [L] falls off \the [src]!"))
+ L.forceMove(T)
+
+ // Do the actual hurting. Double cliffs do halved damage due to them most likely hitting twice.
+ var/harm = !is_double_cliff ? 1 : 0.5
+ if(istype(L.buckled, /obj/vehicle)) // People falling off in vehicles will take less damage, but will damage the vehicle severely.
+ var/obj/vehicle/vehicle = L.buckled
+ vehicle.adjust_health(40 * harm)
+ to_chat(L, span("warning", "\The [vehicle] absorbs some of the impact, damaging it."))
+ harm /= 2
+
+ playsound(L, 'sound/effects/break_stone.ogg', 70, 1)
+ L.Weaken(5 * harm)
+ var/fall_time = 3
+ if(displaced) // Make the fall look more natural when falling sideways.
+ L.pixel_z = 32 * 2
+ animate(L, pixel_z = 0, time = fall_time)
+ sleep(fall_time) // A brief delay inbetween the two sounds helps sell the 'ouch' effect.
+ playsound(L, "punch", 70, 1)
+ shake_camera(L, 1, 1)
+ visible_message(span("danger", "\The [L] hits the ground!"))
+
+ // The bigger they are, the harder they fall.
+ // They will take at least 20 damage at the minimum, and tries to scale up to 40% of their max health.
+ // This scaling is capped at 100 total damage, which occurs if the thing that fell has more than 250 health.
+ var/damage = between(20, L.getMaxHealth() * 0.4, 100)
+ var/target_zone = ran_zone()
+ var/blocked = L.run_armor_check(target_zone, "melee") * harm
+ var/soaked = L.get_armor_soak(target_zone, "melee") * harm
+
+ L.apply_damage(damage * harm, BRUTE, target_zone, blocked, soaked, used_weapon=src)
+
+ // Now fall off more cliffs below this one if they exist.
+ var/obj/structure/cliff/bottom_cliff = locate() in T
+ if(bottom_cliff)
+ visible_message(span("danger", "\The [L] rolls down towards \the [bottom_cliff]!"))
+ sleep(5)
+ bottom_cliff.fall_off_cliff(L)
+
+/obj/structure/cliff/can_climb(mob/living/user, post_climb_check = FALSE)
+ // Cliff climbing requires climbing gear.
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ var/obj/item/clothing/shoes/shoes = H.shoes
+ if(shoes && shoes.rock_climbing)
+ return ..() // Do the other checks too.
+
+ to_chat(user, span("warning", "\The [src] is too steep to climb unassisted."))
+ return FALSE
+
+// This tells AI mobs to not be dumb and step off cliffs willingly.
+/obj/structure/cliff/is_safe_to_step(mob/living/L)
+ if(should_fall(L))
+ return FALSE
+ return ..()
diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm
new file mode 100644
index 0000000000..04f58390a6
--- /dev/null
+++ b/code/game/objects/structures/fence.dm
@@ -0,0 +1,179 @@
+//Chain link fences
+//Sprites ported from /VG/
+
+#define CUT_TIME 10 SECONDS
+#define CLIMB_TIME 5 SECONDS
+
+#define NO_HOLE 0 //section is intact
+#define MEDIUM_HOLE 1 //medium hole in the section - can climb through
+#define LARGE_HOLE 2 //large hole in the section - can walk through
+#define MAX_HOLE_SIZE LARGE_HOLE
+
+/obj/structure/fence
+ name = "fence"
+ desc = "A chain link fence. Not as effective as a wall, but generally it keeps people out."
+ description_info = "Projectiles can freely pass fences."
+ density = TRUE
+ anchored = TRUE
+
+ icon = 'icons/obj/fence.dmi'
+ icon_state = "straight"
+
+ var/cuttable = TRUE
+ var/hole_size= NO_HOLE
+ var/invulnerable = FALSE
+
+/obj/structure/fence/Initialize()
+ update_cut_status()
+ return ..()
+
+/obj/structure/fence/examine(mob/user)
+ . = ..()
+
+ switch(hole_size)
+ if(MEDIUM_HOLE)
+ user.show_message("There is a large hole in \the [src].")
+ if(LARGE_HOLE)
+ user.show_message("\The [src] has been completely cut through.")
+
+/obj/structure/fence/get_description_interaction()
+ var/list/results = list()
+ if(cuttable && !invulnerable && hole_size < MAX_HOLE_SIZE)
+ results += "[desc_panel_image("wirecutters")]to [hole_size > NO_HOLE ? "expand the":"cut a"] hole into the fence, allowing passage."
+ return results
+
+/obj/structure/fence/end
+ icon_state = "end"
+ cuttable = FALSE
+
+/obj/structure/fence/corner
+ icon_state = "corner"
+ cuttable = FALSE
+
+/obj/structure/fence/post
+ icon_state = "post"
+ cuttable = FALSE
+
+/obj/structure/fence/cut/medium
+ icon_state = "straight_cut2"
+ hole_size = MEDIUM_HOLE
+
+/obj/structure/fence/cut/large
+ icon_state = "straight_cut3"
+ hole_size = LARGE_HOLE
+
+// Projectiles can pass through fences.
+/obj/structure/fence/CanPass(atom/movable/mover, turf/target, height = 0, air_group = 0)
+ if(istype(mover, /obj/item/projectile))
+ return TRUE
+ return ..()
+
+/obj/structure/fence/attackby(obj/item/W, mob/user)
+ if(W.is_wirecutter())
+ if(!cuttable)
+ to_chat(user, span("warning", "This section of the fence can't be cut."))
+ return
+ if(invulnerable)
+ to_chat(user, span("warning", "This fence is too strong to cut through."))
+ return
+ var/current_stage = hole_size
+ if(current_stage >= MAX_HOLE_SIZE)
+ to_chat(user, span("notice", "This fence has too much cut out of it already."))
+ return
+
+ user.visible_message(span("danger", "\The [user] starts cutting through \the [src] with \the [W]."),\
+ span("danger", "You start cutting through \the [src] with \the [W]."))
+ playsound(src, W.usesound, 50, 1)
+
+ if(do_after(user, CUT_TIME * W.toolspeed, target = src))
+ if(current_stage == hole_size)
+ switch(++hole_size)
+ if(MEDIUM_HOLE)
+ visible_message(span("notice", "\The [user] cuts into \the [src] some more."))
+ to_chat(user, span("notice", "You could probably fit yourself through that hole now. Although climbing through would be much faster if you made it even bigger."))
+ climbable = TRUE
+ if(LARGE_HOLE)
+ visible_message(span("notice", "\The [user] completely cuts through \the [src]."))
+ to_chat(user, span("notice", "The hole in \the [src] is now big enough to walk through."))
+ climbable = FALSE
+ update_cut_status()
+ return TRUE
+
+/obj/structure/fence/proc/update_cut_status()
+ if(!cuttable)
+ return
+ density = TRUE
+
+ switch(hole_size)
+ if(NO_HOLE)
+ icon_state = initial(icon_state)
+ if(MEDIUM_HOLE)
+ icon_state = "straight_cut2"
+ if(LARGE_HOLE)
+ icon_state = "straight_cut3"
+ density = FALSE
+
+//FENCE DOORS
+
+/obj/structure/fence/door
+ name = "fence door"
+ desc = "Not very useful without a real lock."
+ icon_state = "door_closed"
+ cuttable = FALSE
+ var/open = FALSE
+ var/locked = FALSE
+
+/obj/structure/fence/door/Initialize()
+ update_door_status()
+ return ..()
+
+/obj/structure/fence/door/opened
+ icon_state = "door_opened"
+ open = TRUE
+ density = TRUE
+
+/obj/structure/fence/door/locked
+ desc = "It looks like it has a strong padlock attached."
+ locked = TRUE
+
+/obj/structure/fence/door/attack_hand(mob/user)
+ if(can_open(user))
+ toggle(user)
+ else
+ to_chat(user, span("warning", "\The [src] is [!open ? "locked" : "stuck open"]."))
+
+ return TRUE
+
+/obj/structure/fence/door/proc/toggle(mob/user)
+ switch(open)
+ if(FALSE)
+ visible_message(span("notice", "\The [user] opens \the [src]."))
+ open = TRUE
+ if(TRUE)
+ visible_message(span("notice", "\The [user] closes \the [src]."))
+ open = FALSE
+
+ update_door_status()
+ playsound(src, 'sound/machines/click.ogg', 100, 1)
+
+/obj/structure/fence/door/proc/update_door_status()
+ switch(open)
+ if(FALSE)
+ density = TRUE
+ icon_state = "door_closed"
+ if(TRUE)
+ density = FALSE
+ icon_state = "door_opened"
+
+/obj/structure/fence/door/proc/can_open(mob/user)
+ if(locked)
+ return FALSE
+ return TRUE
+
+#undef CUT_TIME
+#undef CLIMB_TIME
+
+#undef NO_HOLE
+#undef MEDIUM_HOLE
+#undef LARGE_HOLE
+#undef MAX_HOLE_SIZE
\ No newline at end of file
diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm
index bd868bcc91..26bc212829 100644
--- a/code/game/objects/structures/signs.dm
+++ b/code/game/objects/structures/signs.dm
@@ -239,6 +239,18 @@
name = "\improper EMERGENT INTELLIGENCE DETAILS"
icon_state = "rogueai"
+/obj/structure/sign/warning/falling
+ name = "\improper FALL HAZARD"
+ icon_state = "falling"
+
+/obj/structure/sign/warning/lava
+ name = "\improper MOLTEN SURFACE"
+ icon_state = "lava"
+
+/obj/structure/sign/warning/acid
+ name = "\improper ACIDIC SURFACE"
+ icon_state = "acid"
+
/obj/structure/sign/redcross
name = "medbay"
desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here."
diff --git a/code/game/turfs/simulated/lava.dm b/code/game/turfs/simulated/lava.dm
new file mode 100644
index 0000000000..acf0c17317
--- /dev/null
+++ b/code/game/turfs/simulated/lava.dm
@@ -0,0 +1,91 @@
+/turf/simulated/floor/lava
+ name = "lava"
+ desc = "A pool of molten rock."
+ description_info = "Molten rock is extremly dangerous, as it will cause massive harm to anything that touches it.
\
+ A firesuit cannot fully protect from contact with molten rock."
+ gender = PLURAL // So it says "That's some lava." on examine.
+ icon = 'icons/turf/outdoors.dmi'
+ icon_state = "lava"
+ edge_blending_priority = -1
+ light_range = 2
+ light_power = 0.75
+ light_color = LIGHT_COLOR_LAVA
+ movement_cost = 2
+ can_build_into_floor = TRUE
+ can_dirty = FALSE
+
+/turf/simulated/floor/lava/outdoors
+ outdoors = TRUE
+
+// For maximum pedantry.
+/turf/simulated/floor/lava/Initialize()
+ if(!outdoors)
+ name = "magma"
+ update_icon()
+ return ..()
+
+/turf/simulated/floor/lava/make_outdoors()
+ ..()
+ name = "lava"
+
+/turf/simulated/floor/lava/make_indoors()
+ ..()
+ name = "magma"
+
+/turf/simulated/floor/lava/update_icon()
+ cut_overlays()
+ ..()
+ update_icon_edge()
+
+/turf/simulated/floor/lava/Entered(atom/movable/AM)
+ if(burn_stuff(AM))
+ START_PROCESSING(SSobj, src)
+
+/turf/simulated/floor/lava/hitby(atom/movable/AM)
+ if(burn_stuff(AM))
+ START_PROCESSING(SSobj, src)
+
+/turf/simulated/floor/lava/process()
+ if(!burn_stuff())
+ STOP_PROCESSING(SSobj, src)
+
+/turf/simulated/floor/lava/proc/is_safe()
+ //if anything matching this typecache is found in the lava, we don't burn things
+ var/static/list/lava_safeties_typecache = typecacheof(list(/obj/structure/catwalk))
+ var/list/found_safeties = typecache_filter_list(contents, lava_safeties_typecache)
+ return LAZYLEN(found_safeties)
+
+/turf/simulated/floor/lava/proc/burn_stuff(atom/movable/AM)
+ . = FALSE
+
+ if(is_safe())
+ return FALSE
+
+ var/thing_to_check = src
+ if(AM)
+ thing_to_check = list(AM)
+
+ for(var/thing in thing_to_check)
+ if(isobj(thing))
+ var/obj/O = thing
+ if(O.throwing)
+ continue
+ . = TRUE
+ O.lava_act()
+
+ else if(isliving(thing))
+ var/mob/living/L = thing
+ if(L.hovering || L.throwing) // Flying over the lava. We're just gonna pretend convection doesn't exist.
+ continue
+ . = TRUE
+ L.lava_act()
+
+// Lava that does nothing at all.
+/turf/simulated/floor/lava/harmless/burn_stuff(atom/movable/AM)
+ return FALSE
+
+// Tells AI mobs to not suicide by pathing into lava if it would hurt them.
+/turf/simulated/floor/lava/is_safe_to_enter(mob/living/L)
+ if(!is_safe() && !L.hovering)
+ return FALSE
+ return ..()
\ No newline at end of file
diff --git a/code/game/turfs/simulated/outdoors/grass.dm b/code/game/turfs/simulated/outdoors/grass.dm
index 1258349bbf..d5009dd9e9 100644
--- a/code/game/turfs/simulated/outdoors/grass.dm
+++ b/code/game/turfs/simulated/outdoors/grass.dm
@@ -29,8 +29,13 @@ var/list/grass_types = list(
/obj/structure/flora/sif/eyes
)
+<<<<<<< HEAD
/turf/simulated/floor/outdoors/grass/sif/Initialize()
if(tree_chance && prob(tree_chance))
+=======
+/turf/simulated/floor/outdoors/grass/sif/Initialize()
+ if(tree_chance && prob(tree_chance) && !check_density())
+>>>>>>> afa149c... Adds New PoI Features + Bonus PoI (#5796)
new /obj/structure/flora/tree/sif(src)
. = ..()
@@ -39,7 +44,7 @@ var/list/grass_types = list(
icon_state = "[initial(icon_state)]2"
//edge_blending_priority++
- if(grass_chance && prob(grass_chance))
+ if(grass_chance && prob(grass_chance) && !check_density())
var/grass_type = pick(grass_types)
new grass_type(src)
. = ..()
diff --git a/code/game/turfs/simulated/outdoors/outdoors.dm b/code/game/turfs/simulated/outdoors/outdoors.dm
index b59523a679..a378cc48da 100644
--- a/code/game/turfs/simulated/outdoors/outdoors.dm
+++ b/code/game/turfs/simulated/outdoors/outdoors.dm
@@ -51,10 +51,10 @@ var/list/turf_edge_cache = list()
make_indoors()
/turf/simulated/proc/update_icon_edge()
- if(edge_blending_priority)
+ if(edge_blending_priority && !forbid_turf_edge())
for(var/checkdir in cardinal)
var/turf/simulated/T = get_step(src, checkdir)
- if(istype(T) && T.edge_blending_priority && edge_blending_priority < T.edge_blending_priority && icon_state != T.icon_state)
+ if(istype(T) && T.edge_blending_priority && edge_blending_priority < T.edge_blending_priority && icon_state != T.icon_state && !T.forbid_turf_edge())
var/cache_key = "[T.get_edge_icon_state()]-[checkdir]"
if(!turf_edge_cache[cache_key])
var/image/I = image(icon = 'icons/turf/outdoors_edge.dmi', icon_state = "[T.get_edge_icon_state()]-edge", dir = checkdir, layer = ABOVE_TURF_LAYER)
@@ -65,6 +65,14 @@ var/list/turf_edge_cache = list()
/turf/simulated/proc/get_edge_icon_state()
return icon_state
+// Tests if we shouldn't apply a turf edge.
+// Returns the blocker if one exists.
+/turf/simulated/proc/forbid_turf_edge()
+ for(var/obj/structure/S in contents)
+ if(S.block_turf_edges)
+ return S
+ return null
+
/turf/simulated/floor/outdoors/update_icon()
..()
update_icon_edge()
@@ -80,6 +88,8 @@ var/list/turf_edge_cache = list()
icon_state = "rock"
edge_blending_priority = 1
+/turf/simulated/floor/outdoors/rocks/caves
+ outdoors = FALSE
// This proc adds a 'layer' on top of the turf.
/turf/simulated/floor/outdoors/proc/promote(var/new_turf_type)
diff --git a/code/game/turfs/simulated/water.dm b/code/game/turfs/simulated/water.dm
index abf8bb9579..33901a8b2b 100644
--- a/code/game/turfs/simulated/water.dm
+++ b/code/game/turfs/simulated/water.dm
@@ -108,6 +108,8 @@
return 0
if(hovering)
return 0
+ if(locate(/obj/structure/catwalk) in loc)
+ return 0
var/turf/simulated/floor/water/T = loc
if(istype(T))
return T.depth
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index f4c35b6e04..f10f88e64d 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -32,6 +32,7 @@
var/block_tele = FALSE // If true, most forms of teleporting to or from this turf tile will fail.
var/can_build_into_floor = FALSE // Used for things like RCDs (and maybe lattices/floor tiles in the future), to see if a floor should replace it.
+ var/list/dangerous_objects // List of 'dangerous' objs that the turf holds that can cause something bad to happen when stepped on, used for AI mobs.
/turf/New()
..()
@@ -322,8 +323,28 @@ var/const/enterloopsanity = 100
// Returns false if stepping into a tile would cause harm (e.g. open space while unable to fly, water tile while a slime, lava, etc).
/turf/proc/is_safe_to_enter(mob/living/L)
+ if(LAZYLEN(dangerous_objects))
+ for(var/obj/O in dangerous_objects)
+ if(!O.is_safe_to_step(L))
+ return FALSE
return TRUE
+// Tells the turf that it currently contains something that automated movement should consider if planning to enter the tile.
+// This uses lazy list macros to reduce memory footprint, since for 99% of turfs the list would've been empty anyways.
+/turf/proc/register_dangerous_object(obj/O)
+ if(!istype(O))
+ return FALSE
+ LAZYADD(dangerous_objects, O)
+// color = "#FF0000"
+
+// Similar to above, for when the dangerous object stops being dangerous/gets deleted/moved/etc.
+/turf/proc/unregister_dangerous_object(obj/O)
+ if(!istype(O))
+ return FALSE
+ LAZYREMOVE(dangerous_objects, O)
+ UNSETEMPTY(dangerous_objects) // This nulls the list var if it's empty.
+// color = "#00FF00"
+
// This is all the way up here since its the common ancestor for things that need to get replaced with a floor when an RCD is used on them.
// More specialized turfs like walls should instead override this.
// The code for applying lattices/floor tiles onto lattices could also utilize something similar in the future.
diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm
index 47c0b21635..eb985d268b 100644
--- a/code/game/turfs/turf_changing.dm
+++ b/code/game/turfs/turf_changing.dm
@@ -38,6 +38,7 @@
var/old_lighting_overlay = lighting_overlay
var/old_corners = corners
var/old_outdoors = outdoors
+ var/old_dangerous_objects = dangerous_objects
//world << "Replacing [src.type] with [N]"
@@ -95,6 +96,8 @@
recalc_atom_opacity()
+ dangerous_objects = old_dangerous_objects
+
if(lighting_overlays_initialised)
lighting_overlay = old_lighting_overlay
affecting_lights = old_affecting_lights
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 84a331a77b..bfbf1bb204 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -473,6 +473,7 @@
var/water_speed = 0 //Speed boost/decrease in water, lower/negative values mean more speed
var/snow_speed = 0 //Speed boost/decrease on snow, lower/negative values mean more speed
+ var/rock_climbing = FALSE // If true, allows climbing cliffs with clickdrag.
var/step_volume_mod = 1 //How quiet or loud footsteps in this shoe are
diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm
index 0b6b6757dc..dd5e7956df 100644
--- a/code/modules/clothing/shoes/boots.dm
+++ b/code/modules/clothing/shoes/boots.dm
@@ -114,6 +114,13 @@
icon_state = "explorer"
armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 0, rad = 0)
+// Allows the wearer to climb cliffs, which could allow for shortcuts or sequence-breaking.
+/obj/item/clothing/shoes/boots/winter/climbing
+ name = "climbing winter boots"
+ desc = "A pair of winter boots, with metal bracing attached to assist in climbing rocky terrain."
+ icon_state = "climbing_boots"
+ rock_climbing = TRUE
+
/obj/item/clothing/shoes/boots/tactical
name = "tactical boots"
desc = "Tan boots with extra padding and armor."
diff --git a/code/modules/mob/_modifiers/modifiers_misc.dm b/code/modules/mob/_modifiers/modifiers_misc.dm
index b94024c7e3..be5be67280 100644
--- a/code/modules/mob/_modifiers/modifiers_misc.dm
+++ b/code/modules/mob/_modifiers/modifiers_misc.dm
@@ -180,6 +180,8 @@ the artifact triggers the rage.
accuracy = -75 // Aiming requires focus.
accuracy_dispersion = 3 // Ditto.
evasion = -45 // Too angry to dodge.
+<<<<<<< HEAD
+=======
// Non-cult version of deep wounds.
// Surprisingly, more dangerous.
@@ -213,6 +215,10 @@ the artifact triggers the rage.
stacks = MODIFIER_STACK_ALLOWED // Multiple instances will hurt a lot.
var/damage_per_tick = 5
+/datum/modifier/fire/intense
+ mob_overlay_state = "on_fire_intense"
+ damage_per_tick = 10
+
/datum/modifier/fire/tick()
holder.inflict_heat_damage(damage_per_tick)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 29cdc8753b..87145b46fc 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -452,6 +452,13 @@
emp_act(1)
to_chat(src, span("critical", "You've been struck by lightning!"))
+// Called when touching a lava tile.
+// Does roughly 100 damage to unprotected mobs, and 20 to fully protected mobs.
+/mob/living/lava_act()
+ add_modifier(/datum/modifier/fire/intense, 8 SECONDS) // Around 40 total if left to burn and without fire protection per stack.
+ inflict_heat_damage(40) // Another 40, however this is instantly applied to unprotected mobs.
+ adjustFireLoss(20) // Lava cannot be 100% resisted with fire protection.
+
/mob/living/proc/reagent_permeability()
return 1
return round(FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE*(fire_stacks/FIRE_MAX_FIRESUIT_STACKS)**2)
diff --git a/code/modules/mob/living/simple_mob/defense.dm b/code/modules/mob/living/simple_mob/defense.dm
index af1b2774b3..744237b21d 100644
--- a/code/modules/mob/living/simple_mob/defense.dm
+++ b/code/modules/mob/living/simple_mob/defense.dm
@@ -216,6 +216,17 @@
ash()
return // No point deafening something that wont exist.
+// Lava
+/mob/living/simple_mob/lava_act()
+ ..()
+ // Similar to lightning, the mob is turned to ash if the lava tick was fatal and it isn't a player.
+ // Unlike lightning, we don't add an additional damage spike (since lava already hurts a lot).
+ if(!client)
+ updatehealth()
+ if(health <= 0)
+ visible_message(span("critical", "\The [src] flashes into ash as the lava consumes them!"))
+ ash()
+
// Injections.
/mob/living/simple_mob/can_inject(mob/user, error_msg, target_zone, ignore_thickness)
if(ignore_thickness)
diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm
index cac6065b64..1bef7d41ea 100644
--- a/code/modules/vehicles/vehicle.dm
+++ b/code/modules/vehicles/vehicle.dm
@@ -164,6 +164,10 @@
..()
healthcheck()
+/obj/vehicle/proc/adjust_health(amount)
+ health = between(0, health + amount, maxhealth)
+ healthcheck()
+
/obj/vehicle/ex_act(severity)
switch(severity)
if(1.0)
diff --git a/code/modules/xenoarcheaology/finds/misc.dm b/code/modules/xenoarcheaology/finds/misc.dm
index 04e7b788de..97a604f52b 100644
--- a/code/modules/xenoarcheaology/finds/misc.dm
+++ b/code/modules/xenoarcheaology/finds/misc.dm
@@ -3,13 +3,18 @@
//legacy crystal
/obj/machinery/crystal
- name = "Crystal"
+ name = "crystal"
+ desc = "A shiny looking crystal formation."
icon = 'icons/obj/mining.dmi'
icon_state = "crystal"
density = TRUE
anchored = TRUE
-/obj/machinery/crystal/New()
+/obj/machinery/crystal/Initialize()
+ randomize_color()
+ return ..()
+
+/obj/machinery/crystal/proc/randomize_color()
if(prob(30))
icon_state = "crystal2"
set_light(3, 3, "#CC00CC")
@@ -21,18 +26,25 @@
desc = "A large crystalline ice formation."
icon_state = "icecrystal2"
-/obj/machinery/crystal/ice/New()
- if(prob(10))
- icon_state = "crystal"
- set_light(5, 5, "#33CC33")
- if(prob(10))
- icon_state = "crystal2"
- set_light(5, 5, "#CC00CC")
+/obj/machinery/crystal/ice/randomize_color()
if(prob(30))
icon_state = "icecrystal1"
- set_light(5, 5, "#C4FFFF")
- else
- set_light(5, 5, "#C4FFFF")
+ set_light(3, 3, "#C4FFFF")
+
+/obj/machinery/crystal/lava
+ name = "lava crystal"
+ desc = "A large crystalline formation found near extreme heat."
+ icon_state = "grey_crystal"
+ color = "#FCCF64"
+
+/obj/machinery/crystal/lava/randomize_color()
+ if(prob(50))
+ icon_state = "grey_crystal2"
+
+ if(prob(30))
+ color = "#E03131"
+
+ set_light(3, 3, color)
//large finds
/*
diff --git a/icons/mob/feet.dmi b/icons/mob/feet.dmi
index d1c09ef542..9c3997985e 100644
Binary files a/icons/mob/feet.dmi and b/icons/mob/feet.dmi differ
diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi
index a923ea9986..d2901f5bf3 100644
Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ
diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi
index 6fae3b0bee..c7b1fe5787 100644
Binary files a/icons/obj/decals.dmi and b/icons/obj/decals.dmi differ
diff --git a/icons/obj/fence.dmi b/icons/obj/fence.dmi
new file mode 100644
index 0000000000..31b1abef3c
Binary files /dev/null and b/icons/obj/fence.dmi differ
diff --git a/icons/obj/flora/rocks.dmi b/icons/obj/flora/rocks.dmi
index 0974360e27..12d4f2c8ee 100644
Binary files a/icons/obj/flora/rocks.dmi and b/icons/obj/flora/rocks.dmi differ
diff --git a/icons/turf/areas.dmi b/icons/turf/areas.dmi
old mode 100755
new mode 100644
index de00a11f60..1132fa10a9
Binary files a/icons/turf/areas.dmi and b/icons/turf/areas.dmi differ
diff --git a/icons/turf/outdoors.dmi b/icons/turf/outdoors.dmi
index ec94c60efd..b8af78d986 100644
Binary files a/icons/turf/outdoors.dmi and b/icons/turf/outdoors.dmi differ
diff --git a/maps/plane/plane-1.dmm b/maps/plane/plane-1.dmm
index 8017636b44..5fb3912356 100644
--- a/maps/plane/plane-1.dmm
+++ b/maps/plane/plane-1.dmm
@@ -1,71 +1,71 @@
-"a" = (/turf/unsimulated/wall/planetary/sif,/area/plane_ground)
-"b" = (/turf/simulated/floor/outdoors/dirt,/area/plane_ground)
-"c" = (/obj/effect/landmark/start,/turf/simulated/floor/outdoors/dirt,/area/plane_ground)
-"d" = (/obj/effect/landmark{name = "JoinLate"},/turf/simulated/floor/outdoors/dirt,/area/plane_ground)
-
-(1,1,1) = {"
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbdddbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbdddbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbdddbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-"}
+"a" = (/turf/unsimulated/wall/planetary/sif,/area/plane_ground)
+"b" = (/turf/simulated/floor/outdoors/dirt,/area/plane_ground)
+"c" = (/obj/effect/landmark{name = "JoinLate"},/turf/simulated/floor/outdoors/dirt,/area/plane_ground)
+"d" = (/obj/effect/landmark/start,/turf/simulated/floor/outdoors/dirt,/area/plane_ground)
+
+(1,1,1) = {"
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbdbcccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+"}
diff --git a/maps/southern_cross/southern_cross_defines.dm b/maps/southern_cross/southern_cross_defines.dm
index 6c3b60aa40..f55067f0a3 100644
--- a/maps/southern_cross/southern_cross_defines.dm
+++ b/maps/southern_cross/southern_cross_defines.dm
@@ -213,46 +213,49 @@
teleport_y = world.maxy - 1
teleport_z = Z_LEVEL_SURFACE_MINE
+/datum/planet/sif
+ expected_z_levels = list(
+ Z_LEVEL_SURFACE,
+ Z_LEVEL_SURFACE_MINE,
+ Z_LEVEL_SURFACE_WILD,
+ Z_LEVEL_TRANSIT
+ )
-/obj/effect/step_trigger/teleporter/bridge/east_to_west/New()
- ..()
+/obj/effect/step_trigger/teleporter/bridge/east_to_west/Initialize()
teleport_x = src.x - 4
teleport_y = src.y
teleport_z = src.z
+ return ..()
-/obj/effect/step_trigger/teleporter/bridge/east_to_west/small/New()
- ..()
+/obj/effect/step_trigger/teleporter/bridge/east_to_west/small/Initialize()
teleport_x = src.x - 3
teleport_y = src.y
teleport_z = src.z
+ return ..()
-
-/obj/effect/step_trigger/teleporter/bridge/west_to_east/New()
- ..()
+/obj/effect/step_trigger/teleporter/bridge/west_to_east/Initialize()
teleport_x = src.x + 4
teleport_y = src.y
teleport_z = src.z
+ return ..()
-/obj/effect/step_trigger/teleporter/bridge/west_to_east/small/New()
- ..()
+/obj/effect/step_trigger/teleporter/bridge/west_to_east/small/Initialize()
teleport_x = src.x + 3
teleport_y = src.y
teleport_z = src.z
+ return ..()
-
-/obj/effect/step_trigger/teleporter/bridge/north_to_south/New()
- ..()
+/obj/effect/step_trigger/teleporter/bridge/north_to_south/Initialize()
teleport_x = src.x
teleport_y = src.y - 4
teleport_z = src.z
+ return ..()
-
-/obj/effect/step_trigger/teleporter/bridge/south_to_north/New()
- ..()
+/obj/effect/step_trigger/teleporter/bridge/south_to_north/Initialize()
teleport_x = src.x
teleport_y = src.y + 4
teleport_z = src.z
-
+ return ..()
/datum/planet/sif
expected_z_levels = list(
diff --git a/maps/submaps/surface_submaps/mountains/lava_trench.dmm b/maps/submaps/surface_submaps/mountains/lava_trench.dmm
new file mode 100644
index 0000000000..76b9f6f01f
--- /dev/null
+++ b/maps/submaps/surface_submaps/mountains/lava_trench.dmm
@@ -0,0 +1,146 @@
+"aa" = (/turf/template_noop,/area/template_noop)
+"ab" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 9},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"ac" = (/obj/structure/cliff/automatic,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"ad" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 5},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"ae" = (/obj/structure/cliff/automatic/corner{icon_state = "cliffbuilder-corner"; dir = 9},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"af" = (/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"ag" = (/obj/structure/cliff/automatic/corner,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"ah" = (/obj/structure/fence/end{icon_state = "end"; dir = 4},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"ai" = (/obj/structure/fence/post{icon_state = "post"; dir = 4},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"aj" = (/obj/structure/fence/door/opened,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"ak" = (/obj/structure/fence/end{icon_state = "end"; dir = 8},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"al" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 8},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"am" = (/obj/structure/fence/end{icon_state = "end"; dir = 1},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"an" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 9},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"ao" = (/obj/structure/cliff/automatic,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"ap" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 5},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aq" = (/obj/structure/sign/warning/lava,/turf/simulated/wall,/area/submap/lava_trench)
+"ar" = (/obj/structure/fence/post,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"as" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 6},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"at" = (/obj/structure/cliff/automatic/corner{icon_state = "cliffbuilder-corner"; dir = 9},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"au" = (/turf/simulated/floor/lava,/area/submap/lava_trench)
+"av" = (/obj/structure/cliff/automatic/corner,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aw" = (/obj/structure/railing{icon_state = "railing0"; dir = 4},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"ax" = (/obj/structure/catwalk,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"ay" = (/obj/structure/railing{icon_state = "railing0"; dir = 8},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"az" = (/obj/structure/fence/door/opened{icon_state = "door_opened"; dir = 8},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"aA" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 8},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aB" = (/turf/simulated/mineral/floor/ignore_mapgen,/area/template_noop)
+"aC" = (/turf/simulated/floor/outdoors/rocks/caves,/area/template_noop)
+"aD" = (/obj/structure/cliff/automatic,/obj/structure/railing{icon_state = "railing0"; dir = 4},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aE" = (/obj/structure/cliff/automatic,/obj/structure/railing{icon_state = "railing0"; dir = 8},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aF" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 10},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aG" = (/obj/structure/cliff/automatic/corner{icon_state = "cliffbuilder-corner"; dir = 10},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aH" = (/obj/structure/railing{icon_state = "railing0"; dir = 4},/obj/effect/step_trigger/teleporter/offset/east,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aI" = (/obj/structure/catwalk,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aJ" = (/obj/structure/ore_box,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"aK" = (/obj/structure/railing{icon_state = "railing0"; dir = 8},/obj/effect/step_trigger/teleporter/offset/west,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aL" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 4},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"aM" = (/obj/machinery/light/small/flicker{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"aN" = (/obj/machinery/door/airlock/hatch{normalspeed = 0; safe = 0},/obj/effect/map_effect/interval/effect_emitter/sparks,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"aO" = (/turf/simulated/wall/rshull,/area/submap/lava_trench/outpost)
+"aP" = (/obj/machinery/door/airlock/hatch{normalspeed = 0; safe = 0},/obj/effect/map_effect/interval/effect_emitter/sparks,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"aQ" = (/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"aR" = (/obj/effect/floor_decal/corner_oldtile/blue/full{icon_state = "corner_oldtile_full"; dir = 8},/obj/machinery/microscope,/obj/structure/table/standard,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"aS" = (/obj/effect/floor_decal/corner_oldtile/blue/full{icon_state = "corner_oldtile_full"; dir = 8},/obj/structure/table/standard,/obj/random/unidentified_medicine/scientific,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"aT" = (/obj/structure/fence/end,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"aU" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 2},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aV" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 10},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"aW" = (/obj/structure/cliff/automatic/corner{icon_state = "cliffbuilder-corner"; dir = 10},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"aX" = (/obj/structure/cliff/automatic/corner{icon_state = "cliffbuilder-corner"; dir = 6},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aY" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 2},/obj/structure/railing{icon_state = "railing0"; dir = 4},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"aZ" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 2},/obj/structure/railing{icon_state = "railing0"; dir = 8},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"ba" = (/obj/machinery/crystal/lava,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bb" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 4},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"bc" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 6},/turf/simulated/floor/lava,/area/submap/lava_trench)
+"bd" = (/obj/structure/table/steel,/obj/item/weapon/storage/excavation,/obj/item/device/measuring_tape,/obj/effect/floor_decal/corner_oldtile/purple{icon_state = "corner_oldtile"; dir = 4},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"be" = (/turf/simulated/mineral/ignore_mapgen,/area/template_noop)
+"bf" = (/obj/structure/railing,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bg" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 10},/obj/structure/railing,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"bh" = (/obj/structure/cliff/automatic/corner{icon_state = "cliffbuilder-corner"; dir = 10},/obj/structure/railing,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"bi" = (/obj/structure/railing,/obj/effect/step_trigger/teleporter/offset/south,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"bj" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 4},/obj/structure/railing,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"bk" = (/obj/structure/catwalk,/obj/structure/railing,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bl" = (/obj/structure/catwalk,/obj/structure/railing,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"bm" = (/obj/structure/fence/door/opened{icon_state = "door_opened"; dir = 4},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bn" = (/obj/structure/cliff/automatic{icon_state = "cliffbuilder"; dir = 2},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bo" = (/obj/effect/floor_decal/corner_oldtile/purple/full{icon_state = "corner_oldtile_full"; dir = 1},/obj/machinery/space_heater,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bp" = (/obj/machinery/floodlight,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bq" = (/obj/machinery/newscaster{pixel_y = 32},/obj/machinery/light/small/flicker{icon_state = "bulb1"; dir = 1},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"br" = (/obj/effect/floor_decal/corner_oldtile/blue{icon_state = "corner_oldtile"; dir = 1},/obj/structure/bed/chair/office/light{icon_state = "officechair_white"; dir = 4},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bs" = (/turf/simulated/floor/tiled/old_tile/gray,/area/submap/lava_trench/outpost)
+"bt" = (/obj/effect/floor_decal/corner_oldtile/purple{icon_state = "corner_oldtile"; dir = 4},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bu" = (/obj/structure/cliff/automatic/corner{icon_state = "cliffbuilder-corner"; dir = 6},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bv" = (/obj/item/slime_crystal,/obj/item/slime_crystal,/obj/item/slime_crystal,/obj/effect/floor_decal/corner_oldtile/blue{icon_state = "corner_oldtile"; dir = 9},/obj/structure/table/standard,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bw" = (/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"bx" = (/obj/machinery/crystal/ice,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"by" = (/obj/machinery/ai_status_display{pixel_y = 32},/obj/machinery/light/small/flicker{icon_state = "bulb1"; dir = 1},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bz" = (/obj/effect/floor_decal/corner_oldtile{icon_state = "corner_oldtile"; dir = 1},/turf/simulated/floor/tiled/old_tile/gray,/area/submap/lava_trench/outpost)
+"bA" = (/obj/effect/floor_decal/corner_oldtile{icon_state = "corner_oldtile"; dir = 4},/turf/simulated/floor/tiled/old_tile/gray,/area/submap/lava_trench/outpost)
+"bB" = (/obj/effect/floor_decal/corner_oldtile/blue{icon_state = "corner_oldtile"; dir = 8},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bC" = (/obj/structure/table/rack,/obj/item/weapon/shovel,/obj/effect/floor_decal/corner_oldtile/purple/full{icon_state = "corner_oldtile_full"; dir = 1},/obj/item/weapon/pickaxe/drill,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bD" = (/obj/effect/step_trigger/teleporter/offset/north,/turf/simulated/floor/lava,/area/submap/lava_trench)
+"bE" = (/obj/machinery/crystal/lava,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"bF" = (/obj/structure/table/rack,/obj/random/tool/powermaint,/obj/random/tool/powermaint,/obj/effect/floor_decal/corner_oldtile/purple{icon_state = "corner_oldtile"; dir = 6},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bG" = (/obj/effect/floor_decal/corner_oldtile/purple,/obj/structure/table/steel,/obj/item/device/xenoarch_multi_tool,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bH" = (/obj/effect/floor_decal/corner_oldtile/purple,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bI" = (/obj/item/device/gps/science{gps_tag = "CRYSTALS"},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bK" = (/obj/effect/floor_decal/corner_oldtile/blue/full,/obj/random/drinkbottle,/obj/random/maintenance/research,/obj/structure/table/standard,/obj/machinery/light/small/flicker{icon_state = "bulb1"; dir = 8},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bL" = (/obj/structure/flora/pottedplant/crystal,/obj/effect/floor_decal/corner_oldtile/blue{icon_state = "corner_oldtile"; dir = 8},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bM" = (/obj/structure/cult/pylon,/obj/effect/floor_decal/industrial/outline,/turf/simulated/floor/tiled/old_tile/gray,/area/submap/lava_trench/outpost)
+"bN" = (/obj/structure/anomaly_container,/obj/machinery/artifact,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bO" = (/obj/machinery/light/small/flicker{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bP" = (/obj/effect/floor_decal/corner_oldtile/purple/full{icon_state = "corner_oldtile_full"; dir = 4},/obj/structure/table/steel,/obj/machinery/recharger,/obj/machinery/light/small/flicker{icon_state = "bulb1"; dir = 4},/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bQ" = (/obj/machinery/light/small/flicker{icon_state = "bulb1"; dir = 8},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bR" = (/obj/machinery/light/small/flicker{icon_state = "bulb1"; dir = 1},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bS" = (/obj/effect/floor_decal/corner_oldtile/blue{icon_state = "corner_oldtile"; dir = 1},/obj/structure/loot_pile/surface/medicine_cabinet{pixel_y = 28},/obj/structure/table/standard,/obj/item/device/healthanalyzer/improved,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bT" = (/obj/machinery/suspension_gen{anchored = 1},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bU" = (/obj/machinery/light/small/flicker,/obj/structure/ore_box,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"bW" = (/obj/structure/anomaly_container,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"bX" = (/obj/effect/floor_decal/corner_oldtile/purple/full{icon_state = "corner_oldtile_full"; dir = 4},/obj/item/weapon/storage/box/samplebags,/obj/structure/table/steel,/obj/item/stack/flag/red,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"bY" = (/obj/machinery/crystal,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"bZ" = (/obj/structure/table/steel,/obj/item/weapon/stock_parts/subspace/crystal,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"ca" = (/obj/structure/table/steel,/obj/item/stack/material/diamond,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"cb" = (/obj/structure/loot_pile/surface/bones,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"ce" = (/obj/effect/floor_decal/corner_oldtile/blue/full,/obj/structure/table/standard,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"ch" = (/obj/structure/loot_pile/maint/trash,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+"cj" = (/obj/item/clothing/head/bio_hood/anomaly,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"ck" = (/obj/item/clothing/suit/bio_suit/anomaly,/turf/simulated/floor/tiled/old_tile,/area/submap/lava_trench/outpost)
+"co" = (/obj/machinery/floodlight,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"cp" = (/obj/machinery/light/small/flicker,/obj/structure/closet/crate/secure/loot,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"cq" = (/obj/item/weapon/banner/nt,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"cr" = (/obj/structure/table/steel,/obj/item/weapon/material/shard/phoron,/turf/simulated/floor/tiled/asteroid_steel,/area/submap/lava_trench)
+"cs" = (/obj/item/weapon/banner/nt,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/lava_trench)
+
+(1,1,1) = {"
+aBaBabacacacacacacacacacacadaBaBaBaBaBaCaCaCaBaBaBaBaBaBaBaBaBaBaBaBbebebeaaaaaaaaaaaaaaaaaaaaaa
+aBabaeafafafafafafafafafafagacacacacahaiajaiakacadaBaBaBaBaBaBaBaBaBaBbebebeaaaaaaaaaaaaaaaaaaaa
+aBalafafafafafafafafafafafafafafafafafafafafafafagacacacacacacacadaBaBaBbebebeaaaaaaaaaaaaaaaaaa
+aBamafafbaanaoaoaoaoapafafafafafafafafafafafafaqafafafafafafafafagadaBaBaBbebebeaaaaaaaaaaaaaaaa
+afarafafanatauauauauavaoaoaoaoaoaoaoapawaxayafafafafafafafafafafafagadaBaBaBbebebeaaaaaaaaaaaaaa
+afazafafaAauauauauauauauauauauauauauavaDaxaEaoaoaoaoaoaoaoapafafafafagadaBaBbebebebebebebebeaaaa
+afarafafaFaGauauauauauauauauauauauauauaHaxaKauauauauauauauavapafafafafaLaBaBaBaBbebebebebebebeaa
+aBaTafafafaFaUaGauauauauauauauafauauauaHaIaKauauauauauauauauavapafafafaLaBaBaBaBaBaBaBaBaBbebeaa
+aBalafafafafafaFaGauafauauauauauauauauaHaIaKauauafauauafafauauavapafafagacacadaBaBaBaBaBaBbebeaa
+aBaVaWafafaqafafaFaUafaUaGauauauauauaXaYaIaZaGauauauauauafbaauaubbafafafafafagacacacadaBaBaBaBaB
+aBaBaVaWafafafafafafafafaFaUaUaUaUaUbcawaxayaFaUaUaGauauauauauaubbafafafafafafafafafamaBaBaBaBaB
+aBaBaBalafafafafafafafafafafafafafafafafbwafafafbfbgbhbibibibibibjbfbfafafbaafafafafarafaBaBaBaB
+beaBaBalafafafafbwbwbwbwbwafafafafafafafbwbwbwbwbkbkblblblblblblblbkbkafafafafafafafbmafaBaBaBaB
+beaBaBalafafafafbwbxbEbYbwbwbwbwbwbwbwbwbwbwbwafafafaAbDbDbDbDbDavapafafafafafafafafarafaBaBaBaB
+beaBaBalafafafafbwbZcacrbwbwbwcqbUaJaOaNaOcocpcsafaqaAauauauauauaubbafafafafafafafafaTafaBaBaBaB
+beaBaBalafafafafbwbwbwbwbwbwaJaOaOaOaObOaOaOaOaOafafaFaGauauafauaubbafafaqbpafafafafaLafaBaBaBaB
+beaBaBaVbnbnaWafafbwbwbwbwbwaOaOaSbSaOaPaObdboaOaOafafaAauauauauauavapafafafafafafafaLaBaBaBaBaB
+beaBaBaBaBaBalafafafafafafafaOaRbraQbqaQbycjbtbCaOafafaAauauauauauauavapafafafbaafafaLaBaBbeaBaB
+beaBaBaBaBaBalafafafafafafaMaObvaQaQaQaQaQcbbIbFaObQafaFaGauauauauauaubbafafafafafafaLaBaBbebebe
+bebebebeaBaBaVbnbnbnbnaWafafaOcebBaQaQbTckaQbHbXaOafafafaAauauafauauaubbafafafafafafaLaBaBbebeaa
+bebebebeaBaBaBaBaBaBaBalafafaOaObKbLbzbsbAbGbPaOaOafafafaAauauafbaauaubbafafbaafafafaLaBaBbebeaa
+aaaabebebeaBaBaBaBaBaBalafafafaOaOaObsbMbsaOaOaObNafafafafafauafafauaubbafafafafafbuasaBaBbebeaa
+aaaaaabebebebebebeaBaBaVbnaWafafchaOaOaOaOaObNbWafafafafaAauauauafauaubbafafafbubnasaBaBaBbebeaa
+aaaaaaaabebebebebeaBaBaBaBalafafafafafbRafafafafafafafafaAauauauauauauavapafafaLaBaBaBaBbebebeaa
+aaaaaaaaaaaaaabebebeaBaBaBalafafafafafafafafafafafafafafaFaGauauauauauaubbafafaLaBaBaBbebebeaaaa
+aaaaaaaaaaaaaaaabebebebeaBaVbnbnbnbnbnbnbnbnbnbnbnaWafafafaFaGauauauauaubbafafaLaBaBbebebeaaaaaa
+aaaaaaaaaaaaaaaaaabebebeaBaBaBaBaBaBaBaBaBaBaBaBaBalafafafafaFaUaUaUaUaUbcafafaLaBaBbebeaaaaaaaa
+aaaaaaaaaaaaaaaaaaaabebebeaBaBaBaBaBaBaBaBaBaBaBaBaVbnaWafafafafafafafafafafafaLaBaBbebeaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaabebebebebebebebebebebebeaBaBaBaBaVaWafafafafafafafafafafaLaBaBbebeaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaabebebebebebebebebebebebeaBaBaBaBaVbnbnbnbnahaiajaiakbnasaBaBbebeaaaaaaaa
+"}
diff --git a/maps/submaps/surface_submaps/mountains/mountains.dm b/maps/submaps/surface_submaps/mountains/mountains.dm
index 56a267c475..af6363a18a 100644
--- a/maps/submaps/surface_submaps/mountains/mountains.dm
+++ b/maps/submaps/surface_submaps/mountains/mountains.dm
@@ -32,6 +32,7 @@
#include "BlastMine1.dmm"
#include "crashedcontainmentshuttle.dmm"
#include "deadspy.dmm"
+#include "lava_trench.dmm"
#endif
// The 'mountains' is the mining z-level, and has a lot of caves.
@@ -272,3 +273,10 @@
desc = "An abandoned blast mining site, seems that local wildlife has moved in."
mappath = 'maps/submaps/surface_submaps/mountains/BlastMine1.dmm'
cost = 20
+
+/datum/map_template/surface/mountains/deep/lava_trench
+ name = "lava trench"
+ desc = "A long stretch of lava underground, almost river-like, with a small crystal research outpost on the side."
+ mappath = 'maps/submaps/surface_submaps/mountains/lava_trench.dmm'
+ cost = 20
+ fixed_orientation = TRUE
\ No newline at end of file
diff --git a/maps/submaps/surface_submaps/mountains/mountains_areas.dm b/maps/submaps/surface_submaps/mountains/mountains_areas.dm
index 9bcce0da1e..53fada4b7c 100644
--- a/maps/submaps/surface_submaps/mountains/mountains_areas.dm
+++ b/maps/submaps/surface_submaps/mountains/mountains_areas.dm
@@ -120,4 +120,13 @@
/area/submap/deadspy
name = "Dead Spy"
- ambience = AMBIENCE_FOREBODING
\ No newline at end of file
+ ambience = AMBIENCE_FOREBODING
+
+/area/submap/lava_trench
+ name = "Lava Trench"
+ ambience = AMBIENCE_LAVA
+
+/area/submap/lava_trench/outpost
+ name = "Trench Outpost"
+ requires_power = FALSE
+ icon_state = "submap2"
\ No newline at end of file
diff --git a/vorestation.dme b/vorestation.dme
index 75d3043cfc..02f03559d9 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -1191,6 +1191,7 @@
#include "code\game\objects\structures\bedsheet_bin.dm"
#include "code\game\objects\structures\bonfire.dm"
#include "code\game\objects\structures\catwalk.dm"
+#include "code\game\objects\structures\cliff.dm"
#include "code\game\objects\structures\coathanger.dm"
#include "code\game\objects\structures\curtains.dm"
#include "code\game\objects\structures\displaycase.dm"
@@ -1198,6 +1199,7 @@
#include "code\game\objects\structures\door_assembly.dm"
#include "code\game\objects\structures\electricchair.dm"
#include "code\game\objects\structures\extinguisher.dm"
+#include "code\game\objects\structures\fence.dm"
#include "code\game\objects\structures\fitness.dm"
#include "code\game\objects\structures\flora.dm"
#include "code\game\objects\structures\flora_vr.dm"
@@ -1303,7 +1305,11 @@
#include "code\game\turfs\simulated\floor_icon.dm"
#include "code\game\turfs\simulated\floor_static.dm"
#include "code\game\turfs\simulated\floor_types.dm"
+<<<<<<< HEAD:vorestation.dme
#include "code\game\turfs\simulated\floor_types_vr.dm"
+=======
+#include "code\game\turfs\simulated\lava.dm"
+>>>>>>> afa149c... Adds New PoI Features + Bonus PoI (#5796):polaris.dme
#include "code\game\turfs\simulated\wall_attacks.dm"
#include "code\game\turfs\simulated\wall_icon.dm"
#include "code\game\turfs\simulated\wall_types.dm"