diff --git a/code/datums/outfits/jobs/civilian.dm b/code/datums/outfits/jobs/civilian.dm
index ab102d2a8b..afbd7278e0 100644
--- a/code/datums/outfits/jobs/civilian.dm
+++ b/code/datums/outfits/jobs/civilian.dm
@@ -87,3 +87,18 @@
l_hand = /obj/item/weapon/storage/bible
id_type = /obj/item/weapon/card/id/civilian/chaplain
pda_type = /obj/item/device/pda/chaplain
+
+/decl/hierarchy/outfit/job/explorer
+ name = OUTFIT_JOB_NAME("Explorer")
+ shoes = /obj/item/clothing/shoes/boots/winter/explorer
+ uniform = /obj/item/clothing/under/explorer
+ mask = /obj/item/clothing/mask/gas/explorer
+ suit = /obj/item/clothing/suit/storage/hooded/explorer
+ gloves = /obj/item/clothing/gloves/black
+ l_ear = /obj/item/device/radio/headset
+ id_slot = slot_wear_id
+ id_type = /obj/item/weapon/card/id/civilian
+ pda_slot = slot_belt
+ pda_type = /obj/item/device/pda/cargo // Brown looks more rugged
+ r_pocket = /obj/item/device/gps/explorer
+ id_pda_assignment = "Explorer"
diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm
new file mode 100644
index 0000000000..b9c6952bc9
--- /dev/null
+++ b/code/game/objects/items/devices/gps.dm
@@ -0,0 +1,205 @@
+var/list/GPS_list = list()
+
+/obj/item/device/gps
+ name = "global positioning system"
+ desc = "Triangulates the approximate co-ordinates using a nearby satellite network. Alt+click to toggle power."
+ icon = 'icons/obj/gps.dmi'
+ icon_state = "gps-c"
+ w_class = ITEMSIZE_TINY
+ slot_flags = SLOT_BELT
+ origin_tech = list(TECH_MATERIALS = 2, TECH_BLUESPACE = 2, TECH_MAGNETS = 1)
+ matter = list(DEFAULT_WALL_MATERIAL = 500)
+ var/gps_tag = "COM0"
+ var/emped = FALSE
+ var/tracking = FALSE // Will not show other signals or emit its own signal if false.
+ var/long_range = FALSE // If true, can see farther, depending on get_map_levels().
+ var/local_mode = FALSE // If true, only GPS signals of the same Z level are shown.
+ var/hide_signal = FALSE // If true, signal is not visible to other GPS devices.
+ var/can_hide_signal = FALSE // If it can toggle the above var.
+
+/obj/item/device/gps/initialize()
+ GPS_list += src
+ name = "global positioning system ([gps_tag])"
+ update_icon()
+
+/obj/item/device/gps/Destroy()
+ GPS_list -= src
+ return ..()
+
+/obj/item/device/gps/AltClick(mob/user)
+ toggletracking(user)
+
+/obj/item/device/gps/proc/toggletracking(mob/living/user)
+ if(!istype(user))
+ return
+ if(emped)
+ to_chat(user, "It's busted!")
+ return
+ if(tracking)
+ to_chat(user, "[src] is no longer tracking, or visible to other GPS devices.")
+ tracking = FALSE
+ update_icon()
+ else
+ to_chat(user, "[src] is now tracking, and visible to other GPS devices.")
+ tracking = TRUE
+ update_icon()
+
+/obj/item/device/gps/emp_act(severity)
+ if(emped) // Without a fancy callback system, this will have to do.
+ return
+ var/severity_modifier = severity ? severity : 4 // In case emp_act gets called without any arguments.
+ var/duration = 5 MINUTES / severity_modifier
+ emped = TRUE
+ update_icon()
+
+ spawn(duration)
+ emped = FALSE
+ update_icon()
+ visible_message("\The [src] appears to be functional again.")
+
+/obj/item/device/gps/update_icon()
+ overlays.Cut()
+ if(emped)
+ overlays += image(icon, src, "emp")
+ else if(tracking)
+ overlays += image(icon, src, "working")
+
+/obj/item/device/gps/attack_self(mob/user)
+ display(user)
+
+/obj/item/device/gps/proc/display(mob/user)
+ if(!tracking)
+ to_chat(user, "The device is off. Alt-click it to turn it on.")
+ return
+ if(emped)
+ to_chat(user, "It's busted!")
+ return
+
+ var/list/dat = list()
+
+ var/turf/curr = get_turf(src)
+ var/area/my_area = get_area(src)
+ dat += "Current location: [my_area.name] ([curr.x], [curr.y], [curr.z])"
+ dat += "[hide_signal ? "Tagged" : "Broadcasting"] as '[gps_tag]'. \[Change Tag\] \
+ \[Toggle Scan Range\] \
+ [can_hide_signal ? "\[Toggle Signal Visibility\]":""]"
+
+ var/list/signals = list()
+
+ for(var/gps in GPS_list)
+ var/obj/item/device/gps/G = gps
+ if(G.emped || !G.tracking || G.hide_signal || G == src) // Their GPS isn't on or functional.
+ continue
+ var/turf/T = get_turf(G)
+ var/z_level_detection = using_map.get_map_levels(curr.z, long_range)
+
+ if(local_mode && T.z != curr.z) // Only care about the current z-level.
+ continue
+ else if(!(T.z in z_level_detection)) // Too far away.
+ continue
+
+ var/area/their_area = get_area(G)
+ var/area_name = their_area.name
+ var/coord = "[T.x], [T.y], [T.z]"
+ var/degrees = round(Get_Angle(curr, T))
+ var/direction = uppertext(dir2text(get_dir(curr, T)))
+ var/distance = get_dist(curr, T)
+ var/local = curr.z == T.z ? TRUE : FALSE
+ if(!direction)
+ direction = "CENTER"
+ degrees = "N/A"
+
+ signals += " [G.gps_tag]: [area_name] ([coord]) [local ? "Dist: [distance]m Dir: [degrees]° ([direction])":""]"
+
+ if(signals.len)
+ dat += "Detected signals;"
+ for(var/line in signals)
+ dat += line
+ else
+ dat += "No other signals detected."
+
+ var/result = dat.Join("
")
+ to_chat(user, result)
+
+/obj/item/device/gps/Topic(var/href, var/list/href_list)
+ if(..())
+ return 1
+
+ if(href_list["tag"])
+ var/a = input("Please enter desired tag.", name, gps_tag) as text
+ a = uppertext(copytext(sanitize(a), 1, 11))
+ if(in_range(src, usr))
+ gps_tag = a
+ name = "global positioning system ([gps_tag])"
+ to_chat(usr, "You set your GPS's tag to '[gps_tag]'.")
+
+ if(href_list["range"])
+ local_mode = !local_mode
+ to_chat(usr, "You set the signal receiver to [local_mode ? "'NARROW'" : "'BROAD'"].")
+
+ if(href_list["hide"])
+ if(!can_hide_signal)
+ return
+ hide_signal = !hide_signal
+ to_chat(usr, "You set the device to [hide_signal ? "not " : ""]broadcast a signal while scanning for other signals.")
+
+/obj/item/device/gps/on // Defaults to off to avoid polluting the signal list with a bunch of GPSes without owners. If you need to spawn active ones, use these.
+ tracking = TRUE
+
+/obj/item/device/gps/science
+ icon_state = "gps-s"
+ gps_tag = "SCI0"
+
+/obj/item/device/gps/science/on
+ tracking = TRUE
+
+/obj/item/device/gps/engineering
+ icon_state = "gps-e"
+ gps_tag = "ENG0"
+
+/obj/item/device/gps/engineering/on
+ tracking = TRUE
+
+/obj/item/device/gps/mining
+ icon_state = "gps-m"
+ gps_tag = "MINE0"
+ desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life. Alt+click to toggle power."
+
+/obj/item/device/gps/mining/on
+ tracking = TRUE
+
+/obj/item/device/gps/explorer
+ icon_state = "gps-ex"
+ gps_tag = "EX0"
+ desc = "A positioning system helpful for rescuing trapped or injured explorers, keeping one on you at all times while exploring might just save your life. Alt+click to toggle power."
+
+/obj/item/device/gps/explorer/on
+ tracking = TRUE
+
+/obj/item/device/gps/syndie
+ icon_state = "gps-syndie"
+ gps_tag = "NULL"
+ desc = "A positioning system that has extended range and can detect other GPS device signals without revealing its own. How that works is best left a mystery. Alt+click to toggle power."
+ origin_tech = list(TECH_MATERIALS = 2, TECH_BLUESPACE = 3, TECH_MAGNETS = 2, TECH_ILLEGAL = 2)
+ long_range = TRUE
+ hide_signal = TRUE
+ can_hide_signal = TRUE
+
+/obj/item/device/gps/robot
+ icon_state = "gps-b"
+ gps_tag = "SYNTH0"
+ desc = "A synthetic internal positioning system. Used as a recovery beacon for damaged synthetic assets, or a collaboration tool for mining or exploration teams. \
+ Alt+click to toggle power."
+ tracking = TRUE // On by default.
+
+/obj/item/device/gps/internal // Base type for immobile/internal GPS units.
+ icon_state = null
+ gps_tag = "Eerie Signal"
+ desc = "Report to a coder immediately."
+ invisibility = INVISIBILITY_MAXIMUM
+ tracking = TRUE // Meant to point to a location, so it needs to be on.
+ anchored = TRUE
+
+/obj/item/device/gps/internal/base
+ gps_tag = "NT_BASE"
+ desc = "A homing signal from NanoTrasen's outpost."
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/material/knives.dm b/code/game/objects/items/weapons/material/knives.dm
index 9545504f84..7b6e6184f1 100644
--- a/code/game/objects/items/weapons/material/knives.dm
+++ b/code/game/objects/items/weapons/material/knives.dm
@@ -92,3 +92,11 @@
desc = "A huge thing used for chopping and chopping up meat. This includes clowns and clown-by-products."
force_divisor = 0.25 // 15 when wielded with hardness 60 (steel)
attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+
+/obj/item/weapon/material/hatchet/tacknife/survival
+ name = "survival knife"
+ desc = "A hunting grade survival knife."
+ icon = 'icons/obj/kitchen.dmi'
+ icon_state = "survivalknife"
+ item_state = "knife"
+ applies_material_colour = FALSE
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index 4facc9fef7..299680b864 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -67,6 +67,15 @@
icon_state = "swat"
siemens_coefficient = 0.7
+/obj/item/clothing/mask/gas/explorer
+ name = "explorer gas mask"
+ desc = "A military-grade gas mask that can be connected to an air supply."
+ icon_state = "explorer"
+ item_state_slots = list(slot_r_hand_str = "gas", slot_l_hand_str = "gas")
+ armor = list(melee = 10, bullet = 5, laser = 5,energy = 5, bomb = 0, bio = 50, rad = 0)
+ body_parts_covered = HEAD|FACE|EYES
+ siemens_coefficient = 0.9
+
/obj/item/clothing/mask/gas/clown_hat
name = "clown wig and mask"
desc = "A true prankster's facial attire. A clown is incomplete without their wig and mask."
diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm
index 88206f4132..40dd1c7242 100644
--- a/code/modules/clothing/shoes/boots.dm
+++ b/code/modules/clothing/shoes/boots.dm
@@ -96,6 +96,12 @@
desc = "A pair of winter boots. These ones are lined with brown fur, and their trim is ambrosia green"
icon_state = "winterboots_hydro"
+/obj/item/clothing/shoes/boots/winter/explorer
+ name = "explorer winter boots"
+ desc = "Steel-toed winter boots for mining or exploration in hazardous environments. Very good at keeping toes warm and uncrushed."
+ icon_state = "explorer"
+ armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 0, rad = 0)
+
/obj/item/clothing/shoes/boots/tactical
name = "tactical boots"
desc = "Tan boots with extra padding and armor."
diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm
index 006de8e99c..5819a5e065 100644
--- a/code/modules/clothing/suits/miscellaneous.dm
+++ b/code/modules/clothing/suits/miscellaneous.dm
@@ -770,6 +770,42 @@ obj/item/clothing/suit/storage/toggle/peacoat
name = "mining winter hood"
armor = list(melee = 10, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
+/obj/item/clothing/suit/storage/hooded/explorer
+ name = "explorer suit"
+ desc = "An armoured suit for exploring harsh environments."
+ icon_state = "explorer"
+ item_state = "explorer"
+ flags = THICKMATERIAL
+ body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
+ min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
+ cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
+ hooded = TRUE
+ hoodtype = /obj/item/clothing/head/explorer
+ siemens_coefficient = 0.9
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 20, bomb = 50, bio = 100, rad = 50) // Inferior to sec vests in bullet/laser but better for environmental protection.
+ allowed = list(
+ /obj/item/device/flashlight,
+ /obj/item/weapon/gun,
+ /obj/item/ammo_magazine,
+ /obj/item/weapon/melee,
+ /obj/item/weapon/material/knife,
+ /obj/item/weapon/tank,
+ /obj/item/device/radio,
+ /obj/item/weapon/pickaxe
+ )
+
+/obj/item/clothing/head/explorer
+ name = "explorer hood"
+ desc = "An armoured hood for exploring harsh environments."
+ icon_state = "explorer"
+ body_parts_covered = HEAD
+ cold_protection = HEAD
+ flags = THICKMATERIAL
+ flags_inv = HIDEEARS | BLOCKHAIR
+ min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
+ siemens_coefficient = 0.9
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 20, bomb = 50, bio = 100, rad = 50)
+
/obj/item/clothing/suit/varsity
name = "black varsity jacket"
desc = "A favorite of jocks everywhere from Sol to Nyx."
diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm
index 1176b91089..b7b3b2b0b3 100644
--- a/code/modules/clothing/suits/toggles.dm
+++ b/code/modules/clothing/suits/toggles.dm
@@ -31,6 +31,7 @@
/obj/item/clothing/suit/storage/hooded/proc/RemoveHood()
icon_state = "[initial(icon_state)]"
suittoggled = 0
+ hood.canremove = TRUE // This shouldn't matter anyways but just incase.
if(ishuman(hood.loc))
var/mob/living/carbon/H = hood.loc
H.unEquip(hood, 1)
@@ -53,6 +54,7 @@
else
H.equip_to_slot_if_possible(hood,slot_head,0,0,1)
suittoggled = 1
+ hood.canremove = FALSE
icon_state = "[initial(icon_state)]_t"
H.update_inv_wear_suit()
else
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 77046dd89e..ddfb109ef6 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -812,3 +812,8 @@
desc = "A fluffy robe to keep you from showing off to the world."
icon_state = "bathrobe"
worn_state = "bathrobe"
+
+/obj/item/clothing/under/explorer
+ desc = "A green uniform for operating in hazardous environments."
+ name = "explorer's jumpsuit"
+ icon_state = "explorer"
\ No newline at end of file
diff --git a/code/modules/xenoarcheaology/tools/tools.dm b/code/modules/xenoarcheaology/tools/tools.dm
index d3ab8d07d6..1d79a89449 100644
--- a/code/modules/xenoarcheaology/tools/tools.dm
+++ b/code/modules/xenoarcheaology/tools/tools.dm
@@ -1,17 +1,3 @@
-/obj/item/device/gps
- name = "relay positioning device"
- desc = "Triangulates the approximate co-ordinates using a nearby satellite network."
- icon = 'icons/obj/device.dmi'
- icon_state = "locator"
- item_state = "locator"
- origin_tech = list(TECH_MATERIAL = 2, TECH_DATA = 2, TECH_BLUESPACE = 2)
- matter = list(DEFAULT_WALL_MATERIAL = 500)
- w_class = ITEMSIZE_SMALL
-
-/obj/item/device/gps/attack_self(var/mob/user as mob)
- var/turf/T = get_turf(src)
- user << "\icon[src] \The [src] flashes [T.x]:[T.y]:[T.z]."
-
/obj/item/device/measuring_tape
name = "measuring tape"
desc = "A coiled metallic tape used to check dimensions and lengths."
diff --git a/icons/mob/feet.dmi b/icons/mob/feet.dmi
index 79b56e487c..e61f2d55ac 100644
Binary files a/icons/mob/feet.dmi and b/icons/mob/feet.dmi differ
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 9947dec006..984f68f176 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/mask.dmi b/icons/mob/mask.dmi
index 02ffbf4e65..2d855bb804 100644
Binary files a/icons/mob/mask.dmi and b/icons/mob/mask.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index 0f88d8fd04..3029d8f3d6 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/mob/uniform.dmi b/icons/mob/uniform.dmi
index 4dd885d30b..5261e549f8 100644
Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index 9cc38c1037..8abb265fde 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi
index fd3ff5ceca..090ba33aee 100644
Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ
diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi
index 557ed651ff..a87dcc3a81 100644
Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index 424bc8894c..fa6ecad57a 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi
index 14feefefe6..eeb8183879 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/icons/obj/gps.dmi b/icons/obj/gps.dmi
new file mode 100644
index 0000000000..b51087e9c7
Binary files /dev/null and b/icons/obj/gps.dmi differ
diff --git a/icons/obj/kitchen.dmi b/icons/obj/kitchen.dmi
index 4a269c4284..021d31d6e9 100644
Binary files a/icons/obj/kitchen.dmi and b/icons/obj/kitchen.dmi differ
diff --git a/maps/southern_cross/southern_cross_defines.dm b/maps/southern_cross/southern_cross_defines.dm
index fb70f74cbf..36063692e7 100644
--- a/maps/southern_cross/southern_cross_defines.dm
+++ b/maps/southern_cross/southern_cross_defines.dm
@@ -57,11 +57,16 @@
return map_levels
else if (srcz == Z_LEVEL_TRANSIT)
return list() // Nothing on transit!
- else if (srcz >= Z_LEVEL_STATION_ONE && srcz <= Z_LEVEL_STATION_THREE)
+ else if (srcz >= Z_LEVEL_STATION_ONE && srcz <= Z_LEVEL_STATION_THREE) // Station can see other decks.
return list(
Z_LEVEL_STATION_ONE,
Z_LEVEL_STATION_TWO,
Z_LEVEL_STATION_THREE)
+ else if(srcz in list(Z_LEVEL_SURFACE, Z_LEVEL_SURFACE_MINE, Z_LEVEL_SURFACE_WILD)) // Being on the surface lets you see other surface Zs.
+ return list(
+ Z_LEVEL_SURFACE,
+ Z_LEVEL_SURFACE_MINE,
+ Z_LEVEL_SURFACE_WILD)
else
return ..()
diff --git a/polaris.dme b/polaris.dme
index f193f1328c..f8c678732d 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -824,6 +824,7 @@
#include "code\game\objects\items\devices\flashlight.dm"
#include "code\game\objects\items\devices\floor_painter.dm"
#include "code\game\objects\items\devices\geiger.dm"
+#include "code\game\objects\items\devices\gps.dm"
#include "code\game\objects\items\devices\hacktool.dm"
#include "code\game\objects\items\devices\lightreplacer.dm"
#include "code\game\objects\items\devices\locker_painter.dm"