diff --git a/code/controllers/Processes/planet.dm b/code/controllers/Processes/planet.dm
new file mode 100644
index 00000000000..31406e92a09
--- /dev/null
+++ b/code/controllers/Processes/planet.dm
@@ -0,0 +1,12 @@
+/datum/controller/process/planet
+ var/list/planets = list()
+
+/datum/controller/process/planet/setup()
+ name = "planet"
+ schedule_interval = 600 // every minute
+ planet_sif = new()
+ planets.Add(planet_sif)
+
+/datum/controller/process/planet/doWork()
+ for(var/datum/planet/P in planets)
+ P.process(schedule_interval / 10)
\ No newline at end of file
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index 7a1b12509c6..d1ab11e7067 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -347,7 +347,7 @@
put_mob(usr)
return
-/atom/proc/return_air_for_internal_lifeform()
+/atom/proc/return_air_for_internal_lifeform(var/mob/living/lifeform)
return return_air()
/obj/machinery/atmospherics/unary/cryo_cell/return_air_for_internal_lifeform()
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index 0ad1fb84045..9b731a0fa8d 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -32,6 +32,19 @@
..()
icon_state = "tree_[rand(1, 6)]"
+/obj/structure/flora/tree/sif
+ name = "glowing tree"
+ desc = "It's a tree, except this one seems quite alien. It glows a deep blue."
+ icon = 'icons/obj/flora/deadtrees.dmi'
+ icon_state = "tree_sif"
+
+/obj/structure/flora/tree/sif/New()
+ update_icon()
+
+/obj/structure/flora/tree/sif/update_icon()
+ set_light(5, 1, "#33ccff")
+ overlays.Cut()
+ overlays.Add(image(icon = 'icons/obj/flora/deadtrees.dmi', icon_state = "[icon_state]_glow", layer = LIGHTING_LAYER + 0.1))
//grass
/obj/structure/flora/grass
diff --git a/code/game/turfs/simulated/floor_icon.dm b/code/game/turfs/simulated/floor_icon.dm
index cdde744bd45..0ad44622b76 100644
--- a/code/game/turfs/simulated/floor_icon.dm
+++ b/code/game/turfs/simulated/floor_icon.dm
@@ -72,6 +72,9 @@ var/list/flooring_cache = list()
if(!isnull(burnt) && (flooring.flags & TURF_CAN_BURN))
overlays |= get_flooring_overlay("[flooring.icon_base]-burned-[burnt]","[flooring.icon_base]_burned[burnt]")
+ if(weather_overlay)
+ overlays += weather_overlay
+
if(update_neighbors)
for(var/turf/simulated/floor/F in range(src, 1))
if(F == src)
diff --git a/code/game/turfs/simulated/outdoors/dirt.dm b/code/game/turfs/simulated/outdoors/dirt.dm
new file mode 100644
index 00000000000..1d735d81be2
--- /dev/null
+++ b/code/game/turfs/simulated/outdoors/dirt.dm
@@ -0,0 +1,6 @@
+/turf/simulated/floor/outdoors/dirt
+ name = "dirt"
+ desc = "Quite dirty!"
+ icon_state = "dirt-dark"
+ edge_blending_priority = 1
+ turf_layers = list(/turf/simulated/floor/outdoors/rocks)
\ No newline at end of file
diff --git a/code/game/turfs/simulated/outdoors/grass.dm b/code/game/turfs/simulated/outdoors/grass.dm
new file mode 100644
index 00000000000..98b7d3dfba4
--- /dev/null
+++ b/code/game/turfs/simulated/outdoors/grass.dm
@@ -0,0 +1,42 @@
+var/list/grass_types = list(
+ /obj/structure/flora/ausbushes/sparsegrass,
+ /obj/structure/flora/ausbushes/fullgrass
+)
+
+/turf/simulated/floor/outdoors/grass
+ name = "grass"
+ icon_state = "grass"
+ edge_blending_priority = 3
+ turf_layers = list(
+ /turf/simulated/floor/outdoors/rocks,
+ /turf/simulated/floor/outdoors/dirt
+ )
+ var/grass_chance = 20
+
+/turf/simulated/floor/outdoors/grass/sif
+ name = "growth"
+ icon_state = "grass_sif"
+ edge_blending_priority = 3
+ grass_chance = 0
+
+/turf/simulated/floor/outdoors/grass/New()
+ if(prob(50))
+ icon_state += "2"
+ //edge_blending_priority++
+
+ if(grass_chance && prob(grass_chance))
+ var/grass_type = pick(grass_types)
+ new grass_type(src)
+ ..()
+
+/turf/simulated/floor/outdoors/grass/forest
+ name = "thick grass"
+ icon_state = "grass-dark"
+ grass_chance = 80
+ //tree_prob = 20
+ edge_blending_priority = 4
+
+/turf/simulated/floor/outdoors/grass/sif/forest
+ name = "thick growth"
+ icon_state = "grass_sif_dark"
+ edge_blending_priority = 4
\ No newline at end of file
diff --git a/code/game/turfs/simulated/outdoors/outdoors.dm b/code/game/turfs/simulated/outdoors/outdoors.dm
new file mode 100644
index 00000000000..0ee844f3207
--- /dev/null
+++ b/code/game/turfs/simulated/outdoors/outdoors.dm
@@ -0,0 +1,109 @@
+var/list/turf_edge_cache = list()
+var/list/outdoor_turfs = list()
+
+/turf/
+ // If greater than 0, this turf will apply edge overlays on top of other turfs cardinally adjacent to it, if those adjacent turfs are of a different icon_state,
+ // and if those adjacent turfs have a lower edge_blending_priority.
+ var/edge_blending_priority = 0
+ // Outdoors var determines if the game should consider the turf to be 'outdoors', which controls certain things such as weather effects.
+ var/outdoors = FALSE
+ // This holds the image for the current weather effect.
+ var/image/weather_overlay = null
+
+/turf/simulated/floor/outdoors
+ name = "generic ground"
+ desc = "Rather boring."
+ icon = 'icons/turf/outdoors.dmi'
+ icon_state = null
+ edge_blending_priority = 1
+ outdoors = TRUE // This variable is used for weather effects.
+ // When a turf gets demoted or promoted, this list gets adjusted. The top-most layer is the layer on the bottom of the list, due to how pop() works.
+ var/list/turf_layers = list(/turf/simulated/floor/outdoors/rocks)
+
+/turf/simulated/floor/outdoors/initialize()
+ update_icon()
+ ..()
+
+/turf/simulated/floor/New()
+ if(outdoors)
+ outdoor_turfs.Add(src)
+ ..()
+
+/turf/simulated/floor/Destroy()
+ if(outdoors)
+ outdoor_turfs.Remove(src)
+ ..()
+
+/turf/simulated/floor/proc/update_icon_edge()
+ if(edge_blending_priority)
+ 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)
+ var/cache_key = "[T.get_edge_icon_state()]-[checkdir]"
+ if(!turf_edge_cache[cache_key])
+ turf_edge_cache[cache_key] = image(icon = 'icons/turf/outdoors_edge.dmi', icon_state = "[T.get_edge_icon_state()]-edge", dir = checkdir)
+ overlays += turf_edge_cache[cache_key]
+
+/turf/simulated/proc/get_edge_icon_state()
+ return icon_state
+
+/turf/simulated/floor/outdoors/update_icon()
+ overlays.Cut()
+ update_icon_edge()
+ ..()
+
+/turf/simulated/floor/outdoors/mud
+ name = "grass"
+ icon_state = "mud_dark"
+ edge_blending_priority = 2
+
+/turf/simulated/floor/outdoors/rocks
+ name = "rocks"
+ desc = "Hard as a rock."
+ icon_state = "rock"
+ edge_blending_priority = 1
+
+
+// This proc adds a 'layer' on top of the turf.
+/turf/simulated/floor/outdoors/proc/promote(var/new_turf_type)
+ var/list/new_turf_layer_list = turf_layers.Copy()
+ var/list/coords = list(x, y, z)
+
+ new_turf_layer_list.Add(src.type)
+
+ ChangeTurf(new_turf_type)
+ var/turf/simulated/floor/outdoors/T = locate(coords[1], coords[2], coords[3])
+ if(istype(T))
+ T.turf_layers = new_turf_layer_list.Copy()
+
+// This proc removes the topmost layer.
+/turf/simulated/floor/outdoors/proc/demote()
+ if(!turf_layers.len)
+ return // Cannot demote further.
+ var/list/new_turf_layer_list = turf_layers.Copy()
+ var/list/coords = list(x, y, z)
+
+ ChangeTurf(pop(new_turf_layer_list))
+ var/turf/simulated/floor/outdoors/T = locate(coords[1], coords[2], coords[3])
+ if(istype(T))
+ T.turf_layers = new_turf_layer_list.Copy()
+
+// Called by weather processes, and maybe technomancers in the future.
+/turf/simulated/floor/proc/chill()
+ return
+
+/turf/simulated/floor/outdoors/chill()
+ promote(/turf/simulated/floor/outdoors/snow)
+
+/turf/simulated/floor/outdoors/snow/chill()
+ return // Todo: Add heavy snow.
+
+/turf/simulated/floor/outdoors/ex_act(severity)
+ switch(severity)
+ if(2)
+ if(prob(33))
+ return
+ if(3)
+ if(prob(66))
+ return
+ demote()
\ No newline at end of file
diff --git a/code/game/turfs/simulated/outdoors/snow.dm b/code/game/turfs/simulated/outdoors/snow.dm
new file mode 100644
index 00000000000..474bdb171c0
--- /dev/null
+++ b/code/game/turfs/simulated/outdoors/snow.dm
@@ -0,0 +1,35 @@
+/turf/simulated/floor/outdoors/snow
+ name = "snow"
+ icon_state = "snow"
+ edge_blending_priority = 5
+ movement_cost = 2
+ turf_layers = list(
+ /turf/simulated/floor/outdoors/rocks,
+ /turf/simulated/floor/outdoors/dirt
+ )
+ var/list/crossed_dirs = list()
+
+/turf/simulated/floor/outdoors/snow/Entered(atom/A)
+ if(isliving(A))
+ var/mdir = "[A.dir]"
+ crossed_dirs[mdir] = 1
+ update_icon()
+ . = ..()
+
+/turf/simulated/floor/outdoors/snow/update_icon()
+ overlays.Cut()
+ ..()
+ for(var/d in crossed_dirs)
+ overlays += image(icon = 'icons/turf/outdoors.dmi', icon_state = "snow_footprints", dir = text2num(d))
+
+/turf/simulated/floor/outdoors/snow/attackby(var/obj/item/W, var/mob/user)
+ if(istype(W, /obj/item/weapon/shovel))
+ to_chat(user, "You begin to remove \the [src] with your [W].")
+ if(do_after(user, 4 SECONDS))
+ to_chat(user, "\The [src] has been dug up, and now lies in a pile nearby.")
+ new /obj/item/stack/material/snow(src)
+ demote()
+ else
+ to_chat(user, "You decide to not finish removing \the [src].")
+ else
+ ..()
diff --git a/code/game/turfs/simulated/water.dm b/code/game/turfs/simulated/water.dm
new file mode 100644
index 00000000000..cad62cc8de2
--- /dev/null
+++ b/code/game/turfs/simulated/water.dm
@@ -0,0 +1,96 @@
+// This doesn't inherit from /outdoors/ so that the pool can use it as well.
+/turf/simulated/floor/water
+ name = "shallow water"
+ desc = "A body of water. It seems shallow enough to walk through, if needed."
+ icon = 'icons/turf/outdoors.dmi'
+ icon_state = "water_shallow"
+ var/under_state = "rock"
+ edge_blending_priority = -1
+ movement_cost = 4
+ outdoors = TRUE
+ var/movement_message = "You are slowed considerably from the water as you move across it." // Displayed to mobs crossing from one water tile to another.
+ var/depth = 1 // Higher numbers indicates deeper water.
+
+/turf/simulated/floor/water/New()
+ update_icon()
+ ..()
+
+/turf/simulated/floor/water/update_icon()
+ ..() // To get the edges. This also gets rid of other overlays so it needs to go first.
+ var/image/floorbed_sprite = image(icon = 'icons/turf/outdoors.dmi', icon_state = under_state)
+ underlays.Add(floorbed_sprite)
+ update_icon_edge()
+
+/turf/simulated/floor/water/get_edge_icon_state()
+ return "water_shallow"
+
+/turf/simulated/floor/water/return_air_for_internal_lifeform(var/mob/living/L)
+ if(L && L.lying)
+ if(L.can_breathe_water()) // For squid.
+ var/datum/gas_mixture/water_breath = new()
+ var/datum/gas_mixture/above_air = return_air()
+ var/amount = 300
+ water_breath.adjust_gas("oxygen", amount) // Assuming water breathes just extract the oxygen directly from the water.
+ water_breath.temperature = above_air.temperature
+ return water_breath
+ else
+ return null // Lying down means they're submerged, which means no air.
+ return return_air() // Otherwise their head is above the water, so get the air from the atmosphere instead.
+
+/turf/simulated/floor/water/Entered(atom/movable/AM, atom/oldloc)
+ if(istype(AM, /mob/living))
+ var/mob/living/L = AM
+ L.update_water()
+ if(!istype(oldloc, /turf/simulated/floor/water))
+ to_chat(L, "You get drenched in water from entering \the [src]!")
+ else
+ to_chat(L, "[movement_message]")
+ AM.water_act(5)
+ ..()
+
+/turf/simulated/floor/water/Exited(atom/movable/AM, atom/newloc)
+ if(istype(AM, /mob/living))
+ var/mob/living/L = AM
+ L.update_water()
+ if(!istype(newloc, /turf/simulated/floor/water))
+ to_chat(L, "You climb out of \the [src].")
+ ..()
+
+/turf/simulated/floor/water/deep
+ name = "deep water"
+ desc = "A body of water. It seems quite deep."
+ icon_state = "seadeep" // So it shows up in the map editor as water.
+ under_state = "abyss"
+ edge_blending_priority = -2
+ movement_cost = 8
+ movement_message = "You swim forwards."
+ depth = 2
+
+/turf/simulated/floor/water/pool
+ name = "pool"
+ desc = "Don't worry, it's not closed."
+ under_state = "pool"
+ outdoors = FALSE
+
+/mob/living/proc/can_breathe_water()
+ return FALSE
+
+/mob/living/carbon/human/can_breathe_water()
+ if(species)
+ return species.can_breathe_water()
+ return ..()
+
+/mob/living/proc/check_submerged()
+ var/turf/simulated/floor/water/T = loc
+ if(istype(T))
+ return T.depth
+ return 0
+
+// Use this to have things react to having water applied to them.
+/atom/movable/proc/water_act(amount)
+ return
+
+/mob/living/water_act(amount)
+ adjust_fire_stacks(amount * 5)
+ for(var/atom/movable/AM in contents)
+ AM.water_act(amount)
\ No newline at end of file
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index ecc8c49c4b0..1074af1b901 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -25,6 +25,8 @@
var/list/decals
+ var/movement_cost = 0 // How much the turf slows down movement, if any.
+
/turf/New()
..()
for(var/atom/movable/AM as mob|obj in src)
@@ -38,6 +40,9 @@
else
luminosity = 1
+ if(movement_cost && pathweight == 1) // This updates pathweight automatically.
+ pathweight = movement_cost
+
/turf/Destroy()
turfs -= src
..()
diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm
index f26ba433ffc..9b9638d9086 100644
--- a/code/game/turfs/turf_changing.dm
+++ b/code/game/turfs/turf_changing.dm
@@ -25,6 +25,7 @@
var/old_dynamic_lighting = dynamic_lighting
var/list/old_affecting_lights = affecting_lights
var/old_lighting_overlay = lighting_overlay
+ var/old_weather_overlay = weather_overlay
//world << "Replacing [src.type] with [N]"
@@ -42,6 +43,9 @@
if(old_fire)
fire = old_fire
+ if(old_weather_overlay)
+ W.weather_overlay = old_weather_overlay
+
if (istype(W,/turf/simulated/floor))
W.RemoveLattice()
@@ -55,6 +59,7 @@
S.update_starlight()
W.levelupdate()
+ W.update_icon(1)
. = W
else
@@ -64,6 +69,9 @@
if(old_fire)
old_fire.RemoveFire()
+ if(old_weather_overlay)
+ W.weather_overlay = old_weather_overlay
+
if(tell_universe)
universe.OnTurfChange(W)
@@ -74,6 +82,7 @@
S.update_starlight()
W.levelupdate()
+ W.update_icon(1)
. = W
lighting_overlay = old_lighting_overlay
diff --git a/code/game/turfs/unsimulated/planetary.dm b/code/game/turfs/unsimulated/planetary.dm
index 17cd62ffbbd..ce4ffa44c0f 100644
--- a/code/game/turfs/unsimulated/planetary.dm
+++ b/code/game/turfs/unsimulated/planetary.dm
@@ -1,5 +1,7 @@
// This is a wall you surround the area of your "planet" with, that makes the atmosphere inside stay within bounds, even if canisters
// are opened or other strange things occur.
+var/list/planetary_walls = list()
+
/turf/unsimulated/wall/planetary
name = "railroading"
desc = "Choo choo!"
@@ -17,6 +19,14 @@
phoron = 0
temperature = T20C
+/turf/unsimulated/wall/planetary/New()
+ ..()
+ planetary_walls.Add(src)
+
+/turf/unsimulated/wall/planetary/Destroy()
+ planetary_walls.Remove(src)
+ ..()
+
// Normal station/earth air.
/turf/unsimulated/wall/planetary/normal
oxygen = MOLES_O2STANDARD
@@ -44,4 +54,4 @@
/turf/unsimulated/wall/planetary/desert
oxygen = MOLES_O2STANDARD
nitrogen = MOLES_N2STANDARD
- temperature = 310.92 // About 37.7C / 100F
\ No newline at end of file
+ temperature = 310.92 // About 37.7C / 100F
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 91a504f421c..bf5ee47cba1 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -200,7 +200,9 @@ var/list/admin_verbs_debug = list(
/client/proc/toggle_debug_logs,
/client/proc/admin_ghost, //allows us to ghost/reenter body at will,
/datum/admins/proc/view_runtimes,
- /client/proc/show_gm_status
+ /client/proc/show_gm_status,
+ /datum/admins/proc/change_weather,
+ /datum/admins/proc/change_time
)
var/list/admin_verbs_paranoid_debug = list(
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index fa2c51e7e51..a45b9ec1d6b 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -968,3 +968,46 @@
return
error_cache.showTo(usr)
+
+/datum/admins/proc/change_weather()
+ set category = "Debug"
+ set name = "Change Weather"
+ set desc = "Changes the current weather."
+
+ if(!check_rights(R_DEBUG))
+ return
+
+ var/datum/planet/planet = input(usr, "Which planet do you want to modify the weather on?", "Change Weather") in list(planet_sif)
+ var/datum/weather/new_weather = input(usr, "What weather do you want to change to?", "Change Weather") as null|anything in planet.weather_holder.allowed_weather_types
+ if(new_weather)
+ planet.weather_holder.change_weather(new_weather)
+ var/log = "[key_name(src)] changed [planet.name]'s weather to [new_weather]."
+ message_admins(log)
+ log_admin(log)
+
+/datum/admins/proc/change_time()
+ set category = "Debug"
+ set name = "Change Planet Time"
+ set desc = "Changes the time of a planet."
+
+ if(!check_rights(R_DEBUG))
+ return
+
+ var/datum/planet/planet = input(usr, "Which planet do you want to modify time on?", "Change Time") in list(planet_sif)
+
+ var/datum/time/current_time_datum = planet.current_time
+ var/new_hour = input(usr, "What hour do you want to change to?", "Change Time", text2num(current_time_datum.show_time("hh"))) as null|num
+ if(!isnull(new_hour))
+ var/new_minute = input(usr, "What minute do you want to change to?", "Change Time", text2num(current_time_datum.show_time("mm")) ) as null|num
+ if(!isnull(new_minute))
+ var/type_needed = current_time_datum.type
+ var/datum/time/new_time = new type_needed()
+ new_time = new_time.add_hours(new_hour)
+ new_time = new_time.add_minutes(new_minute)
+ planet.current_time = new_time
+ spawn(1)
+ planet.update_sun()
+
+ var/log = "[key_name(src)] changed [planet.name]'s time to [planet.current_time.show_time("hh:mm")]."
+ message_admins(log)
+ log_admin(log)
\ No newline at end of file
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index 74c00c36d9f..3adb5c6458a 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -146,3 +146,6 @@
new/datum/stack_recipe("white folder", /obj/item/weapon/folder/white), \
new/datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow), \
))
+
+/material/snow/generate_recipes()
+ return // Snowmen and snowballs may come here later.
\ No newline at end of file
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index b6e8170e150..84bd14d4175 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -189,6 +189,12 @@
icon_state = "sheet-card"
default_type = "cardboard"
+/obj/item/stack/material/snow
+ name = "snow"
+ desc = "The temptation to build a snowfort rises."
+ icon_state = "sheet-snow"
+ default_type = "snow"
+
/obj/item/stack/material/leather
name = "leather"
desc = "The by-product of mob grinding."
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
index b6e2a49fe07..fb3af280150 100644
--- a/code/modules/materials/materials.dm
+++ b/code/modules/materials/materials.dm
@@ -628,6 +628,22 @@ var/list/name_to_material
door_icon_base = "wood"
destruction_desc = "crumples"
+/material/snow
+ name = "snow"
+ stack_type = /obj/item/stack/material/snow
+ flags = MATERIAL_BRITTLE
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#FFFFFF"
+ integrity = 1
+ hardness = 1
+ weight = 1
+ stack_origin_tech = list(TECH_MATERIAL = 1)
+ melting_point = T0C+1
+ destruction_desc = "crumples"
+ sheet_singular_name = "pile"
+ sheet_plural_name = "piles"
+
/material/cloth //todo
name = "cloth"
stack_origin_tech = list(TECH_MATERIAL = 2)
diff --git a/code/modules/mob/living/carbon/breathe.dm b/code/modules/mob/living/carbon/breathe.dm
index 6b8a3c43b3c..354a26221c4 100644
--- a/code/modules/mob/living/carbon/breathe.dm
+++ b/code/modules/mob/living/carbon/breathe.dm
@@ -53,7 +53,7 @@
var/datum/gas_mixture/environment
if(loc)
- environment = loc.return_air_for_internal_lifeform()
+ environment = loc.return_air_for_internal_lifeform(src)
if(environment)
breath = environment.remove_volume(volume_needed)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 204730a8e82..29422641df4 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -457,7 +457,7 @@
/mob/living/carbon/proc/should_have_organ(var/organ_check)
return 0
-/mob/living/carbon/proc/can_feel_pain(var/check_organ)
+/mob/living/carbon/can_feel_pain(var/check_organ)
if(isSynthetic())
return 0
return !(species.flags & NO_PAIN)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index 80bfd2259d9..287401ebb40 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -76,12 +76,15 @@
var/obj/item/pulled = pulling
tally += max(pulled.slowdown, 0)
+ var/turf/T = get_turf(src)
+ if(T && T.movement_cost)
+ tally += T.movement_cost
+
if(CE_SPEEDBOOST in chem_effects)
if (tally >= 0) // cut any penalties in half
tally = tally/2
tally -= 1 // give 'em a buff on top.
-
- return (tally+config.human_delay)
+ return (tally+config.human_delay)
/mob/living/carbon/human/Process_Spacemove(var/check_drift = 0)
//Can we act?
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index 6a3b4c7ad1d..ddbef02432a 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -305,3 +305,7 @@
// Called in life() when the mob has no client.
/datum/species/proc/handle_npc(var/mob/living/carbon/human/H)
return
+
+// Called when lying down on a water tile.
+/datum/species/proc/can_breathe_water()
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm
index 28eb05bc253..88c696103d1 100644
--- a/code/modules/mob/living/carbon/human/species/station/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station.dm
@@ -193,6 +193,9 @@
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
)
+/datum/species/skrell/can_breathe_water()
+ return TRUE
+
/datum/species/diona
name = "Diona"
name_plural = "Dionaea"
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 3f4c00f8a57..2629e51f0b7 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -132,8 +132,9 @@ Please contact me on #coderbus IRC. ~Carn x
#define L_HAND_LAYER 24
#define R_HAND_LAYER 25
#define FIRE_LAYER 26 //If you're on fire
-#define TARGETED_LAYER 27 //BS12: Layer for the target overlay from weapon targeting system
-#define TOTAL_LAYERS 27
+#define WATER_LAYER 27 //If you're submerged in water.
+#define TARGETED_LAYER 28 //BS12: Layer for the target overlay from weapon targeting system
+#define TOTAL_LAYERS 29
//////////////////////////////////
/mob/living/carbon/human
@@ -461,6 +462,7 @@ var/global/list/damage_icon_parts = list()
update_inv_legcuffed(0)
update_inv_pockets(0)
update_fire(0)
+ update_water(0)
update_surgery(0)
UpdateDamageIcon()
update_icons()
@@ -1116,6 +1118,17 @@ var/global/list/damage_icon_parts = list()
if(update_icons) update_icons()
+/mob/living/carbon/human/update_water(var/update_icons=1)
+ overlays_standing[WATER_LAYER] = null
+ var/depth = check_submerged()
+ if(depth)
+ if(!lying)
+ overlays_standing[WATER_LAYER] = image("icon" = 'icons/mob/submerged.dmi', "icon_state" = "human_swimming_[depth]")
+ // Lying sideways with the overlay looked strange. Another overlay will be needed in the future.
+
+ if(update_icons)
+ update_icons()
+
/mob/living/carbon/human/proc/update_surgery(var/update_icons=1)
overlays_standing[SURGERY_LEVEL] = null
var/image/total = new
@@ -1151,4 +1164,5 @@ var/global/list/damage_icon_parts = list()
#undef R_HAND_LAYER
#undef TARGETED_LAYER
#undef FIRE_LAYER
+#undef WATER_LAYER
#undef TOTAL_LAYERS
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index d31a8f2b0c4..7680b6e163c 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -774,6 +774,7 @@ default behaviour is:
density = 0
if(l_hand) unEquip(l_hand)
if(r_hand) unEquip(r_hand)
+ update_water() // Submerges the mob.
else
density = initial(density)
@@ -792,3 +793,10 @@ default behaviour is:
update_icons()
return canmove
+/mob/living/proc/update_water() // Involves overlays for humans. Maybe we'll get submerged sprites for borgs in the future?
+ return
+
+/mob/living/proc/can_feel_pain(var/check_organ)
+ if(isSynthetic())
+ return FALSE
+ return TRUE
diff --git a/code/modules/planet/planet.dm b/code/modules/planet/planet.dm
new file mode 100644
index 00000000000..65a2de98456
--- /dev/null
+++ b/code/modules/planet/planet.dm
@@ -0,0 +1,42 @@
+// This holds information about a specific 'planetside' area, such as its time, weather, etc. This will most likely be used to model Sif,
+// but away missions may also have use for this.
+
+/datum/planet
+ var/name = "a rock"
+ var/desc = "Someone neglected to write a nice description for this poor rock."
+
+ var/datum/time/current_time = new() // Holds the current time for sun positioning. Note that we assume day and night is the same length because simplicity.
+ var/sun_process_interval = 1 HOUR
+ var/sun_last_process = null // world.time
+
+ var/datum/weather_holder/weather_holder
+
+ var/sun_position = 0 // 0 means midnight, 1 means noon.
+ var/expected_z_levels = list()
+
+/datum/planet/New()
+ ..()
+ weather_holder = new(src)
+ current_time = current_time.make_random_time()
+ update_sun()
+
+/datum/planet/proc/process(amount)
+ if(current_time)
+ current_time = current_time.add_seconds(amount)
+ update_weather() // We update this first, because some weather types decease the brightness of the sun.
+ if(sun_last_process <= world.time - sun_process_interval)
+ update_sun()
+
+// This changes the position of the sun on the planet.
+/datum/planet/proc/update_sun()
+ sun_last_process = world.time
+
+
+/datum/planet/proc/update_weather()
+ if(weather_holder)
+ weather_holder.process()
+
+// Returns the time datum of Sif.
+/proc/get_sif_time()
+ if(planet_sif)
+ return planet_sif.current_time
\ No newline at end of file
diff --git a/code/modules/planet/sif.dm b/code/modules/planet/sif.dm
new file mode 100644
index 00000000000..edc169d50e8
--- /dev/null
+++ b/code/modules/planet/sif.dm
@@ -0,0 +1,96 @@
+var/datum/planet/sif/planet_sif = null
+
+/datum/planet/sif
+ name = "Sif"
+
+/datum/planet/sif
+ name = "Sif"
+ desc = "Sif is a terrestrial planet in the Vir system. It is somewhat earth-like, in that it has oceans, a \
+ breathable atmosphere, a magnetic field, weather, and similar gravity to Earth. It is currently the capital planet of Vir. \
+ Its center of government is the equatorial city and site of first settlement, New Reykjavik." // Ripped straight from the wiki.
+ current_time = new /datum/time/sif() // 32 hour clocks are nice.
+ expected_z_levels = list(1) // To be changed when real map is finished.
+
+/datum/planet/sif/New()
+ ..()
+ weather_holder = new /datum/weather_holder/sif(src) // Cold weather is also nice.
+
+// This code is horrible.
+/datum/planet/sif/update_sun()
+ ..()
+ var/datum/time/time = current_time
+ var/length_of_day = time.seconds_in_day / 10 / 60 / 60 // 32
+ var/noon = length_of_day / 2
+ var/distance_from_noon = abs(text2num(time.show_time("hh")) - noon)
+ sun_position = distance_from_noon / noon
+ sun_position = abs(sun_position - 1)
+
+ var/low_brightness = null
+ var/high_brightness = null
+
+ var/low_color = null
+ var/high_color = null
+ var/min = 0
+
+ switch(sun_position)
+ if(0 to 0.40) // Night
+ low_brightness = 0.2
+ low_color = "#000066"
+
+ high_brightness = 0.5
+ high_color = "#66004D"
+ min = 0
+
+ if(0.40 to 0.50) // Twilight
+ low_brightness = 0.6
+ low_color = "#66004D"
+
+ high_brightness = 0.8
+ high_color = "#CC3300"
+ min = 0.40
+
+ if(0.50 to 0.70) // Sunrise/set
+ low_brightness = 0.8
+ low_color = "#CC3300"
+
+ high_brightness = 0.9
+ high_color = "#FF9933"
+ min = 0.50
+
+ if(0.70 to 1.00) // Noon
+ low_brightness = 0.9
+ low_color = "#DDDDDD"
+
+ high_brightness = 1.0
+ high_color = "#FFFFFF"
+ min = 0.70
+
+ var/lerp_weight = (abs(min - sun_position)) * 4
+ var/weather_light_modifier = 1
+ if(weather_holder && weather_holder.current_weather)
+ weather_light_modifier = weather_holder.current_weather.light_modifier
+
+ var/new_brightness = (Interpolate(low_brightness, high_brightness, weight = lerp_weight) ) * weather_light_modifier
+
+ var/list/low_color_list = hex2rgb(low_color)
+ var/low_r = low_color_list[1]
+ var/low_g = low_color_list[2]
+ var/low_b = low_color_list[3]
+
+ var/list/high_color_list = hex2rgb(high_color)
+ var/high_r = high_color_list[1]
+ var/high_g = high_color_list[2]
+ var/high_b = high_color_list[3]
+
+ var/new_r = Interpolate(low_r, high_r, weight = lerp_weight)
+ var/new_g = Interpolate(low_g, high_g, weight = lerp_weight)
+ var/new_b = Interpolate(low_b, high_b, weight = lerp_weight)
+
+ var/new_color = rgb(new_r, new_g, new_b)
+
+ var/i = 0
+ for(var/turf/simulated/floor/T in outdoor_turfs)
+ T.set_light(2, new_brightness, new_color)
+ i++
+ if(i % 30 == 0)
+ sleep(1)
diff --git a/code/modules/planet/time.dm b/code/modules/planet/time.dm
new file mode 100644
index 00000000000..936ae0eadda
--- /dev/null
+++ b/code/modules/planet/time.dm
@@ -0,0 +1,76 @@
+// This datum allows one to add and subtract various lengths of time. It really shines when using an alternate time system.
+
+/datum/time
+ // Note that the following is actually measured in 10ths of a second.
+ var/seconds_in_day = 60 * 60 * 24 * 10 // 86,400 seconds
+ var/seconds_in_hour = 60 * 60 * 10 // 3,600 seconds
+ var/seconds_in_minute = 60 * 10
+
+ // This holds the amount of seconds.
+ var/seconds_stored = 0
+
+/datum/time/New(new_time)
+ if(new_time)
+ seconds_stored = new_time
+ ..()
+
+/datum/time/proc/add_seconds(amount)
+ var/answer = seconds_stored + amount * 10
+ if(answer >= seconds_in_day)
+ rollover(answer)
+ return new type(answer)
+
+/datum/time/proc/add_minutes(amount)
+ var/real_amount = amount * seconds_in_minute
+ var/answer = real_amount + seconds_stored
+ if(answer >= seconds_in_day)
+ rollover(answer)
+ return new type(answer)
+
+/datum/time/proc/add_hours(amount)
+ var/real_amount = amount * seconds_in_hour
+ var/answer = real_amount + seconds_stored
+ if(answer >= seconds_in_day)
+ rollover(answer)
+ return new type(answer)
+
+/datum/time/proc/rollover(time)
+ return max(time - seconds_in_day, 0)
+
+/datum/time/proc/make_random_time()
+ return new type(rand(0, seconds_in_day - 1))
+
+// This works almost exactly like time2text.
+// The advantage of this is that it can handle time systems beyond 24h.
+// The downside is a lack of date capability.
+/datum/time/proc/show_time(format)
+ var/time = seconds_stored
+ while(time >= seconds_in_day) // First, get rid of extra days.
+ time = rollover(time)
+
+ var/hours = time / seconds_in_hour
+ var/remaining_hour = time % seconds_in_hour
+ var/minutes = remaining_hour / seconds_in_minute
+ var/seconds = remaining_hour % seconds_in_minute / 10
+
+
+ var/hour_text = num2text(Floor(hours))
+ if(length(hour_text) < 2)
+ hour_text = "0[hour_text]" // Add padding if needed, to look more like time2text().
+
+ var/minute_text = num2text(Floor(minutes))
+ if(length(minute_text) < 2)
+ minute_text = "0[minute_text]"
+
+ var/second_text = num2text(Floor(seconds))
+ if(length(second_text) < 2)
+ second_text = "0[second_text]"
+
+ var/answer = replacetext(format, "hh", hour_text)
+ answer = replacetext(answer, "mm", minute_text)
+ answer = replacetext(answer, "ss", second_text)
+ return answer
+
+// We're gonna pretend there are 32 hours in a Sif day instead of 32.64 for the purposes of not losing sanity. We lose 38m 24s but the alternative is a path to madness.
+/datum/time/sif
+ seconds_in_day = 60 * 60 * 32 * 10 // 115,200 seconds. If we did 32.64 hours/day it would be around 117,504 seconds instead.
\ No newline at end of file
diff --git a/code/modules/planet/weather.dm b/code/modules/planet/weather.dm
new file mode 100644
index 00000000000..d4d13d7a409
--- /dev/null
+++ b/code/modules/planet/weather.dm
@@ -0,0 +1,268 @@
+#define WEATHER_CLEAR "clear"
+#define WEATHER_OVERCAST "overcast"
+#define WEATHER_LIGHT_SNOW "light snow"
+#define WEATHER_SNOW "snow"
+#define WEATHER_BLIZZARD "blizzard"
+#define WEATHER_RAIN "rain"
+#define WEATHER_STORM "storm"
+#define WEATHER_HAIL "hail"
+#define WEATHER_WINDY "windy"
+#define WEATHER_HOT "hot"
+
+/datum/weather_holder
+ var/datum/planet/our_planet = null
+ var/datum/weather/current_weather = null
+ var/temperature = T20C
+ var/wind_dir = 0
+ var/wind_speed = 0
+ var/list/allowed_weather_types = list()
+ var/list/roundstart_weather_chances = list()
+ var/next_weather_shift = null
+ var/planetary_wall_type = null // Which walls to look for when updating temperature.
+
+/datum/weather_holder/New(var/source)
+ ..()
+ our_planet = source
+ for(var/A in allowed_weather_types)
+ var/datum/weather/W = allowed_weather_types[A]
+ if(istype(W))
+ W.holder = src
+
+/datum/weather_holder/proc/change_weather(var/new_weather)
+ var/old_light_modifier = null
+ if(current_weather)
+ old_light_modifier = current_weather.light_modifier // We store the old one, so we can determine if recalculating the sun is needed.
+ current_weather = allowed_weather_types[new_weather]
+ next_weather_shift = world.time + rand(20, 30) MINUTES
+
+ update_icon_effects()
+ update_temperature()
+ if(old_light_modifier && current_weather.light_modifier != old_light_modifier) // Updating the sun should be done sparingly.
+ our_planet.update_sun()
+ message_admins("[our_planet.name]'s weather is now [new_weather], with a temperature of [temperature]°K ([temperature - T0C]°C | [temperature * 1.8 - 459.67]°F).")
+
+/datum/weather_holder/proc/process()
+ if(world.time >= next_weather_shift)
+ var/new_weather
+ if(!current_weather)
+ new_weather = pickweight(roundstart_weather_chances)
+ else
+ new_weather = pickweight(current_weather.transition_chances)
+ change_weather(new_weather)
+ else
+ current_weather.process_effects()
+
+/datum/weather_holder/proc/update_icon_effects()
+ if(current_weather)
+ for(var/turf/simulated/floor/T in outdoor_turfs)
+ if(T.z in our_planet.expected_z_levels)
+ T.overlays -= T.weather_overlay
+ T.weather_overlay = image(icon = current_weather.icon, icon_state = current_weather.icon_state, layer = LIGHTING_LAYER - 1)
+ T.overlays += T.weather_overlay
+
+/datum/weather_holder/proc/update_temperature()
+ temperature = Interpolate(current_weather.temp_low, current_weather.temp_high, weight = our_planet.sun_position)
+
+ for(var/turf/unsimulated/wall/planetary/wall in planetary_walls)
+ if(ispath(wall.type, planetary_wall_type))
+ wall.temperature = temperature
+ for(var/dir in cardinal)
+ var/turf/simulated/T = get_step(wall, dir)
+ if(istype(T))
+ if(T.zone)
+ T.zone.rebuild()
+
+
+/datum/weather_holder/proc/get_weather_datum(desired_type)
+ return allowed_weather_types[desired_type]
+
+/datum/weather_holder/sif
+ temperature = T0C
+ allowed_weather_types = list(
+ WEATHER_CLEAR = new /datum/weather/sif/clear(),
+ WEATHER_OVERCAST = new /datum/weather/sif/overcast(),
+ WEATHER_LIGHT_SNOW = new /datum/weather/sif/light_snow(),
+ WEATHER_SNOW = new /datum/weather/sif/snow(),
+ WEATHER_BLIZZARD = new /datum/weather/sif/blizzard(),
+ WEATHER_RAIN = new /datum/weather/sif/rain(),
+ WEATHER_STORM = new /datum/weather/sif/storm(),
+ WEATHER_HAIL = new /datum/weather/sif/hail()
+ )
+ planetary_wall_type = /turf/unsimulated/wall/planetary/sif
+ roundstart_weather_chances = list(
+ WEATHER_CLEAR = 30,
+ WEATHER_OVERCAST = 30,
+ WEATHER_LIGHT_SNOW = 20,
+ WEATHER_SNOW = 5,
+ WEATHER_BLIZZARD = 5,
+ WEATHER_RAIN = 5,
+ WEATHER_STORM = 2.5,
+ WEATHER_HAIL = 2.5
+ )
+
+/datum/weather
+ var/name = "weather base"
+ var/icon = 'icons/effects/weather.dmi'
+ var/icon_state = null // Icon to apply to turf undergoing weather.
+ var/temp_high = T20C
+ var/temp_low = T0C
+ var/light_modifier = 1.0 // Lower numbers means more darkness.
+ var/transition_chances = list() // Assoc list
+ var/datum/weather_holder/holder = null
+
+/datum/weather/proc/process_effects()
+ return
+
+/datum/weather/sif
+ name = "sif base"
+ temp_high = 243.15 // -20c
+ temp_low = 233.15 // -30c
+
+/datum/weather/sif/clear
+ name = "clear"
+ transition_chances = list(
+ WEATHER_CLEAR = 60,
+ WEATHER_OVERCAST = 40
+ )
+
+/datum/weather/sif/overcast
+ name = "overcast"
+ light_modifier = 0.8
+ transition_chances = list(
+ WEATHER_CLEAR = 25,
+ WEATHER_OVERCAST = 50,
+ WEATHER_LIGHT_SNOW = 10,
+ WEATHER_SNOW = 5,
+ WEATHER_RAIN = 5,
+ WEATHER_HAIL = 5
+ )
+
+/datum/weather/sif/light_snow
+ name = "light snow"
+ icon_state = "snowfall_light"
+ temp_high = 238.15 // -25c
+ temp_low = 228.15 // -35c
+ light_modifier = 0.7
+ transition_chances = list(
+ WEATHER_OVERCAST = 20,
+ WEATHER_LIGHT_SNOW = 50,
+ WEATHER_SNOW = 25,
+ WEATHER_HAIL = 5
+ )
+
+/datum/weather/sif/snow
+ name = "moderate snow"
+ icon_state = "snowfall_med"
+ temp_high = 233.15 // -30c
+ temp_low = 223.15 // -40c
+ light_modifier = 0.5
+ transition_chances = list(
+ WEATHER_LIGHT_SNOW = 20,
+ WEATHER_SNOW = 50,
+ WEATHER_BLIZZARD = 20,
+ WEATHER_HAIL = 5,
+ WEATHER_OVERCAST = 5
+ )
+
+/datum/weather/sif/snow/process_effects()
+ for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
+ for(var/dir_checked in cardinal)
+ var/turf/simulated/floor/T = get_step(S, dir_checked)
+ if(istype(T))
+ if(istype(T, /turf/simulated/floor/outdoors) && prob(33))
+ T.chill()
+
+/datum/weather/sif/blizzard
+ name = "blizzard"
+ icon_state = "snowfall_heavy"
+ temp_high = 223.15 // -40c
+ temp_low = 203.15 // -60c
+ light_modifier = 0.3
+ transition_chances = list(
+ WEATHER_SNOW = 45,
+ WEATHER_BLIZZARD = 40,
+ WEATHER_HAIL = 10,
+ WEATHER_OVERCAST = 5
+ )
+
+/datum/weather/sif/blizzard/process_effects()
+ for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
+ for(var/dir_checked in cardinal)
+ var/turf/simulated/floor/T = get_step(S, dir_checked)
+ if(istype(T))
+ if(istype(T, /turf/simulated/floor/outdoors) && prob(50))
+ T.chill()
+
+/datum/weather/sif/rain
+ name = "rain"
+ icon_state = "rain"
+ light_modifier = 0.5
+ transition_chances = list(
+ WEATHER_OVERCAST = 25,
+ WEATHER_LIGHT_SNOW = 10,
+ WEATHER_RAIN = 50,
+ WEATHER_STORM = 10,
+ WEATHER_HAIL = 5
+ )
+
+/datum/weather/sif/rain/process_effects()
+ for(var/mob/living/L in living_mob_list)
+ if(L.z in holder.our_planet.expected_z_levels)
+ var/turf/T = get_turf(L)
+ if(!T.outdoors)
+ return // They're indoors, so no need to rain on them.
+
+ L.adjust_fire_stacks(-5)
+ to_chat(L, "Rain falls on you.")
+
+/datum/weather/sif/storm
+ name = "storm"
+ icon_state = "storm"
+ temp_high = 233.15 // -30c
+ temp_low = 213.15 // -50c
+ light_modifier = 0.3
+ transition_chances = list(
+ WEATHER_RAIN = 45,
+ WEATHER_STORM = 40,
+ WEATHER_HAIL = 10,
+ WEATHER_OVERCAST = 5
+ )
+
+/datum/weather/sif/rain/process_effects()
+ for(var/mob/living/L in living_mob_list)
+ if(L.z in holder.our_planet.expected_z_levels)
+ var/turf/T = get_turf(L)
+ if(!T.outdoors)
+ return // They're indoors, so no need to rain on them.
+
+ L.adjust_fire_stacks(-10)
+ to_chat(L, "Rain falls on you, drenching you in water.")
+
+/datum/weather/sif/hail
+ name = "hail"
+ icon_state = "hail"
+ temp_high = 233.15 // -30c
+ temp_low = 213.15 // -50c
+ light_modifier = 0.3
+ transition_chances = list(
+ WEATHER_RAIN = 45,
+ WEATHER_STORM = 10,
+ WEATHER_HAIL = 40,
+ WEATHER_OVERCAST = 5
+ )
+
+/datum/weather/sif/hail/process_effects()
+ for(var/mob/living/L in living_mob_list)
+ if(L.z in holder.our_planet.expected_z_levels)
+ var/turf/T = get_turf(L)
+ if(!T.outdoors)
+ return // They're indoors, so no need to pelt them with ice.
+
+ var/target_zone = pick(BP_ALL)
+ var/amount_blocked = L.run_armor_check(target_zone, "melee")
+
+ if(amount_blocked >= 100)
+ return // No need to apply damage.
+
+ L.apply_damage(rand(5, 10), BRUTE, target_zone, amount_blocked, used_weapon = "hail")
+ to_chat(L, "The hail raining down on you [L.can_feel_pain() ? "hurts" : "damages you"]!")
diff --git a/icons/effects/weather.dmi b/icons/effects/weather.dmi
new file mode 100644
index 00000000000..d0df90a44a7
Binary files /dev/null and b/icons/effects/weather.dmi differ
diff --git a/icons/mob/submerged.dmi b/icons/mob/submerged.dmi
new file mode 100644
index 00000000000..0aaa1f3ebb1
Binary files /dev/null and b/icons/mob/submerged.dmi differ
diff --git a/icons/obj/flora/deadtrees.dmi b/icons/obj/flora/deadtrees.dmi
index f76ffd442f9..2ae1a5a6e07 100644
Binary files a/icons/obj/flora/deadtrees.dmi and b/icons/obj/flora/deadtrees.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index 88457f09c2f..c0df5a707f7 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/turf/outdoors.dmi b/icons/turf/outdoors.dmi
new file mode 100644
index 00000000000..c2e42d55df4
Binary files /dev/null and b/icons/turf/outdoors.dmi differ
diff --git a/icons/turf/outdoors_edge.dmi b/icons/turf/outdoors_edge.dmi
new file mode 100644
index 00000000000..02a52195c2b
Binary files /dev/null and b/icons/turf/outdoors_edge.dmi differ
diff --git a/polaris.dme b/polaris.dme
index 46dbd389f4d..1531c150721 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -148,6 +148,7 @@
#include "code\controllers\Processes\mob.dm"
#include "code\controllers\Processes\nanoui.dm"
#include "code\controllers\Processes\obj.dm"
+#include "code\controllers\Processes\planet.dm"
#include "code\controllers\Processes\scheduler.dm"
#include "code\controllers\Processes\Shuttle.dm"
#include "code\controllers\Processes\sun.dm"
@@ -1004,6 +1005,11 @@
#include "code\game\turfs\simulated\wall_icon.dm"
#include "code\game\turfs\simulated\wall_types.dm"
#include "code\game\turfs\simulated\walls.dm"
+#include "code\game\turfs\simulated\water.dm"
+#include "code\game\turfs\simulated\outdoors\dirt.dm"
+#include "code\game\turfs\simulated\outdoors\grass.dm"
+#include "code\game\turfs\simulated\outdoors\outdoors.dm"
+#include "code\game\turfs\simulated\outdoors\snow.dm"
#include "code\game\turfs\snow\snow.dm"
#include "code\game\turfs\space\cracked_asteroid.dm"
#include "code\game\turfs\space\space.dm"
@@ -1788,6 +1794,10 @@
#include "code\modules\paperwork\photography.dm"
#include "code\modules\paperwork\silicon_photography.dm"
#include "code\modules\paperwork\stamps.dm"
+#include "code\modules\planet\planet.dm"
+#include "code\modules\planet\sif.dm"
+#include "code\modules\planet\time.dm"
+#include "code\modules\planet\weather.dm"
#include "code\modules\power\apc.dm"
#include "code\modules\power\batteryrack.dm"
#include "code\modules\power\breaker_box.dm"