diff --git a/_maps/map_files/shuttles/emergency_dept.dmm b/_maps/map_files/shuttles/emergency_dept.dmm
new file mode 100644
index 00000000000..64b903a78f5
--- /dev/null
+++ b/_maps/map_files/shuttles/emergency_dept.dmm
@@ -0,0 +1,127 @@
+"aa" = (/turf/space,/area/space)
+"ab" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f6"; dir = 2},/area/shuttle/escape)
+"ac" = (/obj/structure/grille,/obj/structure/window/full/shuttle,/turf/simulated/floor/plating,/area/shuttle/escape)
+"ad" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_f10"; icon_state = "swall_f10"; dir = 2},/area/shuttle/escape)
+"ae" = (/turf/simulated/shuttle/wall{icon_state = "swall12"; dir = 2},/area/shuttle/escape)
+"af" = (/turf/simulated/shuttle/wall{icon_state = "swallc4"},/area/shuttle/escape)
+"ag" = (/obj/machinery/computer/emergency_shuttle,/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"ah" = (/turf/simulated/shuttle/wall{icon_state = "swallc3"},/area/shuttle/escape)
+"ai" = (/obj/machinery/computer/station_alert,/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"aj" = (/obj/machinery/computer/communications,/obj/machinery/light/spot{tag = "icon-tube1 (NORTH)"; icon_state = "tube1"; dir = 1},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"ak" = (/obj/machinery/computer/security{network = list("SS13","Telecomms","Research Outpost","Mining Outpost")},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"al" = (/obj/structure/stool/bed/chair/comfy/blue{dir = 1},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"am" = (/obj/structure/table,/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"an" = (/obj/machinery/computer/crew,/obj/machinery/light/spot{tag = "icon-tube1 (NORTH)"; icon_state = "tube1"; dir = 1},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"ao" = (/obj/machinery/computer/robotics,/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"ap" = (/turf/simulated/shuttle/wall{icon_state = "swall3"; dir = 2},/area/shuttle/escape)
+"aq" = (/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"ar" = (/obj/structure/stool/bed/chair/comfy/beige{dir = 1},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"as" = (/obj/structure/stool/bed/chair/comfy/brown{dir = 1},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"at" = (/obj/structure/stool/bed/chair/comfy/red{dir = 1},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"au" = (/obj/structure/stool/bed/chair/comfy/teal{dir = 1},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"av" = (/obj/structure/stool/bed/chair/comfy/purp{dir = 1},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"aw" = (/turf/simulated/shuttle/wall{icon_state = "swall13"; dir = 2},/area/shuttle/escape)
+"ax" = (/turf/simulated/shuttle/wall{icon_state = "swall14"; dir = 2},/area/shuttle/escape)
+"ay" = (/obj/machinery/door/airlock/glass_command{name = "Escape Shuttle Cockpit"; req_access_txt = "19"},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"az" = (/obj/structure/stool/bed/chair,/turf/simulated/shuttle/floor4,/area/shuttle/escape)
+"aA" = (/obj/machinery/status_display{pixel_y = 30},/obj/machinery/light/spot{tag = "icon-tube1 (NORTH)"; icon_state = "tube1"; dir = 1},/obj/structure/stool/bed/chair,/turf/simulated/shuttle/floor4,/area/shuttle/escape)
+"aB" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "16"},/turf/simulated/floor/plating,/area/shuttle/escape)
+"aC" = (/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape)
+"aD" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape)
+"aE" = (/obj/structure/table/woodentable,/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape)
+"aF" = (/obj/machinery/status_display{pixel_y = 30},/obj/machinery/light/spot{tag = "icon-tube1 (NORTH)"; icon_state = "tube1"; dir = 1},/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape)
+"aG" = (/obj/item/weapon/storage/box/drinkingglasses,/obj/item/weapon/reagent_containers/food/drinks/shaker,/obj/structure/table/woodentable,/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape)
+"aH" = (/obj/structure/closet/walllocker/emerglocker{pixel_x = -28},/turf/simulated/shuttle/floor4,/area/shuttle/escape)
+"aI" = (/turf/simulated/shuttle/floor4,/area/shuttle/escape)
+"aJ" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "15"},/turf/simulated/floor/plating,/area/shuttle/escape)
+"aK" = (/obj/structure/stool/bed/chair,/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape)
+"aL" = (/obj/machinery/chem_dispenser/beer,/obj/structure/table/woodentable,/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape)
+"aM" = (/obj/machinery/door/airlock/glass_security{name = "Escape Shuttle Cell"; req_access_txt = "2"},/turf/simulated/floor/plating,/area/shuttle/escape)
+"aN" = (/obj/item/weapon/storage/box/drinkingglasses,/obj/item/weapon/reagent_containers/food/drinks/shaker,/obj/item/clothing/mask/cigarette/cigar,/obj/structure/table/woodentable,/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape)
+"aO" = (/obj/machinery/chem_dispenser/soda,/obj/structure/table/woodentable,/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape)
+"aP" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/floor/plating,/area/shuttle/escape)
+"aQ" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/shuttle/floor4,/area/shuttle/escape)
+"aR" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape)
+"aS" = (/turf/simulated/shuttle/wall{tag = "icon-swall7"; icon_state = "swall7"; dir = 2},/area/shuttle/escape)
+"aT" = (/obj/docking_port/mobile/emergency{dir = 4; dwidth = 11; height = 13; timid = 1; width = 24},/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"aU" = (/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"aV" = (/obj/structure/stool/bed/chair{dir = 4},/obj/item/device/radio/intercom{dir = 8; name = "station intercom (General)"; pixel_x = -28},/obj/machinery/light/spot{tag = "icon-tube1 (WEST)"; icon_state = "tube1"; dir = 8},/obj/structure/window/reinforced{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape)
+"aW" = (/obj/machinery/door/window/northleft{req_access_txt = "32"},/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape)
+"aX" = (/obj/structure/stool/bed/chair{dir = 8},/obj/structure/window/reinforced{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape)
+"aY" = (/obj/structure/stool/bed/chair{dir = 4},/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"aZ" = (/obj/structure/stool/bed/chair{dir = 8},/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"ba" = (/obj/structure/stool/bed/chair{dir = 4},/obj/structure/window/reinforced{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor5"},/area/shuttle/escape)
+"bb" = (/obj/machinery/door/window/northleft{req_access_txt = "47"},/turf/simulated/shuttle/floor{icon_state = "floor5"},/area/shuttle/escape)
+"bc" = (/obj/structure/stool/bed/chair{dir = 8},/obj/structure/closet/walllocker/emerglocker{pixel_x = 28},/obj/machinery/light/spot{tag = "icon-tube1 (EAST)"; icon_state = "tube1"; dir = 4},/obj/structure/window/reinforced{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor5"},/area/shuttle/escape)
+"bd" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape)
+"be" = (/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape)
+"bf" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape)
+"bg" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "8"},/turf/simulated/floor/plating,/area/shuttle/escape)
+"bh" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bi" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bj" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor{icon_state = "floor5"},/area/shuttle/escape)
+"bk" = (/turf/simulated/shuttle/floor{icon_state = "floor5"},/area/shuttle/escape)
+"bl" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/shuttle/floor{icon_state = "floor5"},/area/shuttle/escape)
+"bm" = (/obj/structure/stool/bed/chair{dir = 4},/obj/structure/window/reinforced,/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape)
+"bn" = (/obj/machinery/door/window/southright{req_access_txt = "32"},/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape)
+"bo" = (/obj/structure/stool/bed/chair{dir = 8},/obj/structure/window/reinforced,/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape)
+"bp" = (/obj/structure/window/reinforced,/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bq" = (/obj/structure/window/reinforced,/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"br" = (/obj/structure/stool/bed/chair{dir = 4},/obj/structure/window/reinforced,/turf/simulated/shuttle/floor{icon_state = "floor5"},/area/shuttle/escape)
+"bs" = (/obj/machinery/door/window/southright{req_access_txt = "47"},/turf/simulated/shuttle/floor{icon_state = "floor5"},/area/shuttle/escape)
+"bt" = (/obj/structure/stool/bed/chair{dir = 8},/obj/structure/window/reinforced,/turf/simulated/shuttle/floor{icon_state = "floor5"},/area/shuttle/escape)
+"bu" = (/obj/machinery/light/spot{tag = "icon-tube1 (WEST)"; icon_state = "tube1"; dir = 8},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bv" = (/obj/machinery/light/spot{tag = "icon-tube1 (EAST)"; icon_state = "tube1"; dir = 4},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bw" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/shuttle/floor,/area/shuttle/escape)
+"bx" = (/obj/structure/noticeboard,/turf/simulated/shuttle/wall{icon_state = "swall12"; dir = 2},/area/shuttle/escape)
+"by" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = null; name = "Shuttle Cargo Hatch"},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape)
+"bz" = (/obj/structure/stool/bed/chair{dir = 4},/obj/structure/window/reinforced{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape)
+"bA" = (/obj/machinery/door/window/northleft{req_access_txt = "5"},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape)
+"bB" = (/obj/structure/stool/bed/chair{dir = 8},/obj/structure/window/reinforced{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape)
+"bC" = (/obj/machinery/door/airlock/glass_medical{id_tag = null; name = "Escape Shuttle Infirmary"; req_access_txt = "0"},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bD" = (/turf/simulated/shuttle/wall{icon_state = "swall11"; dir = 2},/area/shuttle/escape)
+"bE" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape)
+"bF" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape)
+"bG" = (/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape)
+"bH" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape)
+"bI" = (/obj/machinery/vending/wallmed1{layer = 3.3; name = "Emergency NanoMed"; pixel_x = 28; pixel_y = 0; req_access_txt = "0"},/obj/machinery/sleeper,/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bJ" = (/obj/item/device/radio/intercom{dir = 4; name = "station intercom (General)"; pixel_x = 28},/obj/item/weapon/extinguisher,/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bK" = (/obj/structure/closet/cardboard,/obj/machinery/light/spot{tag = "icon-tube1 (WEST)"; icon_state = "tube1"; dir = 8},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bL" = (/obj/machinery/recharge_station,/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bM" = (/obj/structure/table,/obj/item/weapon/storage/firstaid/o2{layer = 2.8; pixel_x = 4; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = 2; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = -2; pixel_y = 4},/obj/item/bodybag/cryobag{pixel_x = 5},/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/storage/firstaid/regular{pixel_x = 2; pixel_y = 3},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bN" = (/obj/structure/stool/bed/roller,/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bO" = (/obj/machinery/sleeper,/obj/machinery/light/spot{tag = "icon-tube1 (EAST)"; icon_state = "tube1"; dir = 4},/turf/simulated/floor/plasteel,/area/shuttle/escape)
+"bP" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f5"; dir = 2},/area/shuttle/escape)
+"bQ" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/shuttle/engine/heater,/turf/simulated/floor/plating/airless,/area/shuttle/escape)
+"bR" = (/obj/structure/shuttle/engine/heater,/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/plating/airless,/area/shuttle/escape)
+"bS" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f9"; dir = 2},/area/shuttle/escape)
+"bT" = (/obj/structure/shuttle/engine/propulsion,/turf/space,/area/shuttle/escape)
+"bU" = (/turf/space,/area/shuttle/escape)
+
+(1,1,1) = {"
+aaaaaaaaaaabacadaaaaaaaaaa
+aaaaabaeaeafagahaeaeadaaaa
+aaabafaiajakalamanaoahadaa
+aaapaqarasataqaqauavaqapaa
+aaapaqaqaqaqaqaqaqaqaqapaa
+abawaeaeaeaxayaeaeaeaeawad
+apazaAazazaBaCaDaEaCaFaGap
+apaHaIaIaIaJaCaDaEaCaKaLap
+apaIaIaIaIaMaCaDaEaCaNaOap
+aPaIaIaQaQaBaCaDaEaCaRaRac
+aSaeaeaeaeaJaCaDaEaCaCaCap
+aTaUaUaUaUaUaUaUaUaUaUaUap
+apaVaWaXaBaYaUaZaBbabbbcap
+aBbdbebfbgbhaUbibgbjbkblaB
+bgbdbebfbgbhaUbibgbjbkblbg
+aJbmbnboaJbpaUbqaJbrbsbtaJ
+apbuaUaUaUaUaUaUaUaUaUbvap
+bwaUaUaUaUaUaUaUaUaUaUaUac
+aSaebxbyaBbzbAbBaBbCacaebD
+bEaUaUaUbgbFbGbHbgaUaUbIap
+acaUaUaUbgbFbGbHbgaUaUbJap
+apbKbLbLaJbFbGbHaJbNbMbOap
+bPaxbQbQawaeaeaeawbRbRaxbS
+aabPbTbTbSbUbUbUbPbTbTbSaa
+"}
+
diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm
index 8e7be007d12..4f07d54ee01 100644
--- a/code/__DEFINES/genetics.dm
+++ b/code/__DEFINES/genetics.dm
@@ -96,6 +96,7 @@
#define NUTRITION_LEVEL_FED 350
#define NUTRITION_LEVEL_HUNGRY 250
#define NUTRITION_LEVEL_STARVING 150
+#define NUTRITION_LEVEL_CURSED 0
//Blood levels
#define BLOOD_VOLUME_NORMAL 560
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 99079fd81bb..a2f487086ae 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -332,4 +332,6 @@
#define STATION_GOAL_BUDGET 1
#define FIRST_DIAG_STEP 1
-#define SECOND_DIAG_STEP 2
\ No newline at end of file
+#define SECOND_DIAG_STEP 2
+
+#define ARBITRARY_VIEWRANGE_NOHUD 2
\ No newline at end of file
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 2e1d87f605e..f4b43516cd0 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -100,6 +100,15 @@
if(display_hud_version > HUD_VERSIONS) //If the requested version number is greater than the available versions, reset back to the first version
display_hud_version = 1
+ if(mymob.client.view < world.view)
+ if(mymob.client.view < ARBITRARY_VIEWRANGE_NOHUD)
+ to_chat(mymob, "HUD is unavailable with this view range.")
+ display_hud_version = HUD_STYLE_NOHUD
+ else
+ if(display_hud_version == HUD_STYLE_STANDARD)
+ to_chat(mymob, "Standard HUD mode is unavailable with a smaller-than-normal view range.")
+ display_hud_version = HUD_STYLE_REDUCED
+
switch(display_hud_version)
if(HUD_STYLE_STANDARD) //Default HUD
hud_shown = 1 //Governs behavior of other procs
diff --git a/code/datums/outfits/outfit_admin.dm b/code/datums/outfits/outfit_admin.dm
index 5c11c42930a..40c38ac0627 100644
--- a/code/datums/outfits/outfit_admin.dm
+++ b/code/datums/outfits/outfit_admin.dm
@@ -1173,3 +1173,39 @@
suit = /obj/item/clothing/suit/wizrobe/marisa
shoes = /obj/item/clothing/shoes/sandal/marisa
head = /obj/item/clothing/head/wizard/marisa
+
+
+/datum/outfit/admin/dark_priest
+ name = "Dark Priest"
+
+ uniform = /obj/item/clothing/under/color/black
+ suit = /obj/item/clothing/suit/hooded/chaplain_hoodie
+ back = /obj/item/weapon/storage/backpack
+ head = /obj/item/clothing/head/chaplain_hood
+ gloves = /obj/item/clothing/gloves/color/black
+ shoes = /obj/item/clothing/shoes/black
+ l_ear = /obj/item/device/radio/headset/syndicate
+ id = /obj/item/weapon/card/id/syndicate
+ r_hand = /obj/item/weapon/nullrod/armblade
+ backpack_contents = list(
+ /obj/item/weapon/storage/box/survival = 1,
+ /obj/item/device/flashlight = 1,
+ )
+
+/datum/outfit/admin/dark_priest/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+ if(visualsOnly)
+ return
+ var/obj/item/weapon/card/id/I = H.wear_id
+ if(istype(I))
+ apply_to_card(I, H, get_all_accesses(), "Dark Priest", "syndie")
+ var/obj/item/weapon/nullrod/armblade/B = H.r_hand
+ if(istype(B))
+ B.force = 20
+ B.name = "blessing of the reaper"
+ B.desc = "Sometimes, someone's just gotta die."
+ var/obj/item/device/radio/headset/R = H.l_ear
+ if(istype(R))
+ R.flags |= NODROP
+ var/obj/item/weapon/implant/dust/D = new /obj/item/weapon/implant/dust(H)
+ D.implant(H)
\ No newline at end of file
diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm
index 24007dbafee..3d0f877a3aa 100644
--- a/code/datums/shuttles.dm
+++ b/code/datums/shuttles.dm
@@ -39,6 +39,12 @@
suffix = "cyb"
name = "emergency shuttle (Cyberiad)"
+/datum/map_template/shuttle/emergency/dept
+ suffix = "dept"
+ name = "emergency shuttle (department)"
+ description = "Features include: areas for each department, and a small bar."
+ admin_notes = "Designed to reduce chaos. Each dept requires dept access."
+
/datum/map_template/shuttle/emergency/clown
suffix = "clown"
name = "Snappop(tm)!"
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 5d1dd5c74fb..292ad651235 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -34,6 +34,9 @@
//Detective Work, used for the duplicate data points kept in the scanners
var/list/original_atom
+ //Detective Work, used for allowing a given atom to leave its fibers on stuff. Allowed by default
+ var/can_leave_fibers = TRUE
+
var/allow_spin = 1 //Set this to 1 for a _target_ that is being thrown at; if an atom has this set to 1 then atoms thrown AT it will not spin; currently used for the singularity. -Fox
var/admin_spawned = 0 //was this spawned by an admin? used for stat tracking stuff.
@@ -469,4 +472,4 @@
/atom/on_varedit(modified_var)
if(!Debug2)
admin_spawned = TRUE
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/game/machinery/holosign.dm b/code/game/machinery/holosign.dm
index 3abbcef84ae..5ce444bcc09 100644
--- a/code/game/machinery/holosign.dm
+++ b/code/game/machinery/holosign.dm
@@ -36,7 +36,7 @@
/obj/machinery/holosign_switch
name = "holosign switch"
icon = 'icons/obj/power.dmi'
- icon_state = "light1"
+ icon_state = "light0"
desc = "A remote control switch for holosign."
var/id = null
var/active = 0
diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm
index 1a901f4a71e..a08f4bea77a 100644
--- a/code/game/mecha/combat/marauder.dm
+++ b/code/game/mecha/combat/marauder.dm
@@ -157,10 +157,10 @@
log_message("Toggled zoom mode.")
occupant_message("Zoom mode [zoom?"en":"dis"]abled.")
if(zoom)
- occupant.client.view = 12
+ occupant.client.AddViewMod("mecha", 12)
to_chat(occupant, sound('sound/mecha/imag_enh.ogg',volume=50))
else
- occupant.client.view = initial(occupant.client.view)
+ occupant.client.RemoveViewMod("mecha")
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 9eab3e88cee..1daa7300b1d 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -1309,7 +1309,7 @@
dir = dir_in
if(L && L.client)
- L.client.view = world.view
+ L.client.RemoveViewMod("mecha")
/////////////////////////
////// Access stuff /////
diff --git a/code/game/objects/effects/glowshroom.dm b/code/game/objects/effects/glowshroom.dm
index f641cb26c32..9af07df67b4 100644
--- a/code/game/objects/effects/glowshroom.dm
+++ b/code/game/objects/effects/glowshroom.dm
@@ -162,6 +162,8 @@
G.endurance -= damage_to_do
G.CheckEndurance()
return
+ else if(I.sharp)
+ damage_to_do = I.force * 3 // wirecutter: 6->18, knife 10->30, hatchet 12->36
if(I.damtype != STAMINA)
endurance -= damage_to_do
CheckEndurance()
diff --git a/code/game/objects/items/weapons/highlander_swords.dm b/code/game/objects/items/weapons/highlander_swords.dm
new file mode 100644
index 00000000000..22686b90c96
--- /dev/null
+++ b/code/game/objects/items/weapons/highlander_swords.dm
@@ -0,0 +1,50 @@
+
+//Highlander Style Martial Art
+// Prevents use of guns, but makes the highlander impervious to ranged attacks. Their bravery in battle shields them from the weapons of COWARDS!
+
+/datum/martial_art/highlander
+ name = "Highlander Style"
+ deflection_chance = 100
+ no_guns = TRUE
+ no_guns_message = "You'd never stoop so low as to use the weapon of a COWARD!"
+
+
+//Highlander Claymore
+// Grants the wielder the Highlander Style Martial Art
+
+/obj/item/weapon/claymore/highlander
+ name = "Highlander Claymore"
+ desc = "Imbues the wielder with legendary martial prowress and a nigh-unquenchable thirst for glorious battle!"
+ var/datum/martial_art/highlander/style = new
+
+/obj/item/weapon/claymore/highlander/Destroy()
+ if(ishuman(loc)) //just in case it gets destroyed while in someone's possession, such as due to acid or something?
+ var/mob/living/carbon/human/H = loc
+ style.remove(H)
+ QDEL_NULL(style)
+ return ..()
+
+/obj/item/weapon/claymore/highlander/equipped(mob/user, slot)
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/H = user
+ if(slot == slot_r_hand || slot == slot_l_hand)
+ if(H.martial_art && H.martial_art != style)
+ style.teach(H, 1)
+ to_chat(H, "THERE CAN ONLY BE ONE!")
+ else if(H.martial_art && H.martial_art == style)
+ style.remove(H)
+ var/obj/item/weapon/claymore/highlander/sword = H.is_in_hands(/obj/item/weapon/claymore/highlander)
+ if(sword)
+ //if we have a highlander sword in the other hand, relearn the style from that sword.
+ sword.style.teach(H, 1)
+
+/obj/item/weapon/claymore/highlander/dropped(mob/user)
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/H = user
+ style.remove(H)
+ var/obj/item/weapon/claymore/highlander/sword = H.is_in_hands(/obj/item/weapon/claymore/highlander)
+ if(sword)
+ //if we have a highlander sword in the other hand, relearn the style from that sword.
+ sword.style.teach(H, 1)
diff --git a/code/game/objects/items/weapons/implants/implant_track.dm b/code/game/objects/items/weapons/implants/implant_track.dm
index d0d1159a9c5..e0d44cdefcf 100644
--- a/code/game/objects/items/weapons/implants/implant_track.dm
+++ b/code/game/objects/items/weapons/implants/implant_track.dm
@@ -30,3 +30,11 @@
circuitry. As a result neurotoxins can cause massive damage.
Implant Specifics:
"}
return dat
+
+/obj/item/weapon/implantcase/track
+ name = "implant case - 'Tracking'"
+ desc = "A glass case containing a tracking implant."
+
+/obj/item/weapon/implantcase/track/New()
+ imp = new /obj/item/weapon/implant/tracking(src)
+ ..()
\ No newline at end of file
diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm
index 9636e1407b6..f3ab646c952 100644
--- a/code/game/objects/structures/artstuff.dm
+++ b/code/game/objects/structures/artstuff.dm
@@ -1,10 +1,3 @@
-/////////////////
-// NEW DEFINES //
-/////////////////
-
-/client
- var/viewingCanvas = 0 //If this is 1, as soon as client /TRIES/ to move the view resets.
-
///////////
// EASEL //
///////////
@@ -140,20 +133,4 @@ var/global/list/globalBlankCanvases[AMT_OF_CANVASES]
icon = blank
user.visible_message("[user] cleans the canvas.","You clean the canvas.")
-//Examine to enlarge
-/obj/item/weapon/canvas/examine(mob/user)
- ..(user)
- if(in_range(user, src) && get_turf(src) && user.client && ishuman(user)) //Let only humans be the robust zoominators. I'm too spooked other mobs trying to use it may get broken huds.
- if(src.loc == user || get_turf(src) == get_turf(user))
- to_chat(user, "[src] has to be on the ground to focus on it!")
- return
- to_chat(user, "You focus on \the [src].")
- user.client.screen = list() //This is because screen objects go way past the view bounds we set, therefore not allowing stretch to fit to zoom in properly.
- user.client.reset_stretch = winget(user.client, "mapwindow.map", "icon-size") //Remember previous icon-size
- user.client.view = 3 //Decrease view
- winset(user.client, "mapwindow.map", "icon-size=0") //Enable stretch-to-fit
- user.client.viewingCanvas = 1 //Reset everything we just changed as soon as client tries to move
- else
- to_chat(user, "It is too far away.")
-
#undef AMT_OF_CANVASES
\ No newline at end of file
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 6db9a26fd8d..d5b966c7d98 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -193,6 +193,9 @@
L[tmpname] = R
var/desc = input("Please select a telepad.", "RCS") in L
E.pad = L[desc]
+ if(!Adjacent(user))
+ to_chat(user, "Unable to teleport, too far from crate.")
+ return
playsound(E.loc, E.usesound, 50, 1)
to_chat(user, "Teleporting [name]...")
E.teleporting = 1
@@ -204,17 +207,22 @@
to_chat(user, "Error: User located in container--aborting for safety.")
playsound(E.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
return
+ if(!(E.rcell && E.rcell.use(E.chargecost)))
+ to_chat(user, "Unable to teleport, insufficient charge.")
+ return
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
s.set_up(5, 1, src)
s.start()
do_teleport(src, E.pad, 0)
- E.rcell.use(E.chargecost)
to_chat(user, "Teleport successful. [round(E.rcell.charge/E.chargecost)] charge\s left.")
return
else
E.rand_x = rand(50,200)
E.rand_y = rand(50,200)
var/L = locate(E.rand_x, E.rand_y, 6)
+ if(!Adjacent(user))
+ to_chat(user, "Unable to teleport, too far from crate.")
+ return
playsound(E.loc, E.usesound, 50, 1)
to_chat(user, "Teleporting [name]...")
E.teleporting = 1
@@ -226,11 +234,13 @@
to_chat(user, "Error: User located in container--aborting for safety.")
playsound(E.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
return
+ if(!(E.rcell && E.rcell.use(E.chargecost)))
+ to_chat(user, "Unable to teleport, insufficient charge.")
+ return
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
s.set_up(5, 1, src)
s.start()
do_teleport(src, L)
- E.rcell.use(E.chargecost)
to_chat(user, "Teleport successful. [round(E.rcell.charge/E.chargecost)] charge\s left.")
return
else
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index 76b69edc28c..ed2599e91dd 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -327,7 +327,7 @@
new /obj/item/clothing/suit/storage/det_suit(src)
new /obj/item/clothing/suit/storage/det_suit/forensics/blue(src)
new /obj/item/clothing/suit/storage/det_suit/forensics/red(src)
- new /obj/item/clothing/gloves/color/black(src)
+ new /obj/item/clothing/gloves/color/black/forensics(src)
new /obj/item/clothing/head/det_hat(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/weapon/storage/box/evidence(src)
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 07a738a8c94..010da69a834 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -102,6 +102,9 @@
L[tmpname] = R
var/desc = input("Please select a telepad.", "RCS") in L
E.pad = L[desc]
+ if(!Adjacent(user))
+ to_chat(user, "Unable to teleport, too far from crate.")
+ return
playsound(E.loc, E.usesound, 50, 1)
to_chat(user, "Teleporting [src.name]...")
E.teleporting = 1
@@ -109,17 +112,23 @@
E.teleporting = 0
return
E.teleporting = 0
+ if(!(E.rcell && E.rcell.use(E.chargecost)))
+ to_chat(user, "Unable to teleport, insufficient charge.")
+ return
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
s.set_up(5, 1, src)
s.start()
do_teleport(src, E.pad, 0)
- E.rcell.use(E.chargecost)
to_chat(user, "Teleport successful. [round(E.rcell.charge/E.chargecost)] charge\s left.")
return
+
else
E.rand_x = rand(50,200)
E.rand_y = rand(50,200)
var/L = locate(E.rand_x, E.rand_y, 6)
+ if(!Adjacent(user))
+ to_chat(user, "Unable to teleport, too far from crate.")
+ return
playsound(E.loc, E.usesound, 50, 1)
to_chat(user, "Teleporting [src.name]...")
E.teleporting = 1
@@ -127,11 +136,13 @@
E.teleporting = 0
return
E.teleporting = 0
+ if(!(E.rcell && E.rcell.use(E.chargecost)))
+ to_chat(user, "Unable to teleport, insufficient charge.")
+ return
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
s.set_up(5, 1, src)
s.start()
do_teleport(src, L)
- E.rcell.use(E.chargecost)
to_chat(user, "Teleport successful. [round(E.rcell.charge/E.chargecost)] charge\s left.")
return
else
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 6853baf0755..d7de6dd6844 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -101,7 +101,9 @@ var/global/nologevent = 0
[check_rights(R_ADMIN,0) ? "Traitor panel | " : "" ]
Narrate to |
- Subtle message
+ Subtle message |
+ Bless |
+ Smite
"}
if(M.client)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 605c4acd1f3..b43001f3abc 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1546,7 +1546,7 @@
to_chat(X, take_msg)
else if(is_mhelp && check_rights(R_MOD|R_MENTOR, 0, X.mob))
to_chat(X, take_msg)
- to_chat(M, "Your question is being attended to by [key_name(usr.client)]. Thanks for your patience!")
+ to_chat(M, "Your question is being attended to by [key_name(usr.client, null, 0)]. Thanks for your patience!")
else
to_chat(usr, "Unable to locate mob.")
@@ -1790,9 +1790,15 @@
H = M
ptypes += "Brain Damage"
ptypes += "Honk Tumor"
+ ptypes += "Hallucinate"
+ ptypes += "Cold"
+ ptypes += "Hunger"
ptypes += "Cluwne"
ptypes += "Mutagen Cookie"
ptypes += "Hellwater Cookie"
+ ptypes += "Assassin"
+ ptypes += "Priest"
+ ptypes += "Lynch"
var/punishment = input(owner, "How would you like to smite [M]?", "Its good to be baaaad...", "") as null|anything in ptypes
if(!(punishment in ptypes))
return
@@ -1820,6 +1826,15 @@
to_chat(H, "Life seems funnier, somehow.")
organ.insert(H)
logmsg = "a honk tumor."
+ if("Hallucinate")
+ H.Hallucinate(1000)
+ logmsg = "hallucinations."
+ if("Hunger")
+ H.nutrition = NUTRITION_LEVEL_CURSED
+ logmsg = "starvation."
+ if("Cold")
+ H.reagents.add_reagent("frostoil", 40)
+ H.reagents.add_reagent("ice", 40)
if("Cluwne")
H.makeCluwne()
logmsg = "cluwned."
@@ -1828,6 +1843,7 @@
evilcookie.reagents.add_reagent("mutagen", 10)
evilcookie.desc = "It has a faint green glow."
evilcookie.bitesize = 100
+ evilcookie.flags = NODROP
H.drop_l_hand()
H.equip_to_slot_or_del(evilcookie, slot_l_hand)
logmsg = "a mutagen cookie."
@@ -1836,9 +1852,92 @@
evilcookie.reagents.add_reagent("hell_water", 25)
evilcookie.desc = "Sulphur-flavored."
evilcookie.bitesize = 100
+ evilcookie.flags = NODROP
H.drop_l_hand()
H.equip_to_slot_or_del(evilcookie, slot_l_hand)
logmsg = "a hellwater cookie."
+ if("Priest")
+ logmsg = "priest."
+ H.mutations |= NOCLONE
+ message_admins("[key_name_admin(owner)] is sending a dark priest to assassinate [key_name_admin(M)]...")
+ var/list/candidates = pollCandidates("Do you want to play as a murderous dark priest?")
+ if(!candidates.len)
+ to_chat(usr, "ERROR: Could not create priest. No valid candidates.")
+ return
+ var/mob/C = pick(candidates)
+ var/key_of_priest = C.key
+ if(!key_of_priest)
+ to_chat(usr, "ERROR: Could not create priest. Could not pick key.")
+ return
+ var/datum/mind/priest_mind = new /datum/mind(key_of_priest)
+ priest_mind.active = 1
+ var/mob/living/carbon/human/priest_mob = new /mob/living/carbon/human(pick(latejoin))
+ priest_mind.transfer_to(priest_mob)
+ var/datum/outfit/admin/dark_priest/O = new /datum/outfit/admin/dark_priest
+ priest_mob.equipOutfit(O, FALSE)
+ var/obj/item/weapon/pinpointer/advpinpointer/N = new /obj/item/weapon/pinpointer/advpinpointer(priest_mob)
+ priest_mob.equip_to_slot_or_del(N, slot_r_store)
+ N.active = 1
+ N.mode = 2
+ N.target = H
+ N.point_at(N.target)
+ N.flags |= NODROP
+ var/datum/objective/assassinate/kill_objective = new
+ kill_objective.owner = priest_mind
+ kill_objective.target = H.mind
+ kill_objective.explanation_text = "Murder [H.real_name], the [H.mind.assigned_role], in the name of the dark gods."
+ priest_mind.objectives += kill_objective
+ ticker.mode.traitors |= priest_mob.mind
+ to_chat(priest_mob, "ATTENTION: You are now a dark priest!")
+ to_chat(priest_mob, "Goal: MURDER [H.real_name], currently in [get_area(H.loc)], in the name of the dark gods. ");
+ to_chat(priest_mob, "The gods will prevent their revival.");
+ priest_mob.mind.special_role = SPECIAL_ROLE_TRAITOR
+ var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR]
+ tatorhud.join_hud(priest_mob)
+ ticker.mode.set_antag_hud(priest_mob, "hudsyndicate")
+ if("Assassin")
+ logmsg = "assassin."
+ var/list/possible_traitors = list()
+ for(var/mob/living/player in living_mob_list)
+ if(player.client && player.mind && !player.mind.special_role && player.stat != DEAD && player != H)
+ if(ishuman(player))
+ if(player.client && (ROLE_TRAITOR in player.client.prefs.be_special) && !jobban_isbanned(player, ROLE_TRAITOR) && !jobban_isbanned(player, "Syndicate"))
+ possible_traitors += player.mind
+ for(var/datum/mind/player in possible_traitors)
+ if(player.current)
+ if(ismindshielded(player.current))
+ possible_traitors -= player
+ if(possible_traitors.len)
+ var/datum/mind/newtraitormind = pick(possible_traitors)
+ var/mob/living/newtraitor = newtraitormind.current
+ var/datum/objective/assassinate/kill_objective = new
+ kill_objective.owner = newtraitormind
+ kill_objective.target = H.mind
+ kill_objective.explanation_text = "Assassinate [H.real_name], the [H.mind.assigned_role]."
+ newtraitormind.objectives += kill_objective
+ ticker.mode.equip_traitor(newtraitor)
+ ticker.mode.traitors |= newtraitor.mind
+ to_chat(newtraitor, "ATTENTION: It is time to pay your debt to the Syndicate...")
+ to_chat(newtraitor, "You are now a traitor.")
+ to_chat(newtraitor, "Goal: KILL [H.real_name], currently in [get_area(H.loc)]");
+ newtraitor.mind.special_role = SPECIAL_ROLE_TRAITOR
+ var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR]
+ tatorhud.join_hud(newtraitor)
+ ticker.mode.set_antag_hud(newtraitor, "hudsyndicate")
+ else
+ to_chat(usr, "ERROR: Failed to create a traitor.")
+ return
+ if("Lynch")
+ logmsg = "lynch."
+ for(var/datum/mind/crew in ticker.minds)
+ if(!crew.current)
+ continue
+ if(!isliving(crew.current))
+ continue
+ if(crew == H.mind)
+ continue
+ to_chat(crew.current, "
The gods have given you a task: find [H.real_name], located in [get_area(H.loc)], and slay them!");
+ to_chat(crew.current, "Do not harm anyone other than [H.real_name] while carrying out this task.
");
if("Gib")
logmsg = "gibbed."
M.gib(FALSE)
diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm
index 9bfe544cef5..79914745e79 100644
--- a/code/modules/admin/verbs/onlyone.dm
+++ b/code/modules/admin/verbs/onlyone.dm
@@ -37,7 +37,7 @@
H.equip_to_slot_or_del(new /obj/item/clothing/under/kilt(H), slot_w_uniform)
H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(H), slot_l_ear)
H.equip_to_slot_or_del(new /obj/item/clothing/head/beret(H), slot_head)
- H.equip_to_slot_or_del(new /obj/item/weapon/claymore(H), slot_r_hand)
+ H.equip_to_slot_or_del(new /obj/item/weapon/claymore/highlander(H), slot_r_hand)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(H), slot_shoes)
H.equip_to_slot_or_del(new /obj/item/weapon/pinpointer(H.loc), slot_l_store)
diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm
index d547a9a582f..ca3d17e9c50 100644
--- a/code/modules/client/client defines.dm
+++ b/code/modules/client/client defines.dm
@@ -76,8 +76,6 @@
"off" = "borgmacro")
)
- var/reset_stretch = 0 //Used by things that fiddle with client's stretch-to-fit.
-
var/topic_debugging = 0 //if set to true, allows client to see nanoUI errors -- yes i realize this is messy but it'll make live testing infinitely easier
control_freak = CONTROL_FREAK_ALL | CONTROL_FREAK_SKIN | CONTROL_FREAK_MACROS
@@ -93,7 +91,7 @@
// Donator stuff.
var/donator_level = DONATOR_LEVEL_NONE
-
+
// If set to true, this client can interact with atoms such as buttons and doors on top of regular machinery interaction
var/advanced_admin_interaction = FALSE
diff --git a/code/modules/client/view.dm b/code/modules/client/view.dm
new file mode 100644
index 00000000000..f4e74e203e8
--- /dev/null
+++ b/code/modules/client/view.dm
@@ -0,0 +1,90 @@
+/*
+ * ViewMods Client module
+ * This should be used by anything that wants to change a client's view range.
+ * Also includes
+ */
+
+/* Defines */
+#define CUSTOM_VIEWRANGES list(1, 2, 3, 4, 5, 6, "RESET")
+
+/* Viewmods */
+/client
+ var/list/ViewMods = list()
+ var/ViewModsActive = FALSE
+ var/ViewPreferedIconSize = 0
+
+/client/proc/AddViewMod(id, size)
+ var/datum/viewmod/V = new /datum/viewmod(id, size)
+ ViewMods[V.id] = V
+ UpdateView()
+
+/client/proc/CheckViewMod(id)
+ . = 0
+ if(ViewMods[id])
+ . = 1
+
+/client/proc/RemoveViewMod(id)
+ if(CheckViewMod(id))
+ qdel(ViewMods[id])
+ ViewMods.Remove(id)
+ UpdateView()
+
+/client/proc/UpdateView()
+ if(!ViewModsActive)
+ ViewPreferedIconSize = winget(src, "mapwindow.map", "icon-size")
+
+ var/highest_range = 0
+ for(var/mod_id in ViewMods)
+ var/datum/viewmod/V = ViewMods[mod_id]
+ highest_range = max(highest_range, V.size)
+
+ SetView(highest_range ? highest_range : world.view)
+ ViewModsActive = (highest_range > 0)
+
+/client/proc/SetView(view_range)
+ if(view_range == world.view)
+ winset(src, "mapwindow.map", "icon-size=[ViewPreferedIconSize]")
+ else
+ winset(src, "mapwindow.map", "icon-size=0")
+
+ view = view_range
+
+ if(mob && mob.hud_used)
+ // If view range is less than world.view, assume the HUD will not fit under normal mode and turn it to reduced
+ if(view_range < world.view)
+ // If it's really tiny, turn their hud off completely
+ if(view_range <= ARBITRARY_VIEWRANGE_NOHUD)
+ mob.hud_used.show_hud(HUD_STYLE_NOHUD)
+ else
+ mob.hud_used.show_hud(HUD_STYLE_REDUCED)
+ else
+ mob.hud_used.show_hud(HUD_STYLE_STANDARD)
+
+/* Viewmod datums */
+/datum/viewmod
+ var/id = ""
+ var/size = -1
+
+/datum/viewmod/New(new_id, new_size = world.view)
+ . = ..()
+ id = new_id
+ size = new_size
+
+/* Client verbs */
+/proc/viewNum_to_text(view)
+ return "[(view * 2) + 1]x[(view * 2) + 1]"
+
+/client/verb/set_view_range(view_range as null|anything in CUSTOM_VIEWRANGES)
+ set name = "Set View Range"
+ set category = "Preferences"
+
+ if(!view_range)
+ return
+
+ RemoveViewMod("custom")
+ if(view_range == "RESET")
+ to_chat(src, "View range reset.")
+ return
+
+ to_chat(src, "View range set to [viewNum_to_text(view_range)]")
+ AddViewMod("custom", view_range)
\ No newline at end of file
diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm
index ee5022a1793..5b0ec203c1d 100644
--- a/code/modules/clothing/gloves/miscellaneous.dm
+++ b/code/modules/clothing/gloves/miscellaneous.dm
@@ -17,6 +17,13 @@
icon_state = "black"
item_state = "r_hands"
+
+/obj/item/clothing/gloves/color/black/forensics
+ name = "forensics gloves"
+ desc = "These high-tech gloves don't leave any material traces on objects they touch. Perfect for leaving crime scenes undisturbed...both before and after the crime."
+ icon_state = "forensics"
+ can_leave_fibers = FALSE
+
/obj/item/clothing/gloves/combat
desc = "These tactical gloves are somewhat fire and impact resistant."
name = "combat gloves"
@@ -124,4 +131,4 @@
to_chat(user, "You cut [cell] away from [src].")
cell.forceMove(get_turf(loc))
cell = null
- update_icon()
\ No newline at end of file
+ update_icon()
diff --git a/code/modules/detective_work/detective_work.dm b/code/modules/detective_work/detective_work.dm
index 01267f2fb08..dd22a439c19 100644
--- a/code/modules/detective_work/detective_work.dm
+++ b/code/modules/detective_work/detective_work.dm
@@ -16,33 +16,33 @@ atom/proc/add_fibers(mob/living/carbon/human/M)
var/item_multiplier = istype(src,/obj/item)?1.2:1
if(M.wear_suit)
fibertext = "Material from \a [M.wear_suit]."
- if(prob(10*item_multiplier) && !(fibertext in suit_fibers))
+ if(prob(10*item_multiplier) && !(fibertext in suit_fibers) && M.wear_suit.can_leave_fibers)
//log_to_dd("Added fibertext: [fibertext]")
suit_fibers += fibertext
if(!(M.wear_suit.body_parts_covered & UPPER_TORSO))
if(M.w_uniform)
fibertext = "Fibers from \a [M.w_uniform]."
- if(prob(12*item_multiplier) && !(fibertext in suit_fibers)) //Wearing a suit means less of the uniform exposed.
+ if(prob(12*item_multiplier) && !(fibertext in suit_fibers) && M.w_uniform.can_leave_fibers) //Wearing a suit means less of the uniform exposed.
//log_to_dd("Added fibertext: [fibertext]")
suit_fibers += fibertext
if(!(M.wear_suit.body_parts_covered & HANDS))
if(M.gloves)
fibertext = "Material from a pair of [M.gloves.name]."
- if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
+ if(prob(20*item_multiplier) && !(fibertext in suit_fibers) && M.gloves.can_leave_fibers)
//log_to_dd("Added fibertext: [fibertext]")
suit_fibers += fibertext
else if(M.w_uniform)
fibertext = "Fibers from \a [M.w_uniform]."
- if(prob(15*item_multiplier) && !(fibertext in suit_fibers))
+ if(prob(15*item_multiplier) && !(fibertext in suit_fibers) && M.w_uniform.can_leave_fibers)
// "Added fibertext: [fibertext]"
suit_fibers += fibertext
if(M.gloves)
fibertext = "Material from a pair of [M.gloves.name]."
- if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
+ if(prob(20*item_multiplier) && !(fibertext in suit_fibers) && M.gloves.can_leave_fibers)
//log_to_dd("Added fibertext: [fibertext]")
suit_fibers += "Material from a pair of [M.gloves.name]."
else if(M.gloves)
fibertext = "Material from a pair of [M.gloves.name]."
- if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
+ if(prob(20*item_multiplier) && !(fibertext in suit_fibers) && M.gloves.can_leave_fibers)
//log_to_dd("Added fibertext: [fibertext]")
- suit_fibers += "Material from a pair of [M.gloves.name]."
\ No newline at end of file
+ suit_fibers += "Material from a pair of [M.gloves.name]."
diff --git a/code/modules/martial_arts/martial.dm b/code/modules/martial_arts/martial.dm
index 3f1705f4651..10b3e8f3ad0 100644
--- a/code/modules/martial_arts/martial.dm
+++ b/code/modules/martial_arts/martial.dm
@@ -7,6 +7,8 @@
var/datum/martial_art/base = null // The permanent style
var/deflection_chance = 0 //Chance to deflect projectiles
var/help_verb = null
+ var/no_guns = FALSE //set to TRUE to prevent users of this style from using guns (sleeping carp, highlander). They can still pick them up, but not fire them.
+ var/no_guns_message = "" //message to tell the style user if they try and use a gun while no_guns = TRUE (DISHONORABRU!)
/datum/martial_art/proc/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
return 0
diff --git a/code/modules/martial_arts/sleeping_carp.dm b/code/modules/martial_arts/sleeping_carp.dm
index 960844a063a..c6af4679552 100644
--- a/code/modules/martial_arts/sleeping_carp.dm
+++ b/code/modules/martial_arts/sleeping_carp.dm
@@ -8,6 +8,8 @@
name = "The Sleeping Carp"
deflection_chance = 100
help_verb = /mob/living/carbon/human/proc/sleeping_carp_help
+ no_guns = TRUE
+ no_guns_message = "Use of ranged weaponry would bring dishonor to the clan."
/datum/martial_art/the_sleeping_carp/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
if(findtext(streak,WRIST_WRENCH_COMBO))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 000a7a52bd0..e8737175b23 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1985,8 +1985,8 @@
to_chat(src, "Your fingers don't fit in the trigger guard!")
return 0
- if(martial_art && martial_art.name == "The Sleeping Carp") //great dishonor to famiry
- to_chat(src, "Use of ranged weaponry would bring dishonor to the clan.")
+ if(martial_art && martial_art.no_guns) //great dishonor to famiry
+ to_chat(src, "[martial_art.no_guns_message]")
return 0
return .
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index 95a1d100161..5f977bfd508 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -37,12 +37,85 @@
icon_resting = "cat_rest"
gender = FEMALE
gold_core_spawnable = CHEM_MOB_SPAWN_INVALID
+ var/list/family = list()
+ var/memory_saved = 0
+ var/list/children = list() //Actual mob instances of children
+ var/cats_deployed = 0
+
+/mob/living/simple_animal/pet/cat/Runtime/New()
+ Read_Memory()
+ ..()
+
+/mob/living/simple_animal/pet/cat/Runtime/Life()
+ if(!cats_deployed && ticker.current_state >= GAME_STATE_SETTING_UP)
+ Deploy_The_Cats()
+ if(!stat && ticker.current_state == GAME_STATE_FINISHED && !memory_saved)
+ Write_Memory()
+ ..()
+
+/mob/living/simple_animal/pet/cat/Runtime/make_babies()
+ var/mob/baby = ..()
+ if(baby)
+ children += baby
+ return baby
+
+/mob/living/simple_animal/pet/cat/Runtime/death()
+ if(!memory_saved)
+ Write_Memory(1)
+ ..()
+
+/mob/living/simple_animal/pet/cat/Runtime/proc/Read_Memory()
+ var/savefile/S = new /savefile("data/npc_saves/Runtime.sav")
+ S["family"] >> family
+
+ if(isnull(family))
+ family = list()
+
+/mob/living/simple_animal/pet/cat/Runtime/proc/Write_Memory(dead)
+ var/savefile/S = new /savefile("data/npc_saves/Runtime.sav")
+ family = list()
+ if(!dead)
+ for(var/mob/living/simple_animal/pet/cat/kitten/C in children)
+ if(istype(C,type) || C.stat || !C.z || !C.butcher_results)
+ continue
+ if(C.type in family)
+ family[C.type] += 1
+ else
+ family[C.type] = 1
+ S["family"] << family
+ memory_saved = 1
+
+/mob/living/simple_animal/pet/cat/Runtime/proc/Deploy_The_Cats()
+ cats_deployed = 1
+ for(var/cat_type in family)
+ if(family[cat_type] > 0)
+ for(var/i in 1 to min(family[cat_type],100)) //Limits to about 500 cats, you wouldn't think this would be needed (BUT IT IS)
+ new cat_type(loc)
+
/mob/living/simple_animal/pet/cat/handle_automated_action()
..()
+ if(prob(1))
+ custom_emote(1, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
+ icon_state = "[icon_living]_rest"
+ resting = 1
+ update_canmove()
+ else if (prob(1))
+ custom_emote(1, pick("sits down.", "crouches on its hind legs.", "looks alert."))
+ icon_state = "[icon_living]_sit"
+ resting = 1
+ update_canmove()
+ else if (prob(1))
+ if (resting)
+ custom_emote(1, pick("gets up and meows.", "walks around.", "stops resting."))
+ icon_state = "[icon_living]"
+ resting = 0
+ update_canmove()
+ else
+ custom_emote(1, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
//MICE!
- if(eats_mice && loc && isturf(loc) && !incapacitated())
+ if(eats_mice && isturf(loc) && !incapacitated())
for(var/mob/living/simple_animal/mouse/M in view(1,src))
if(!M.stat && Adjacent(M))
custom_emote(1, "splats \the [M]!")
@@ -50,13 +123,11 @@
movement_target = null
stop_automated_movement = 0
break
-
- //attempt to mate
make_babies()
/mob/living/simple_animal/pet/cat/handle_automated_movement()
..()
- if(eats_mice && !incapacitated())
+ if(!stat && !resting && !buckled)
turns_since_scan++
if(turns_since_scan > 5)
walk_to(src,0)
@@ -75,6 +146,7 @@
stop_automated_movement = 1
walk_to(src,movement_target,0,3)
+
/mob/living/simple_animal/pet/cat/Proc
name = "Proc"
@@ -102,4 +174,4 @@
gold_core_spawnable = CHEM_MOB_SPAWN_INVALID
eats_mice = 0
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
- minbodytemp = 0
\ No newline at end of file
+ minbodytemp = 0
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 1aa6c82b4a8..f24068bf35d 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -592,7 +592,7 @@
alone = 0
continue
if(alone && partner && children < 3)
- new childtype(loc)
+ return new childtype(loc)
/mob/living/simple_animal/say_quote(var/message)
var/verb = "says"
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 03ba9618bd4..20e08001754 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -149,14 +149,6 @@
/client/Move(n, direct)
- if(viewingCanvas)
- view = world.view //Reset the view
- winset(src, "mapwindow.map", "icon-size=[src.reset_stretch]")
- viewingCanvas = 0
- mob.reset_perspective()
- if(mob.hud_used)
- mob.hud_used.show_hud(HUD_STYLE_STANDARD)
-
if(world.time < move_delay)
return
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 3f42b4d58ce..366c9ee52af 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -122,6 +122,7 @@
fixture_type = "bulb"
sheets_refunded = 1
+
// the standard tube light fixture
/obj/machinery/light
name = "light fixture"
@@ -149,6 +150,7 @@
// this is used to calc the probability the light burns out
var/rigged = 0 // true if rigged to explode
+ var/lightmaterials = list(MAT_GLASS=100) //stores the materials the light is made of to stop infinite glass exploit
// the smaller bulb light fixture
@@ -305,6 +307,7 @@
brightness_range = L.brightness_range
brightness_power = L.brightness_power
brightness_color = L.brightness_color
+ lightmaterials = L.materials
on = has_power()
update()
@@ -472,6 +475,7 @@
L.brightness_range = brightness_range
L.brightness_power = brightness_power
L.brightness_color = brightness_color
+ L.materials = lightmaterials
// light item inherits the switchcount, then zero it
L.switchcount = switchcount
@@ -500,6 +504,7 @@
L.brightness_range = brightness_range
L.brightness_power = brightness_power
L.brightness_color = brightness_color
+ L.materials = lightmaterials
// light item inherits the switchcount, then zero it
L.switchcount = switchcount
@@ -596,7 +601,7 @@
var/status = 0 // LIGHT_OK, LIGHT_BURNED or LIGHT_BROKEN
var/base_state
var/switchcount = 0 // number of times switched
- materials = list(MAT_METAL=60)
+ materials = list(MAT_GLASS=100)
var/rigged = 0 // true if rigged to explode
var/brightness_range = 2 //how much light it gives off
var/brightness_power = 1
@@ -608,7 +613,6 @@
icon_state = "ltube"
base_state = "ltube"
item_state = "c_tube"
- materials = list(MAT_GLASS=100)
brightness_range = 8
/obj/item/weapon/light/tube/large
@@ -623,7 +627,6 @@
icon_state = "lbulb"
base_state = "lbulb"
item_state = "contvapour"
- materials = list(MAT_GLASS=100)
brightness_range = 5
brightness_color = "#a0a080"
@@ -637,7 +640,6 @@
icon_state = "fbulb"
base_state = "fbulb"
item_state = "egg4"
- materials = list(MAT_GLASS=100)
brightness_range = 5
// update the icon state and description of the light
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index c84c7c4c6c8..66c150f636d 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -394,22 +394,22 @@
build_path = /obj/item/weapon/implantcase
category = list("Medical")
-/datum/design/implant_freedom
- name = "Freedom Implant Case"
+/datum/design/implant_chem
+ name = "Chemical Implant Case"
desc = "A glass case containing an implant."
- id = "implant_freedom"
- req_tech = list("combat" = 6, "biotech" = 5, "magnets" = 3, "syndicate" = 3)
+ id = "implant_chem"
+ req_tech = list("materials" = 3, "biotech" = 5,)
build_type = PROTOLATHE
- materials = list(MAT_METAL = 800, MAT_GLASS = 500, MAT_GOLD = 500)
- build_path = /obj/item/weapon/implantcase/freedom
+ materials = list(MAT_GLASS = 700)
+ build_path = /obj/item/weapon/implantcase/chem
category = list("Medical")
-/datum/design/implant_adrenalin
- name = "Adrenalin Implant Case"
+/datum/design/implant_tracking
+ name = "Tracking Implant Case"
desc = "A glass case containing an implant."
- id = "implant_adrenalin"
- req_tech = list("biotech" = 6, "combat" = 6, "syndicate" = 6)
+ id = "implant_tracking"
+ req_tech = list("materials" = 2, "biotech" = 3, "magnets" = 3, "programming" = 2)
build_type = PROTOLATHE
- materials = list(MAT_METAL = 1000, MAT_GLASS = 500, MAT_GOLD = 500, MAT_URANIUM = 600, MAT_DIAMOND = 600)
- build_path = /obj/item/weapon/implantcase/adrenaline
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500)
+ build_path = /obj/item/weapon/implantcase/track
category = list("Medical")
diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm
index e05c7bc924a..d24853a7948 100644
--- a/code/modules/shuttle/supply.dm
+++ b/code/modules/shuttle/supply.dm
@@ -245,6 +245,7 @@
/obj/machinery/teleport/station,
/obj/machinery/teleport/hub,
/obj/machinery/telepad,
+ /obj/machinery/telepad_cargo,
/obj/machinery/clonepod,
/obj/effect/hierophant,
/obj/item/device/warp_cube,
diff --git a/html/changelog.html b/html/changelog.html
index 19eab0e6555..8321bac3afd 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -55,11 +55,56 @@
-->
+
10 June 2017
+
Alffd updated:
+
+ - Ports Incoming5643's persistence features for Runtime from TG
+ - Ports additional cat NPC emotes from TG
+
+
Citinited updated:
+
+ - Disconnecting before the shuttle leaves after having spent karma will no longer prompt you to spend karma.
+
+
FalseIncarnate updated:
+
+ - Adds Highlander Style, granted to the wielder of Highlander Claymores. This martial art allows you to deflect ranged attacks from the weapons of COWARDS. FOR THE HONOR OF THE HIGHLANDERS!
+ - Highlander now equips combatants with a Highlander claymore instead of a normal claymore. FIGHT ON BROTHERS!
+
+
09 June 2017
+
Alexshreds updated:
+
+ - Taking mhelps no longer gives mhelping players your IC name
+
+
FlattyPatty updated:
+
+ - Added forensics gloves for the Detective.
+
Fox McCloud updated:
- Paramedic door is no longer diamond
- Fixes the backwards health analyzer sprite
+ - Remove adrenaline and freedom implants from R&D
+ - Added chem and tracking implants to R&D
+
+
KasparoVy updated:
+
+ - Adds some sanity checking to the RCS.
+ - The cargo shuttle no longer permits RCS telepads.
+
+
Kyep updated:
+
+ - glowshrooms are now destroyable with two hits from a wirecutter.
+ - New 'department' shuttle, which can be sent by CC instead of the regular evac shuttle.
+ - The gods have grown tired of prayers requesting freebies, and developed some new curses with which to smite those who would treat them like miracle vending machines.
+
+
alexkar598 updated:
+
+ - Surgury holosign switch has correct icon at roundstart
+
+
tigercat2000 updated:
+
+ - You can now zoom in with the Set View Range option in your Preferences tab!
08 June 2017
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 111dd18c2b9..e05ac7eb89b 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -4870,6 +4870,40 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
Alexshreds:
- bugfix: Hyphema and Ocular Restoration are now possible to evolve from viruses
2017-06-09:
+ Alexshreds:
+ - tweak: Taking mhelps no longer gives mhelping players your IC name
+ FlattyPatty:
+ - rscadd: Added forensics gloves for the Detective.
Fox McCloud:
- tweak: Paramedic door is no longer diamond
- bugfix: Fixes the backwards health analyzer sprite
+ - rscdel: Remove adrenaline and freedom implants from R&D
+ - rscadd: Added chem and tracking implants to R&D
+ KasparoVy:
+ - bugfix: Adds some sanity checking to the RCS.
+ - bugfix: The cargo shuttle no longer permits RCS telepads.
+ Kyep:
+ - rscadd: glowshrooms are now destroyable with two hits from a wirecutter.
+ - rscadd: New 'department' shuttle, which can be sent by CC instead of the regular
+ evac shuttle.
+ - rscadd: The gods have grown tired of prayers requesting freebies, and developed
+ some new curses with which to smite those who would treat them like miracle
+ vending machines.
+ alexkar598:
+ - bugfix: Surgury holosign switch has correct icon at roundstart
+ tigercat2000:
+ - rscadd: You can now zoom in with the Set View Range option in your Preferences
+ tab!
+2017-06-10:
+ Alffd:
+ - rscadd: Ports Incoming5643's persistence features for Runtime from TG
+ - rscadd: Ports additional cat NPC emotes from TG
+ Citinited:
+ - bugfix: Disconnecting before the shuttle leaves after having spent karma will
+ no longer prompt you to spend karma.
+ FalseIncarnate:
+ - rscadd: Adds Highlander Style, granted to the wielder of Highlander Claymores.
+ This martial art allows you to deflect ranged attacks from the weapons of COWARDS.
+ FOR THE HONOR OF THE HIGHLANDERS!
+ - tweak: Highlander now equips combatants with a Highlander claymore instead of
+ a normal claymore. FIGHT ON BROTHERS!
diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi
index 82ce8437b28..42f1eda0e74 100644
Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 6d6976fa27a..71edb0e003d 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -806,6 +806,7 @@
#include "code\game\objects\items\weapons\garrote.dm"
#include "code\game\objects\items\weapons\gift_wrappaper.dm"
#include "code\game\objects\items\weapons\handcuffs.dm"
+#include "code\game\objects\items\weapons\highlander_swords.dm"
#include "code\game\objects\items\weapons\holosign.dm"
#include "code\game\objects\items\weapons\holy_weapons.dm"
#include "code\game\objects\items\weapons\kitchen.dm"
@@ -1139,6 +1140,7 @@
#include "code\modules\client\client defines.dm"
#include "code\modules\client\client procs.dm"
#include "code\modules\client\message.dm"
+#include "code\modules\client\view.dm"
#include "code\modules\client\preference\preferences.dm"
#include "code\modules\client\preference\preferences_mysql.dm"
#include "code\modules\client\preference\preferences_spawnpoints.dm"