diff --git a/.travis.yml b/.travis.yml
index eaa289e5cc7..526ebde75ea 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,16 +5,6 @@ sudo: false
git:
depth: 1
-env:
- global:
- - BYOND_MAJOR="511"
- - BYOND_MINOR="1385"
- - BYOND_MACRO_COUNT=2
- matrix:
- - DM_MAPFILE="cyberiad"
- - DM_MAPFILE="metastation"
- - DM_MAPFILE="test_away_missions"
-
cache:
directories:
- $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}
@@ -26,24 +16,57 @@ addons:
- libgcc1:i386
- libstdc++6:i386
+env:
+ global:
+ - BYOND_MAJOR="511"
+ - BYOND_MINOR="1385"
+ - BYOND_MACRO_COUNT=4
+ matrix:
+ - DM_MAPFILE="cyberiad"
+ - DM_MAPFILE="metastation"
+ - DM_MAPFILE="test_all_maps"
+
+stages:
+ - File Checks
+ - test
+
before_script:
- chmod +x ./install-byond.sh
- ./install-byond.sh
script:
- - (num=`grep -E '\\\\(red|blue|green|black|italic|bold|b|i[^mc])' **/*.dm | wc -l`; echo "$num BYOND text macros (expecting ${BYOND_MACRO_COUNT} or fewer)"; [ $num -le ${BYOND_MACRO_COUNT} ])
- source $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin/byondsetup
- bash dm.sh -M${DM_MAPFILE} paradise.dme
-matrix:
+jobs:
include:
- - env: FILE_CHECKS=1
+ # Basic styling/functionality checks
+ - stage: File Checks
+ env:
addons:
install:
- pip install --user PyYaml -q
- pip install --user beautifulsoup4 -q
- before_script:
+ before_script: skip
script:
- shopt -s globstar
- (! grep 'step_[xy]' _maps/map_files/**/*.dmm)
+ - (num=$(grep -Ern '\\(red|blue|green|black|italic|bold|b|i[^mc])' code/ | wc -l); echo "$num BYOND text macros (expecting ${BYOND_MACRO_COUNT} or fewer)"; [ $num -le ${BYOND_MACRO_COUNT} ])
- md5sum -c - <<< "6dc1b6bf583f3bd4176b6df494caa5f1 *html/changelogs/example.yml"
- python tools/ss13_genchangelog.py html/changelog.html html/changelogs
+
+ # Compile NanoUI to make sure it works
+ - stage: NanoUI
+ language: node_js
+ node_js:
+ - "9"
+ env:
+ addons:
+ before_install:
+ - npm install -g bower gulp
+ - cd ./nano/
+ install:
+ - npm install --loglevel=error
+ - bower install --silent
+ before_script:
+ script:
+ - gulp --min
diff --git a/_maps/map_files/RandomZLevels/evil_santa.dmm b/_maps/map_files/RandomZLevels/evil_santa.dmm
index 2b51f7407a5..ca6ab415c1f 100644
--- a/_maps/map_files/RandomZLevels/evil_santa.dmm
+++ b/_maps/map_files/RandomZLevels/evil_santa.dmm
@@ -14,7 +14,7 @@
"an" = (/obj/item/paper/journal_scrap_2,/turf/simulated/floor/carpet,/area/awaymission/challenge/main)
"ao" = (/obj/structure/flora/rock/pile,/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main)
"ap" = (/obj/structure/flora/tree/dead,/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main)
-"aq" = (/obj/machinery/door/unpowered/shuttle,/obj/structure/fans/tiny,/turf/simulated/floor/plasteel{icon_state = "delivery"},/area/awaymission/challenge/main)
+"aq" = (/obj/structure/mineral_door/wood{tag = "icon-wood"; icon_state = "wood"},/obj/structure/fans/tiny,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main)
"ar" = (/obj/item/restraints/legcuffs/beartrap,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main)
"as" = (/obj/machinery/space_heater,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main)
"at" = (/obj/structure/table/wood,/obj/item/newton,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main)
@@ -42,7 +42,7 @@
"aP" = (/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/turf/simulated/shuttle/wall{icon_state = "swall_f6"; dir = 2},/area/awaymission/challenge/main)
"aQ" = (/turf/simulated/shuttle/wall{icon_state = "swall12"; dir = 2},/area/awaymission/challenge/main)
"aR" = (/turf/simulated/shuttle/wall{icon_state = "swall8"; dir = 2},/area/awaymission/challenge/main)
-"aS" = (/obj/structure/mineral_door/wood{tag = "icon-wood"; icon_state = "wood"},/obj/structure/fans/tiny,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main)
+"aS" = (/obj/machinery/door/unpowered/shuttle,/obj/structure/fans/tiny,/turf/simulated/floor/plasteel{icon_state = "delivery"},/area/awaymission/challenge/main)
"aT" = (/turf/simulated/shuttle/wall{icon_state = "swall4"; dir = 2},/area/awaymission/challenge/main)
"aU" = (/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/turf/simulated/shuttle/wall{icon_state = "swall_f10"; dir = 2},/area/awaymission/challenge/main)
"aV" = (/turf/simulated/floor/plasteel{icon_plating = "asteroid"; icon_state = "asteroid"; name = "Asteroid"},/area/awaymission/challenge/main)
@@ -78,55 +78,54 @@
"bz" = (/obj/item/clothing/head/cone,/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main)
"bA" = (/mob/living/simple_animal/walrus,/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main)
"bB" = (/obj/structure/closet/toolcloset,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main)
-"bC" = (/obj/item/taperoll/engineering,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main)
-"bD" = (/obj/item/storage/toolbox/emergency,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main)
+"bC" = (/obj/item/storage/toolbox/emergency,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main)
+"bD" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
"bE" = (/obj/machinery/door/poddoor{id_tag = "challenge"; name = "Gateway Shutters"},/obj/structure/fans/tiny,/turf/simulated/floor/plasteel{tag = "icon-delivery (SOUTHEAST)"; icon_state = "delivery"; dir = 6},/area/awaymission/challenge/start)
-"bF" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
-"bG" = (/obj/machinery/door/unpowered/shuttle,/turf/simulated/floor/plasteel{tag = "icon-delivery (SOUTHEAST)"; icon_state = "delivery"; dir = 6},/area/awaymission/challenge/start)
-"bH" = (/obj/machinery/door/poddoor{id_tag = "challenge"; name = "Gateway Shutters"},/turf/simulated/floor/plasteel{tag = "icon-delivery (SOUTHEAST)"; icon_state = "delivery"; dir = 6},/area/awaymission/challenge/start)
-"bI" = (/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"bF" = (/obj/machinery/door/unpowered/shuttle,/turf/simulated/floor/plasteel{tag = "icon-delivery (SOUTHEAST)"; icon_state = "delivery"; dir = 6},/area/awaymission/challenge/start)
+"bG" = (/obj/machinery/door/poddoor{id_tag = "challenge"; name = "Gateway Shutters"},/turf/simulated/floor/plasteel{tag = "icon-delivery (SOUTHEAST)"; icon_state = "delivery"; dir = 6},/area/awaymission/challenge/start)
+"bH" = (/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"bI" = (/obj/machinery/door_control{id = "challenge"; name = "Gateway Lockdown"; pixel_x = -4; pixel_y = 26; req_access_txt = "0"},/turf/simulated/floor/plasteel{dir = 1; icon_state = "warning"},/area/awaymission/challenge/start)
"bJ" = (/obj/machinery/atmospherics/unary/vent_scrubber{on = 1},/turf/simulated/floor/plasteel{dir = 1; icon_state = "warning"},/area/awaymission/challenge/start)
-"bK" = (/obj/machinery/door_control{id = "challenge"; name = "Gateway Lockdown"; pixel_x = -4; pixel_y = 26; req_access_txt = "0"},/turf/simulated/floor/plasteel{dir = 1; icon_state = "warning"},/area/awaymission/challenge/start)
-"bL" = (/obj/effect/landmark{name = "awaystart"},/turf/simulated/floor/greengrid,/area/awaymission/challenge/start)
-"bM" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"bK" = (/obj/effect/landmark{name = "awaystart"},/turf/simulated/floor/greengrid,/area/awaymission/challenge/start)
+"bL" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"bM" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/item/paper/journal_scrap_1,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
"bN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"bO" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/item/paper/journal_scrap_1,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"bP" = (/obj/machinery/gateway{dir = 9},/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
+"bO" = (/obj/machinery/gateway{dir = 9},/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
+"bP" = (/obj/machinery/gateway{dir = 1},/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
"bQ" = (/obj/machinery/gateway{dir = 5},/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
"bR" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/main)
-"bS" = (/obj/machinery/gateway{dir = 1},/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
-"bT" = (/obj/machinery/atmospherics/unary/vent_pump{on = 1},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"bU" = (/obj/structure/dispenser/oxygen{oxygentanks = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"bV" = (/obj/machinery/gateway{dir = 8},/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
+"bS" = (/obj/machinery/atmospherics/unary/vent_pump{on = 1},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"bT" = (/obj/structure/dispenser/oxygen{oxygentanks = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"bU" = (/obj/machinery/gateway{dir = 8},/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
+"bV" = (/obj/machinery/gateway/centeraway,/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
"bW" = (/obj/machinery/gateway{dir = 4},/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
"bX" = (/obj/machinery/power/smes/magical,/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/plating,/area/awaymission/challenge/main)
"bY" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc/noalarm{dir = 4; name = "Worn-out APC"; pixel_x = 24; pixel_y = 0},/turf/simulated/floor/plating,/area/awaymission/challenge/main)
-"bZ" = (/obj/machinery/gateway/centeraway,/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
+"bZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
"ca" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"cb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"cc" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"cb" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"cc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
"cd" = (/obj/machinery/gateway{dir = 10},/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
-"ce" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"ce" = (/obj/machinery/gateway,/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
"cf" = (/obj/machinery/gateway{dir = 6},/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
"cg" = (/turf/simulated/floor/plating,/area/awaymission/challenge/main)
"ch" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/plating,/area/awaymission/challenge/main)
-"ci" = (/obj/machinery/gateway,/turf/simulated/floor/bluegrid,/area/awaymission/challenge/start)
-"cj" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/machinery/power/apc/noalarm{dir = 4; name = "Worn-out APC"; pixel_x = 24; pixel_y = 0},/turf/simulated/floor/plating,/area/awaymission/challenge/start)
-"ck" = (/obj/machinery/space_heater,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"cl" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"ci" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/machinery/power/apc/noalarm{dir = 4; name = "Worn-out APC"; pixel_x = 24; pixel_y = 0},/turf/simulated/floor/plating,/area/awaymission/challenge/start)
+"cj" = (/obj/machinery/space_heater,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"ck" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"cl" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
"cm" = (/obj/structure/table,/obj/item/clothing/accessory/scarf/christmas,/obj/item/clothing/accessory/scarf/christmas,/obj/item/clothing/accessory/scarf/christmas,/obj/item/clothing/accessory/scarf/christmas,/obj/item/clothing/accessory/scarf/christmas,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"cn" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"cn" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/table,/obj/item/clothing/head/helmet/space/santahat,/obj/item/clothing/head/helmet/space/santahat,/obj/item/clothing/head/helmet/space/santahat,/obj/item/clothing/head/helmet/space/santahat,/obj/item/clothing/head/helmet/space/santahat,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
"co" = (/obj/structure/table,/obj/item/clothing/suit/furcoat,/obj/item/clothing/suit/furcoat,/obj/item/clothing/suit/furcoat,/obj/item/clothing/suit/furcoat,/obj/item/clothing/suit/furcoat,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"cp" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/table,/obj/item/clothing/head/helmet/space/santahat,/obj/item/clothing/head/helmet/space/santahat,/obj/item/clothing/head/helmet/space/santahat,/obj/item/clothing/head/helmet/space/santahat,/obj/item/clothing/head/helmet/space/santahat,/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"cq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
-"cr" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
+"cp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plasteel,/area/awaymission/challenge/start)
+"cq" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
+"cr" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 6},/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
"cs" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal{dir = 4},/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
-"ct" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 6},/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
-"cu" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
-"cv" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; initialize_directions = 10},/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
+"ct" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
+"cu" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; initialize_directions = 10},/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/awaymission/challenge/start)
+"cv" = (/obj/machinery/atmospherics/unary/tank/air{dir = 1},/turf/simulated/floor/plating,/area/awaymission/challenge/start)
"cw" = (/turf/space,/area/space)
-"cx" = (/obj/machinery/atmospherics/unary/tank/air{dir = 1},/turf/simulated/floor/plating,/area/awaymission/challenge/start)
-"cy" = (/obj/machinery/atmospherics/unary/outlet_injector/on{dir = 1},/turf/simulated/floor/plating/airless,/area/awaymission/challenge/start)
+"cx" = (/obj/machinery/atmospherics/unary/outlet_injector/on{dir = 1},/turf/simulated/floor/plating/airless,/area/awaymission/challenge/start)
(1,1,1) = {"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
@@ -140,7 +139,7 @@ aaabababababacababafacacacacacacacacacacacacacacacacacacacacacacababacacacacacac
aaababababacacacacacacacacacacahacacacacacacacacacacacacacacacacacacacacacacacacacacacacacagagagaiajakagacacacacacacabababababaa
aaabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacalagamamajajajagacacacacacacacababababaa
aaabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacalagamamanajajagacacacacacacacacabababaa
-aaabababacacacaoacacacacacacacacacacacacacacacacacacacacapacacacacacacacacacacacacacacacacaSaramamasagagacacacacacacacacabababaa
+aaabababacacacaoacacacacacacacacacacacacacacacacacacacacapacacacacacacacacacacacacacacacacaqaramamasagagacacacacacacacacabababaa
aaabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacagagagamatauacacacacacacacacacabababaa
aaabababacacacacacacacacacacacacagagagagagagagavacacacacacacacacacacacacacacacacacacacacacacawagaxayauacacacacacacacacacabababaa
aaabababacadacacacacacacacacacacagazaAaBaCaDagacacacacacacacacafacacacacacacacacacacacacacacacagagagagacacacacacacacacacabababaa
@@ -148,7 +147,7 @@ aaabababacacacacacacacacacacacacagamamamamamagacacacacacacacacacacacacacaoacacab
aaabababacacacacacacacacacacacacauamamamamamauacacacacacacacacacacacacacacababababacacacacacacacacacacacacacacacacacacacabababaa
aaabababacacacacacacalacacacacacagamamamamaEagacacacacacacacacacacacacacacabababababababacacacacacacacacacacacacacacacacabababaa
aaabababacacacacacacacacacacacacagasamamamaFagacacacacacacacacacacacacacacacababababababacacacacacacacacacacacacacahacacabababaa
-aaabababacacacacacafacacacacacacagagagaSagagagacacacacacacacacacacacacacacacacabababacavacacacacacacacacacacacacacacacacabababaa
+aaabababacacacacacafacacacacacacagagagaqagagagacacacacacacacacacacacacacacacacabababacavacacacacacacacacacacacacacacacacabababaa
aaabababacacacacacacacacacacacacacaGacacacacalacacacacacacacacacaHacacacacacacacababababacacacacacacacacacacacacacacacacabababaa
aaabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababacacacacacacacacacacacacacacacacacabababaa
aaabababacacacacacacacacacacacacacacacacacacacacacacacaIacacacacacacacacadacacacabacacacacacacacacacacacacacacacacacacacabababaa
@@ -157,15 +156,15 @@ aaabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacac
aaabaJabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaKacacacacacacacacacacacacacacacacacacacacacacacababababaa
aaabaHaLacaLacabaKacacacacacacacacacacacaKacacacacacacacacacacacacacacaKacacacacacacacacacacacacacacacaHacacacacacacabababababaa
aaabababacabababababacacacacacaHacacacacaKacacacacacacacacaGacacacaGacacacacacacacacacacacacacacacacacacacacacacacacabacabababaa
-aaabaMaMaNaMaOababacacacacacacacacacacacacacacacacacacaPaQaRaqaqaqaTaQaUacacacacacacacacacacacacacacacacacacacacacacacacabababaa
+aaabaMaMaNaMaOababacacacacacacacacacacacacacacacacacacaPaQaRaSaSaSaTaQaUacacacacacacacacacacacacacacacacacacacacacacacacabababaa
aaabaMaVaVaVaWababacacacacacacacacacacacacacacacacacacaXaYaZaYaZaYaZaYaXacacacacacacacacacapacacacacacacacacacacacababababababaa
aaabaOaVbaaVaMababacacacacacacacacacacacacacacacacacaGbbaZaYaZaYaZaYaZbbaGacacacacacacacacacacacacacacacacacacacacacabababababaa
-aaabaWbcbdbeaOababababacacacacacacaIacacacacacacacacacaqaYaZaYaZaYaZaYaqacacacacacacacacacacacacacacacacacacacacacacabababababaa
-aaabaMaMaOaMaWabababacacacacacacacacacacacacacacacacacaqaZaYaZbfaZaYaZaqacacacacacacacacacacacacacacacacavacacacacacabababababaa
-aaababababababababacacacacacacacacacacacacacacacacacacaqaYaZaYaZaYaZaYaqacacacacacacacacacacacacacacacacacacacacacacabababababaa
+aaabaWbcbdbeaOababababacacacacacacaIacacacacacacacacacaSaYaZaYaZaYaZaYaSacacacacacacacacacacacacacacacacacacacacacacabababababaa
+aaabaMaMaOaMaWabababacacacacacacacacacacacacacacacacacaSaZaYaZbfaZaYaZaSacacacacacacacacacacacacacacacacavacacacacacabababababaa
+aaababababababababacacacacacacacacacacacacacacacacacacaSaYaZaYaZaYaZaYaSacacacacacacacacacacacacacacacacacacacacacacabababababaa
aaabababababababababacacacacacacacacacacacacacacacacaGbgaZaYaZaYaZaYaZbgaGacacacacacacacacacacacaIacacacacacacacacacacababababaa
aaabababacabababababacacacacacacacacacacacacacacacacacaXaYaZaYaZaYaZaYaXacacacacacacacacacacacacacacacacacacacacacacacacabababaa
-aaabababacacacacacacacacacacacacacacacacacacacacacacacbhaQaRaqaqaqaTaQbiacacacaKacacacacaoacacacacacacacacacacacacacacacabababaa
+aaabababacacacacacacacacacacacacacacacacacacacacacacacbhaQaRaSaSaSaTaQbiacacacaKacacacacaoacacacacacacacacacacacacacacacabababaa
aaabababacacacacacacacacacacacacacacacacacacacacaHacacacacaGacacacaGacacacacacacacacacacacacacacacacacacacacacacacacacacabababaa
aaabababacacacacacacacacacacacacaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababaa
aaabababacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababaa
@@ -180,18 +179,17 @@ aaabababacacacacacbkagagagagacacacacacacacacacacacacacacabacabababacacacacacacac
aaabababacacacacacagagbubvagagacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababaa
aaabababacacacacacagbwamambxagacacacacacacacacacacacacacacacaIacacacacacacacacafacacacacacacacacacacacacacacacacacacacacabababaa
aaabababacacacacacaubyamamamagbzacacacacacbjacacacacacacacacacbAacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababaa
-aaabababacacacacacauasamamamaSacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababaa
-aaabababacacacacacagbBbCambDagbzacacacacacacacacacacacacacacacacacacacacacacacacacacacacacapacacacacacacacacacacacacacacabababaa
-aaabababacacacacacagagagagagagacacacacacacacacacacacacacacbFbEbEbEbFbkacacacacacacacacacacacacacacacacacacacacacacaeacacabababaa
-aaabababacacacacacalacacacacacacacacacacacacacacacacacaeacbFbGbGbGbFbjaIacacacacacacacacacacacacacacacacacacacacacacacacabababaa
-aaabababacacacacacacacacacacacacacacacacacacacacbFbFbFbFbFbFbHbHbHbFbFbFbFbFbFacacacacacacacacacacacacacacacacacacacacacabababaa
-aaabababacaeacacacacacacacacacacacacacacacabacabbFbIbIbIbIbKbJbJbJbKbIbIbIbIbFababacacacacacacacacacacacacacacacacacacacabababaa
-aaababababacacacacacacadacacacacacacacacababababbFbIbLbLbLbIbMbObNbIbPbSbQbIbFabbjacababacacacacacacacadacacacacacacacacabababaa
-aaabababababacacacacacacacacacacacacacababbRbRbRbFbIbLbLbLbIbTbUbTbIbVbZbWbIbFbRbRbRababacacacacacacacacacacacacacacacababababaa
-aaabababababacabacacacacacacacacacacacababbRbXbYbFbIbLbLbLcbcacccacecdcicfbIbFcgcgbRabababacacacacacacacacacacacacacabababababaa
-aaababababababababababababababababababababbRchcjbFckcbclclcncmcpcocqclclcebIbFcgcgbRabababababababababababababababababababababaa
-aaababababababababababababababababababababbRcgcgbFbFcrbFbFctcscucscvbFbFcrbFbFcgcgbRabababababababababababababababababababababaa
-aaababababababababababababababababababababbRcgcgcgbFcxbFcwcycwcwcwcycwbFcxbFcgcgcgbRabababababababababababababababababababababaa
+aaabababacacacacacauasamamamaqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacabababaa
+aaabababacacacacacagbBamambCagbzacacacacacacacacacacacacacacacacacacacacacacacacacacacacacapacacacacacacacacacacacacacacabababaa
+aaabababacacacacacagagagagagagacacacacacacacacacacacacacacbDbEbEbEbDbkacacacacacacacacacacacacacacacacacacacacacacaeacacabababaa
+aaabababacacacacacalacacacacacacacacacacacacacacacacacaeacbDbFbFbFbDbjaIacacacacacacacacacacacacacacacacacacacacacacacacabababaa
+aaabababacacacacacacacacacacacacacacacacacacacacbDbDbDbDbDbDbGbGbGbDbDbDbDbDbDacacacacacacacacacacacacacacacacacacacacacabababaa
+aaabababacaeacacacacacacacacacacacacacacacabacabbDbHbHbHbHbIbJbJbJbIbHbHbHbHbDababacacacacacacacacacacacacacacacacacacacabababaa
+aaababababacacacacacacadacacacacacacacacababababbDbHbKbKbKbHbLbMbNbHbObPbQbHbDabbjacababacacacacacacacadacacacacacacacacabababaa
+aaabababababacacacacacacacacacacacacacababbRbRbRbDbHbKbKbKbHbSbTbSbHbUbVbWbHbDbRbRbRababacacacacacacacacacacacacacacacababababaa
+aaabababababacabacacacacacacacacacacacababbRbXbYbDbHbKbKbKbZcacbcacccdcecfbHbDcgcgbRabababacacacacacacacacacacacacacabababababaa
+aaababababababababababababababababababababbRchcibDcjbZckckclcmcncocpckckccbHbDcgcgbRabababababababababababababababababababababaa
+aaababababababababababababababababababababbRcgcgbDbDcqbDbDcrcsctcscubDbDcqbDbDcgcgbRabababababababababababababababababababababaa
+aaababababababababababababababababababababbRcgcgcgbDcvbDcwcxcwcwcwcxcwbDcvbDcgcgcgbRabababababababababababababababababababababaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
"}
-
diff --git a/_maps/map_files/RandomZLevels/spacehotel.dmm b/_maps/map_files/RandomZLevels/spacehotel.dmm
index 9a66c57d6ba..f40c2033dfd 100644
--- a/_maps/map_files/RandomZLevels/spacehotel.dmm
+++ b/_maps/map_files/RandomZLevels/spacehotel.dmm
@@ -409,7 +409,7 @@
"hS" = (/turf/unsimulated/floor{icon_state = "whiteyellow"; dir = 4},/area/awaymission/spacehotel)
"hT" = (/obj/effect/view_portal{id = "hotel_12"},/turf/unsimulated/floor{icon_state = "rampbottom"; dir = 4},/area/awaymission/spacehotel)
"hU" = (/obj/effect/view_portal/visual{dir = 4; dist = 0; id = "hotel_22"; opacity = 0; radius = 0},/turf/unsimulated/floor,/area/awaymission/spacehotel)
-"hV" = (/obj/machinery/door/airlock/public/glass{icon_state = "door_locked"; locked = 1; name = "Employees Only"; req_access_txt = "150"},/obj/item/tape/police{icon_state = "police_door"; layer = 3.2},/turf/unsimulated/floor{dir = 8; icon_state = "whitered"},/area/awaymission/spacehotel)
+"hV" = (/obj/machinery/door/airlock/public/glass{icon_state = "door_locked"; locked = 1; name = "Employees Only"; req_access_txt = "150"},/turf/unsimulated/floor{dir = 8; icon_state = "whitered"},/area/awaymission/spacehotel)
"hW" = (/obj/effect/decal/cleanable/blood/old,/turf/unsimulated/floor{icon_state = "white"},/area/awaymission/spacehotel)
"hX" = (/obj/effect/view_portal/visual{dir = 8; dist = 0; id = "hotel_13"; radius = 0},/turf/unsimulated/floor,/area/awaymission/spacehotel)
"hY" = (/obj/effect/view_portal{id = "hotel_23"},/turf/unsimulated/floor{icon_state = "ramptop"; dir = 4},/area/awaymission/spacehotel)
@@ -485,7 +485,7 @@
"jq" = (/obj/item/toy/spinningtoy,/turf/unsimulated/floor/carpet,/area/awaymission/spacehotel)
"jr" = (/obj/item/grown/bananapeel,/obj/item/toy/spinningtoy,/turf/unsimulated/floor/carpet,/area/awaymission/spacehotel)
"js" = (/obj/structure/barricade/wooden,/turf/unsimulated/floor/carpet,/area/awaymission/spacehotel)
-"jt" = (/obj/machinery/door/airlock/public/glass,/obj/item/tape/engineering{icon_state = "engineering_door"; layer = 3.2},/turf/unsimulated/floor/carpet,/area/awaymission/spacehotel)
+"jt" = (/obj/machinery/door/airlock/public/glass,/turf/unsimulated/floor/carpet,/area/awaymission/spacehotel)
"ju" = (/obj/machinery/gateway{dir = 10},/turf/unsimulated/floor{icon_state = "warning"; dir = 10},/area/awaymission/spacehotel)
"jv" = (/obj/machinery/gateway,/turf/unsimulated/floor{icon_state = "warning"},/area/awaymission/spacehotel)
"jw" = (/obj/machinery/gateway{dir = 6},/turf/unsimulated/floor{icon_state = "warning"; dir = 6},/area/awaymission/spacehotel)
diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm
index 998ae80eada..e9974435ba9 100644
--- a/_maps/map_files/cyberiad/cyberiad.dmm
+++ b/_maps/map_files/cyberiad/cyberiad.dmm
@@ -5221,7 +5221,7 @@
"bWu" = (/obj/effect/spawner/window/reinforced,/obj/structure/sign/examroom,/turf/simulated/floor/plating,/area/medical/sleeper)
"bWv" = (/turf/simulated/wall/r_wall,/area/crew_quarters/fitness{name = "\improper Arcade"})
"bWw" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
-"bWx" = (/obj/machinery/door/firedoor,/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
+"bWx" = (/obj/machinery/door/firedoor,/turf/simulated/floor/plasteel{tag = "icon-whiteblue (WEST)"; icon_state = "whiteblue"; dir = 8},/area/medical/sleeper)
"bWy" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/medical/cryo)
"bWz" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitebluecorner"; tag = "icon-whitebluecorner"},/area/medical/medbay2)
"bWA" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/medbay2)
@@ -5282,8 +5282,8 @@
"bXD" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/medical/sleeper)
"bXE" = (/obj/item/roller,/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTH)"; icon_state = "whiteblue"; dir = 1},/area/medical/sleeper)
"bXF" = (/obj/machinery/light_switch{pixel_x = -23; pixel_y = 0},/obj/machinery/sleeper{dir = 4},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTHWEST)"; icon_state = "whiteblue"; dir = 9},/area/medical/sleeper)
-"bXG" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/sleeper)
-"bXH" = (/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/sleeper)
+"bXG" = (/obj/machinery/door/firedoor,/turf/simulated/floor/plasteel{dir = 4; icon_state = "whiteblue"; tag = "icon-whitehall (WEST)"},/area/medical/sleeper)
+"bXH" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
"bXI" = (/obj/machinery/vending/medical,/turf/simulated/floor/plasteel{dir = 5; icon_state = "whiteblue"; tag = "icon-whitehall (WEST)"},/area/medical/sleeper)
"bXJ" = (/obj/structure/table,/obj/item/reagent_containers/syringe/antiviral,/obj/item/reagent_containers/syringe/charcoal,/obj/item/reagent_containers/syringe/insulin,/obj/item/reagent_containers/glass/bottle/morphine,/obj/item/reagent_containers/glass/bottle/epinephrine,/obj/item/reagent_containers/syringe,/obj/item/stack/medical/bruise_pack/advanced{pixel_x = 6; pixel_y = 6},/obj/item/stack/medical/ointment/advanced{pixel_x = 6; pixel_y = 8},/obj/item/reagent_containers/food/pill/patch/styptic{pixel_y = 6},/obj/item/reagent_containers/food/pill/patch/styptic{pixel_x = 2; pixel_y = 8},/obj/item/reagent_containers/food/pill/patch/silver_sulf{pixel_x = -8; pixel_y = 6},/obj/item/reagent_containers/food/pill/patch/silver_sulf{pixel_x = -8; pixel_y = 8},/obj/item/storage/pill_bottle/painkillers{pixel_x = -6; pixel_y = -3},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTH)"; icon_state = "whiteblue"; dir = 1},/area/medical/sleeper)
"bXK" = (/obj/item/twohanded/required/kirbyplants,/obj/machinery/firealarm{dir = 8; pixel_x = -24},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/medical/cryo)
@@ -5361,13 +5361,13 @@
"bZe" = (/obj/machinery/camera{c_tag = "Gravity Generator Foyer"; dir = 1; network = list("SS13")},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/obj/structure/closet/radiation,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light,/turf/simulated/floor/plasteel,/area/engine/gravitygenerator)
"bZf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/sortjunction{dir = 8; icon_state = "pipe-j2s"; name = "Genetics"; sortType = 23},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/medical/genetics_cloning)
"bZg" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/status_display{density = 0; layer = 4; pixel_x = -32; pixel_y = 0},/turf/simulated/floor/plasteel,/area/hallway/primary/central/se)
-"bZh" = (/obj/structure/table,/obj/item/roller,/obj/machinery/firealarm{dir = 8; pixel_x = -24},/obj/item/soap/nanotrasen,/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTHWEST)"; icon_state = "whiteblue"; dir = 9},/area/medical/sleeper)
-"bZi" = (/obj/structure/closet/crate/freezer,/obj/item/reagent_containers/blood/empty,/obj/item/reagent_containers/blood/empty,/obj/item/reagent_containers/blood/AMinus,/obj/item/reagent_containers/blood/APlus,/obj/item/reagent_containers/blood/BMinus,/obj/item/reagent_containers/blood/BPlus,/obj/item/reagent_containers/blood/OMinus,/obj/item/reagent_containers/blood/OPlus,/obj/item/reagent_containers/blood/random,/obj/item/reagent_containers/blood/random,/obj/item/reagent_containers/blood/random,/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTHEAST)"; icon_state = "whiteblue"; dir = 5},/area/medical/sleeper)
-"bZj" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (WEST)"; icon_state = "whiteblue"; dir = 8},/area/medical/sleeper)
-"bZk" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4; initialize_directions = 11; level = 1},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/hologram/holopad,/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/sleeper)
-"bZl" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 4; on = 1},/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/sleeper)
+"bZh" = (/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitebluecorner"; tag = "icon-whitebluecorner"},/area/medical/sleeper)
+"bZi" = (/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitebluecorner"; tag = "icon-whitebluecorner"},/area/medical/sleeper)
+"bZj" = (/obj/structure/sink{dir = 8; icon_state = "sink"; pixel_x = -12; pixel_y = 0},/obj/machinery/firealarm{dir = 8; pixel_x = -24},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTHWEST)"; icon_state = "whiteblue"; dir = 9},/area/medical/sleeper)
+"bZk" = (/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
+"bZl" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4; initialize_directions = 11; level = 1},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/hologram/holopad,/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
"bZm" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whiteblue"; tag = "icon-whitehall (WEST)"},/area/medical/sleeper)
-"bZn" = (/obj/machinery/atmospherics/unary/vent_scrubber{on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/structure/disposalpipe/junction{dir = 8; icon_state = "pipe-j2"; tag = "icon-pipe-j1 (WEST)"},/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/sleeper)
+"bZn" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 4; on = 1},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
"bZo" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/medical/cryo)
"bZp" = (/obj/machinery/door/firedoor,/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/medical/cryo)
"bZq" = (/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 1},/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/medical/cryo)
@@ -5433,14 +5433,14 @@
"cay" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/obj/structure/table,/turf/simulated/floor/plasteel,/area/engine/break_room)
"caz" = (/obj/structure/sign/poster/random{pixel_x = -32; pixel_y = 0},/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (WEST)"; icon_state = "whiteblue"; dir = 8},/area/medical/sleeper)
"caA" = (/turf/simulated/wall,/area/medical/sleeper)
-"caB" = (/obj/machinery/door/window/eastright{base_state = "left"; dir = 4; icon_state = "left"; name = "Blood Transfusion Ward"; req_access_txt = "5"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
+"caB" = (/obj/machinery/atmospherics/unary/vent_scrubber{on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/structure/disposalpipe/junction{dir = 8; icon_state = "pipe-j2"; tag = "icon-pipe-j1 (WEST)"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
"caC" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/unary/vent_pump{dir = 4; on = 1},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
-"caD" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/sleeper)
+"caD" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
"caE" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
-"caF" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = "90Curve"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/sleeper)
-"caG" = (/obj/effect/landmark/start{name = "Medical Doctor"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/sleeper)
+"caF" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = "90Curve"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
+"caG" = (/obj/effect/landmark/start{name = "Medical Doctor"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
"caH" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whiteblue"; tag = "icon-whitehall (WEST)"},/area/medical/sleeper)
-"caI" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/sleeper)
+"caI" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/sleeper)
"caJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/medical/cryo)
"caK" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/extinguisher_cabinet{pixel_x = 0; pixel_y = -30},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/medical/cryo)
"caL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/atmospherics/pipe/manifold4w/hidden,/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/medical/cryo)
@@ -5480,7 +5480,7 @@
"cbt" = (/obj/machinery/navbeacon{codes_txt = "delivery"; dir = 4; location = "Medbay"},/obj/structure/plasticflaps{opacity = 1},/turf/simulated/floor/plating,/area/medical/sleeper)
"cbu" = (/obj/structure/lamarr,/turf/simulated/floor/plasteel{dir = 4; icon_state = "warnwhite"; tag = "icon-warnwhite (NORTH)"},/area/crew_quarters/hor)
"cbv" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/maintenance/asmaint)
-"cbw" = (/obj/machinery/iv_drip,/turf/simulated/floor/plasteel{tag = "icon-whiteblue"; icon_state = "whiteblue"},/area/medical/sleeper)
+"cbw" = (/obj/structure/table,/obj/item/roller,/obj/item/soap/nanotrasen,/turf/simulated/floor/plasteel{dir = 10; icon_state = "whiteblue"; tag = "icon-whitehall (WEST)"},/area/medical/sleeper)
"cbx" = (/obj/structure/stool/bed/chair/comfy/black{dir = 4},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/administration)
"cby" = (/obj/machinery/computer/shuttle/admin,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/administration)
"cbz" = (/obj/machinery/door/airlock/centcom{id_tag = "adminshuttle"; name = "Bridge"; opacity = 1; req_access_txt = "106"},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/administration)
@@ -5510,7 +5510,7 @@
"cbX" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{level = 1},/obj/structure/disposalpipe/junction{tag = "icon-pipe-j1 (EAST)"; icon_state = "pipe-j1"; dir = 4},/turf/simulated/floor/plasteel{dir = 1; icon_state = "blue"},/area/hallway/primary/central/south)
"cbY" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{dir = 1; icon_state = "blue"},/area/hallway/primary/central/south)
"cbZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{req_access_txt = "0"},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel,/area/hallway/primary/central/south)
-"cca" = (/obj/structure/closet/crate/freezer,/obj/item/reagent_containers/blood/empty,/obj/item/reagent_containers/blood/empty,/obj/item/reagent_containers/blood/AMinus,/obj/item/reagent_containers/blood/APlus,/obj/item/reagent_containers/blood/BMinus,/obj/item/reagent_containers/blood/BPlus,/obj/item/reagent_containers/blood/OMinus,/obj/item/reagent_containers/blood/OPlus,/obj/item/reagent_containers/blood/random,/obj/item/reagent_containers/blood/random,/obj/item/reagent_containers/blood/random,/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (SOUTHEAST)"; icon_state = "whiteblue"; dir = 6},/area/medical/sleeper)
+"cca" = (/obj/structure/closet/crate/freezer,/obj/item/reagent_containers/blood/empty,/obj/item/reagent_containers/blood/empty,/obj/item/reagent_containers/blood/AMinus,/obj/item/reagent_containers/blood/APlus,/obj/item/reagent_containers/blood/BMinus,/obj/item/reagent_containers/blood/BPlus,/obj/item/reagent_containers/blood/OMinus,/obj/item/reagent_containers/blood/OPlus,/obj/item/reagent_containers/blood/random,/obj/item/reagent_containers/blood/random,/obj/item/reagent_containers/blood/random,/obj/machinery/iv_drip,/turf/simulated/floor/plasteel{tag = "icon-whiteblue"; icon_state = "whiteblue"},/area/medical/sleeper)
"ccb" = (/obj/machinery/ai_status_display{pixel_y = 32},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel,/area/hallway/primary/central/south)
"ccc" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{level = 1},/obj/item/radio/intercom{broadcasting = 0; name = "station intercom (General)"; pixel_y = 25},/turf/simulated/floor/plasteel,/area/hallway/primary/central/south)
"ccd" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/decal/warning_stripes/north,/turf/simulated/floor/plasteel,/area/hallway/primary/central/south)
@@ -5520,15 +5520,15 @@
"cch" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1; initialize_directions = 11; level = 1},/turf/simulated/floor/plasteel,/area/hallway/primary/central/south)
"cci" = (/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel,/area/hallway/primary/central/south)
"ccj" = (/obj/machinery/camera{c_tag = "Central Primary Hallway South"; dir = 2; network = list("SS13")},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel,/area/hallway/primary/central/south)
-"cck" = (/obj/machinery/iv_drip,/obj/machinery/ai_status_display{pixel_y = -32},/turf/simulated/floor/plasteel{tag = "icon-whiteblue"; icon_state = "whiteblue"},/area/medical/sleeper)
+"cck" = (/obj/structure/closet/crate/freezer,/obj/item/reagent_containers/blood/empty,/obj/item/reagent_containers/blood/empty,/obj/item/reagent_containers/blood/AMinus,/obj/item/reagent_containers/blood/APlus,/obj/item/reagent_containers/blood/BMinus,/obj/item/reagent_containers/blood/BPlus,/obj/item/reagent_containers/blood/OMinus,/obj/item/reagent_containers/blood/OPlus,/obj/item/reagent_containers/blood/random,/obj/item/reagent_containers/blood/random,/obj/item/reagent_containers/blood/random,/obj/machinery/iv_drip,/obj/machinery/ai_status_display{pixel_y = -32},/turf/simulated/floor/plasteel{tag = "icon-whiteblue"; icon_state = "whiteblue"},/area/medical/sleeper)
"ccl" = (/obj/machinery/door/firedoor,/turf/simulated/floor/plasteel,/area/hallway/primary/central/south)
"ccm" = (/obj/machinery/door/airlock/public/glass{name = "Central Access"},/turf/simulated/floor/plasteel,/area/hallway/primary/central/se)
"ccn" = (/obj/machinery/atm{pixel_y = 32},/turf/simulated/floor/plasteel,/area/hallway/primary/central/se)
"cco" = (/obj/machinery/newscaster{pixel_y = 32},/turf/simulated/floor/plasteel,/area/hallway/primary/central/se)
"ccp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/plasteel,/area/hallway/primary/central/se)
-"ccq" = (/obj/machinery/camera{c_tag = "Medbay Treatment Center"; dir = 1; network = list("SS13"); pixel_x = 0},/obj/machinery/light,/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable,/turf/simulated/floor/plasteel{tag = "icon-whiteblue"; icon_state = "whiteblue"},/area/medical/sleeper)
+"ccq" = (/obj/machinery/camera{c_tag = "Medbay Treatment Center"; dir = 1; network = list("SS13"); pixel_x = 0},/obj/machinery/light,/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable,/obj/item/roller,/turf/simulated/floor/plasteel{tag = "icon-whiteblue"; icon_state = "whiteblue"},/area/medical/sleeper)
"ccr" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/plasteel,/area/hallway/primary/central/se)
-"ccs" = (/obj/machinery/sleeper{dir = 4},/obj/item/radio/intercom{name = "station intercom (General)"; pixel_y = -28},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (SOUTHWEST)"; icon_state = "whiteblue"; dir = 10},/area/medical/sleeper)
+"ccs" = (/obj/machinery/sleeper{dir = 4},/obj/item/radio/intercom{name = "station intercom (General)"; pixel_y = -28},/turf/simulated/floor/plasteel{tag = "icon-whiteblue"; icon_state = "whiteblue"},/area/medical/sleeper)
"cct" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{tag = "icon-whiteblue"; icon_state = "whiteblue"},/area/medical/sleeper)
"ccu" = (/turf/simulated/floor/plasteel{tag = "icon-whiteblue"; icon_state = "whiteblue"},/area/medical/sleeper)
"ccv" = (/obj/machinery/light{dir = 4},/obj/machinery/alarm{dir = 1; pixel_y = -22},/obj/machinery/body_scanconsole,/turf/simulated/floor/plasteel{dir = 6; icon_state = "whiteblue"; tag = "icon-whitehall (WEST)"},/area/medical/sleeper)
@@ -5978,8 +5978,8 @@
"ckX" = (/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTH)"; icon_state = "whiteblue"; dir = 1},/area/medical/surgery1)
"ckY" = (/obj/machinery/firealarm{dir = 8; pixel_x = -24},/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/obj/structure/cable,/turf/simulated/floor/plasteel{dir = 10; icon_state = "darkblue"},/area/medical/ward)
"ckZ" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4; initialize_directions = 11; level = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11; level = 1},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/medical/ward)
-"cla" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 4; on = 1},/obj/machinery/alarm{dir = 1; pixel_y = -22},/turf/simulated/floor/plasteel{dir = 2; icon_state = "darkblue"},/area/medical/ward)
-"clb" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1},/obj/machinery/light_switch{pixel_x = 27},/turf/simulated/floor/plasteel{dir = 6; icon_state = "darkblue"},/area/medical/ward)
+"cla" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 4; on = 1},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/medical/ward)
+"clb" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1},/obj/machinery/light_switch{pixel_x = 27},/obj/machinery/alarm{dir = 1; pixel_y = -22},/turf/simulated/floor/plasteel{dir = 6; icon_state = "darkblue"},/area/medical/ward)
"clc" = (/obj/machinery/bodyscanner,/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTH)"; icon_state = "whiteblue"; dir = 1},/area/medical/surgery2)
"cld" = (/obj/structure/closet/secure_closet/medical2,/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitebluecorner"; tag = "icon-whitebluecorner"},/area/medical/surgery2)
"cle" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/obj/machinery/light_switch{pixel_x = 23; pixel_y = -5},/obj/machinery/holosign_switch{id = "surgery2"; pixel_x = 23; pixel_y = 4},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTH)"; icon_state = "whiteblue"; dir = 1},/area/medical/surgery2)
@@ -6042,7 +6042,7 @@
"cmj" = (/obj/machinery/computer/security/telescreen{desc = "Used for watching the singularity chamber."; dir = 8; layer = 4; name = "Singularity Engine Telescreen"; network = list("Singularity"); pixel_x = 0; pixel_y = 30},/obj/structure/stool/bed/chair/office/dark{dir = 4},/turf/simulated/floor/plasteel,/area/engine/controlroom)
"cmk" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/maintenance/asmaint)
"cml" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/medical{name = "Operating Theatre Storage"; req_access_txt = "45"},/turf/simulated/floor/plasteel{icon_state = "showroomfloor"},/area/medical/surgery1)
-"cmm" = (/obj/machinery/door/firedoor,/obj/structure/disposalpipe/segment,/obj/machinery/door/airlock/medical/glass{id_tag = ""; name = "Medbay Virology Lobby"; req_access_txt = "5"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/virology/lab{name = "\improper Virology Lobby"})
+"cmm" = (/obj/machinery/door/firedoor,/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/airlock/medical/glass{id_tag = null; name = "Virology Lobby Hallway"; req_access_txt = "0"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/medical/virology/lab{name = "\improper Virology Lobby"})
"cmn" = (/obj/machinery/vending/coffee,/turf/simulated/floor/plasteel{tag = "icon-whitegreen (NORTHWEST)"; icon_state = "whitegreen"; dir = 9},/area/medical/virology/lab{name = "\improper Virology Lobby"})
"cmo" = (/obj/structure/sign/biohazard,/turf/simulated/wall,/area/medical/virology/lab{name = "\improper Virology Lobby"})
"cmp" = (/obj/machinery/vending/medical,/turf/simulated/floor/plasteel{tag = "icon-whitegreen (NORTHEAST)"; icon_state = "whitegreen"; dir = 5},/area/medical/virology/lab{name = "\improper Virology Lobby"})
@@ -6104,8 +6104,8 @@
"cnt" = (/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/maintenance/apmaint)
"cnu" = (/obj/structure/stool/bed/chair/office/dark,/turf/simulated/floor/carpet,/area/ntrep)
"cnv" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/wood,/area/blueshield)
-"cnw" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/virology/lab{name = "\improper Virology Lobby"})
-"cnx" = (/turf/simulated/floor/plasteel{tag = "icon-whitegreen (NORTHWEST)"; icon_state = "whitegreen"; dir = 9},/area/medical/virology/lab{name = "\improper Virology Lobby"})
+"cnw" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/medical/glass{id_tag = null; name = "Virology Lobby Hallway"; req_access_txt = "0"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/medical/ward)
+"cnx" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitegreencorner"},/area/medical/virology/lab{name = "\improper Virology Lobby"})
"cny" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel,/area/hallway/primary/aft)
"cnz" = (/obj/structure/sign/biohazard{pixel_y = 32},/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitegreen"; tag = "icon-whitegreen (WEST)"},/area/medical/virology/lab{name = "\improper Virology Lobby"})
"cnA" = (/turf/simulated/floor/plasteel{dir = 2; icon_state = "yellowcorner"},/area/hallway/primary/aft)
@@ -6374,15 +6374,15 @@
"csD" = (/turf/simulated/wall,/area/engine/controlroom)
"csE" = (/obj/machinery/camera{c_tag = "NT Representative's Office"; dir = 1; network = list("SS13")},/obj/structure/table/wood,/obj/machinery/photocopier/faxmachine/longrange{department = "NT Representative's Office"},/obj/machinery/newscaster/security_unit{pixel_x = 0; pixel_y = -32},/turf/simulated/floor/wood,/area/ntrep)
"csF" = (/obj/item/flashlight,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/maintenance/genetics)
-"csG" = (/obj/structure/closet/firecloset,/obj/item/taperoll/engineering,/turf/simulated/floor/plasteel,/area/engine/controlroom)
+"csG" = (/obj/machinery/firealarm{dir = 8; pixel_x = -24},/obj/structure/closet/firecloset,/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/turf/simulated/floor/plasteel,/area/engine/controlroom)
"csH" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel,/area/hallway/primary/aft)
"csI" = (/obj/structure/disposalpipe/segment,/obj/item/radio/intercom{dir = 8; name = "station intercom (General)"; pixel_x = -28},/obj/machinery/camera{c_tag = "Aft Primary Hallway 1"; dir = 4; network = list("SS13")},/turf/simulated/floor/plasteel{dir = 8; icon_state = "cautioncorner"},/area/hallway/primary/aft)
"csJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/wall,/area/engine/controlroom)
"csK" = (/obj/structure/table,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/asmaint)
"csL" = (/turf/simulated/floor/plating,/area/maintenance/asmaint)
"csM" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/maintenance/genetics)
-"csN" = (/obj/machinery/firealarm{dir = 8; pixel_x = -24},/obj/structure/closet/firecloset,/obj/item/taperoll/engineering,/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/turf/simulated/floor/plasteel,/area/engine/controlroom)
-"csO" = (/obj/structure/extinguisher_cabinet{pixel_x = 0; pixel_y = 30},/obj/structure/closet/firecloset,/obj/item/taperoll/engineering,/turf/simulated/floor/plasteel,/area/engine/controlroom)
+"csN" = (/obj/structure/closet/firecloset,/turf/simulated/floor/plasteel,/area/engine/controlroom)
+"csO" = (/obj/structure/extinguisher_cabinet{pixel_x = 0; pixel_y = 30},/obj/structure/closet/firecloset,/turf/simulated/floor/plasteel,/area/engine/controlroom)
"csP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/wall/r_wall,/area/maintenance/genetics)
"csQ" = (/obj/structure/cable,/obj/machinery/computer/monitor{name = "Grid Power Monitoring Computer"},/turf/simulated/floor/plasteel{icon_state = "caution"; dir = 5},/area/engine/controlroom)
"csR" = (/obj/structure/rack{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/effect/spawner/lootdrop/maintenance{lootcount = 2; name = "2maintenance loot spawner"},/turf/simulated/floor/plating,/area/maintenance/genetics)
@@ -6505,7 +6505,7 @@
"cve" = (/obj/item/assembly/timer,/obj/item/assembly/timer{pixel_x = 6},/obj/item/assembly/timer{pixel_x = -5; pixel_y = 6},/obj/structure/table,/obj/item/assembly/timer{pixel_x = -3; pixel_y = -4},/obj/item/assembly/timer{pixel_x = 8; pixel_y = 8},/obj/item/assembly/timer,/obj/machinery/light_switch{pixel_y = -23},/obj/machinery/light,/obj/machinery/requests_console{department = "Science"; departmentType = 2; name = "Science Requests Console"; pixel_x = 0; pixel_y = -30},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/mixing)
"cvf" = (/obj/machinery/atmospherics/trinary/mixer{density = 0; dir = 8; req_access = null},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/mixing)
"cvg" = (/obj/machinery/atmospherics/unary/portables_connector{dir = 4},/obj/item/radio/intercom{name = "station intercom (General)"; pixel_y = -28},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/mixing)
-"cvh" = (/obj/item/radio/beacon,/obj/effect/decal/warning_stripes/red/hollow,/turf/simulated/floor/plasteel/airless,/area/toxins/test_area)
+"cvh" = (/obj/item/radio/beacon,/obj/effect/decal/warning_stripes/red/hollow,/turf/simulated/floor/plasteel/airless/indestructible,/area/toxins/test_area)
"cvi" = (/obj/machinery/atmospherics/binary/valve{dir = 4},/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/mixing)
"cvj" = (/obj/machinery/mass_driver{dir = 4; id_tag = "toxinsdriver"},/turf/simulated/floor/plating,/area/toxins/launch{name = "Toxins Launch Room"})
"cvk" = (/obj/structure/closet/crate,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/apmaint)
@@ -7170,6 +7170,7 @@
"cHT" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/turf/simulated/floor/plasteel,/area/engine/break_room)
"cHU" = (/obj/structure/sign/securearea,/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/yellow{tag = "icon-intact (NORTHWEST)"; icon_state = "intact"; dir = 9},/turf/simulated/wall,/area/engine/break_room)
"cHV" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{level = 1},/turf/simulated/wall/r_wall,/area/atmos/control)
+"cHW" = (/turf/simulated/floor/plasteel{tag = "icon-whitegreen (WEST)"; icon_state = "whitegreen"; dir = 8},/area/medical/virology/lab{name = "\improper Virology Lobby"})
"cHY" = (/obj/machinery/computer/general_air_control{frequency = 1441; name = "Tank Monitor"; sensors = list("n2_sensor" = "Nitrogen", "o2_sensor" = "Oxygen", "co2_sensor" = "Carbon Dioxide", "tox_sensor" = "Toxins", "n2o_sensor" = "Nitrous Oxide", "waste_sensor" = "Gas Mix Tank")},/obj/machinery/alarm{frequency = 1439; pixel_y = 23},/turf/simulated/floor/plasteel,/area/atmos/control)
"cHZ" = (/obj/machinery/kitchen_machine/grill,/turf/simulated/floor/plating,/area/maintenance/asmaint)
"cIa" = (/obj/machinery/cooker/deepfryer,/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint)
@@ -8972,10 +8973,10 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabPLbPIbVebVfbVgbVhbVibRGbVkbRAbVlbRAbRAbRAbRAbRAbTlbRGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabOebVmbOcbOcbOcbVnbOebPTbKBbKBbVobKzbPPbKzbKzbKzbKzbKzbJfbKAbTsbVpbxbbVrbBnbVqbVsbBnbVwbzEbBnbBnbVtbDXbOwbTybTzbRVbRWbMGbVubVvbVybVxbVzbMHbVBbVAbVDbVCbHsbVEbVFbHsbHtbHtbVGbSibVIbVHbVKbVJbVLbVLbVNbVMbVObFObSMbSLbSObSNbSPcrAcrAcrAcrAcrAbSRbSQbSUbSSbSVbXAbSXbRtbXAbThbXAbJRcuobJSbTZbTYbUabUabUcbUbbWgbUdbUfbUdbWibWibWjbWjbWjbWjbIabIabIabIabIabWlbWnbLIbIabNVbNZbNXbWqbWqbPibOabLRctvbPkbPjcacbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabWObWGbRAbRAbWHbWHbWHbRGbRAbRAbRGbWIbWJbWKbRAbWMbWNbRGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabOebOcbOcbOcbOcbOcbWPbTrbTqbTrbPUbWQbWRbKzbKzbKzbWQbKzbJfbKAbTsbWSbxbbWWbBnbzFbQdbBnbzJbLJbBnbBnbWUbDXbOwbTybWVbRVbWXbMGbXbbWYbWZbXabXdbMHbXcbXebXgbXfbXibXhbXjbFCaaaaaaaaabSibXpbXkbXlbXlbXmbXnbXobSibXrbXqbUhbUgbUjbUibUrbUkbUnbUmbUmbUmbUpbUobUmbUmbUqbUmbUmbUsbUnbUmbUmbUGbNubNtbUwbUvbUBbUybZfbUDbXNbUIbUIbUIbUJbWgbLRbUPbWqbWqbXYbXXbWqbXZbYbbYabYdbYcbWqbPlbYgbYfbYibYhbYlbYjbYjbYjbYjbYjcacbGjbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYubWGbRAbRAbRAbRAbRAbYtbRAbRAbRGbPIbPIbPIbPIbPIbPIbYvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabOebOcbOcbOcbOcbOcbYxbYwbYybYwbYAbYzbYBbYBbYBbYBbYBbYCbYEbYDbTsbYFbxbbYGbYIbYHbYNbYJbYKbYLbYLbYLbYMbYMbYObTybYRbYQbRWbMGbYTbYSbYVbVvbYWbMHbYUbYXbZdbTJbZebQmbYYbFCaaaaaaaaabSibYZbZabZbbZcbXmbXnbXobSibZgbZJbURbUQbUTbUScyTcyTbUVbUUbUXbUWcyTbUYbUZbUZbVabUZbUZbUSbUVbUZbVcbVbbVdcyTbVPbVjbVRbVQbVTbVSbVVbVUbVXbVWbVZbVYbWcbWbbWcbWcbWebUNbZMbUNbZNbUNbZPbZObZObPCbPDbZRbZUbZTbZXbZVbGkbZWaYpbYjcacbGGbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaebPIcafcagcahcaibRAbRGbRAbRAbRGbRAcancakcaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabOebOcbOcbOcbOcbOcbOebPTbKBbKBbxbbxbbKBbKBbKBbKBbKBbxbbxbbKBbKBbKBbxbcamcamcamcascambYMcaocapcaqcatbYMbOwbTycawbMEbMEbMGbMGbMGbMGbMGbMNbMHbTJbTIcaubTJcavcaxbFCbFCbFCbFCbFCbSibSjbSibSibSibSibSibSibSibNvbFObWfbSLbWkbWhbWobWmbWscaAbWubWtbWxbWwbWtbWubWabWybWabWybWabWybWabWzbWAcrAbTZbWBbWDbWCbWFbWEbXNbXsbXubXtbXvcbdcbdcbecbdcbfcbicbfcbfcbfcbhcblcbjcbjcbkcbmcbocbnbZUcbpcbrcbqbGlcbscbubYjcacbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabPIbPIbPIbPIbPIbPIbRGbTobRAcbzbRAcbxcbycbAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacbDcbBbOccbCbOccbEcbFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacbGaabaaaaaaaaaaaacamcbIcbHcbKcbJbYMcbNcbLcbMcbRbYMbOwbTycbOcbPcbQbXwcbVcbTcbUcbWcbYcbXbXxcbZcccccbccfccdcceccgccjcchccibXybXzcclccmbEnccnbFOccoccpccrbFObXBbQVbXCcaAcaAbXDbXDcaAbXFbXEbXHbXGbXJbXIbWabXKbXMbXLbXMbXObWabXPbWAbXRbWdbXSbXUbXTbXSbXSbWibXVbXWbXQbYkcbdccTccSccVccUccXccWcdbcbfccYccZcdacbjcbjcdccbocddcdfbPEcdhcdgbGmcdicdkbYjcdndfcbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabPLbPIcdlcdmcdpcdlcdobRGbRAbRAbRGbRAcdrcdqcdsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacdvcdtcducducducdtcdwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacamcdycdxcdAcdzbYLcdBcdDcdCcdEbYMbOwbNwcdFbTybTybYmbYncdIcdJcclcdObYobYpcdMcdNcdNcdQcdPcdRcdNcdNcdTcdNcdNcdScclccmbEncdVcdUcdXbYqcdZcdYbFOchfbYrcaAbZhbYsbYsbZibZjbXHbZlbZkbZnbZmbZpbZobZrbZqbZtbZsbZvbZubWAcuvchrbZwbZybZxbZAbZzbZBccQbXWbXQbZBcbdcezceyceBceAceDceCceGcbfceEccZceFceFcbjceHceJceIceLceKceNceMbGnceOceSbYjcaccLhbGpbGobGsaaaaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabWObWGceRceRceRceRceRceTbRAbRAbRGbPIbPIbPIbPIbPIbPIbPRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaceVceUceUceUceWaaaaaaaaaaaaaaaaaaaaaceXceZceYceZcfaaaaaaaaaacamcamcamcffcfbcdAcfcbYLcfdcbMcfecfgbYMbOwbNxbTicficflcfkbZDbZCbZFbZEbZHbZGbZIcfscftcftcfxcfvcfvcfvcfvcfvcfvcfvcJfcfycfzcfBbZLbZKbZYbZScabcaacadchfcajcaAcazcalcaCcaBcaEcaDcaGcaFcaIcaHcaKcaJcaMcaLcaOcaNbZvcaPcaQcuvbZzcaRcaTcaScaVcaUcaXcaWcaZcaYcaXcbdcgccgbcgecgdcghcgfcggcbfcgiccZceFceFcbjcgjcgmcgkcglcgncgpcgocgrcgqcgvbYjcaccgscgtcgscgucgycgucgucguaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaabaabaabaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaebPIcafcagcahcaibRAbRGbRAbRAbRGbRAcancakcaraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabOebOcbOcbOcbOcbOcbOebPTbKBbKBbxbbxbbKBbKBbKBbKBbKBbxbbxbbKBbKBbKBbxbcamcamcamcascambYMcaocapcaqcatbYMbOwbTycawbMEbMEbMGbMGbMGbMGbMGbMNbMHbTJbTIcaubTJcavcaxbFCbFCbFCbFCbFCbSibSjbSibSibSibSibSibSibSibNvbFObWfbSLbWkbWhbWobWmbWscaAbWubWtbWxbWwbXGbWubWabWybWabWybWabWybWabWzbWAcrAbTZbWBbWDbWCbWFbWEbXNbXsbXubXtbXvcbdcbdcbecbdcbfcbicbfcbfcbfcbhcblcbjcbjcbkcbmcbocbnbZUcbpcbrcbqbGlcbscbubYjcacbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabPIbPIbPIbPIbPIbPIbRGbTobRAcbzbRAcbxcbycbAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacbDcbBbOccbCbOccbEcbFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacbGaabaaaaaaaaaaaacamcbIcbHcbKcbJbYMcbNcbLcbMcbRbYMbOwbTycbOcbPcbQbXwcbVcbTcbUcbWcbYcbXbXxcbZcccccbccfccdcceccgccjcchccibXybXzcclccmbEnccnbFOccoccpccrbFObXBbQVbXCcaAcaAbXDbXDcaAbXFbXEbZhbXHbZibXIbWabXKbXMbXLbXMbXObWabXPbWAbXRbWdbXSbXUbXTbXSbXSbWibXVbXWbXQbYkcbdccTccSccVccUccXccWcdbcbfccYccZcdacbjcbjcdccbocddcdfbPEcdhcdgbGmcdicdkbYjcdndfcbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabPLbPIcdlcdmcdpcdlcdobRGbRAbRAbRGbRAcdrcdqcdsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacdvcdtcducducducdtcdwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacamcdycdxcdAcdzbYLcdBcdDcdCcdEbYMbOwbNwcdFbTybTybYmbYncdIcdJcclcdObYobYpcdMcdNcdNcdQcdPcdRcdNcdNcdTcdNcdNcdScclccmbEncdVcdUcdXbYqcdZcdYbFOchfbYrcaAbZjbYsbYsbXJbZhbZkbZnbZlcaBbZmbZpbZobZrbZqbZtbZsbZvbZubWAcuvchrbZwbZybZxbZAbZzbZBccQbXWbXQbZBcbdcezceyceBceAceDceCceGcbfceEccZceFceFcbjceHceJceIceLceKceNceMbGnceOceSbYjcaccLhbGpbGobGsaaaaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabWObWGceRceRceRceRceRceTbRAbRAbRGbPIbPIbPIbPIbPIbPIbPRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaceVceUceUceUceWaaaaaaaaaaaaaaaaaaaaaceXceZceYceZcfaaaaaaaaaacamcamcamcffcfbcdAcfcbYLcfdcbMcfecfgbYMbOwbNxbTicficflcfkbZDbZCbZFbZEbZHbZGbZIcfscftcftcfxcfvcfvcfvcfvcfvcfvcfvcJfcfycfzcfBbZLbZKbZYbZScabcaacadchfcajcaAcazcalcaCcaEcaEcaDcaGcaFcaIcaHcaKcaJcaMcaLcaOcaNbZvcaPcaQcuvbZzcaRcaTcaScaVcaUcaXcaWcaZcaYcaXcbdcgccgbcgecgdcghcgfcggcbfcgiccZceFceFcbjcgjcgmcgkcglcgncgpcgocgrcgqcgvbYjcaccgscgtcgscgucgycgucgucguaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaabaabaabaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYubWGceRceRceRcgwcgxbRGbRAbRAbRGbRAbRAbRAcgzbRAcgAbRGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacgFcgBcgCcgDcgFbYPbYPbYPcamcgHcgGcgJcgIcgLcgKcgNcgMcgOcgOcgPbYMbTkcgQcgTcgScgScgUcbacgVcgScgWcgWcgYcbbcgZcgWcgWchacclcclchechcchcchcchccbcchcchcchfcbgchfchfchfchfchfchfchfcbvcbtcbScbwcckccaccsccqccucctccwccvbWaccxcczccyccBccAccDccCccEcuvccGccFccIccHccJchrbWibWgbWgbWgbWicbdcbdchMchQchOchPchOchRcbfchUchSchTchTcbjchVchXbTwbYjbYjbYjbYjbYjbYjbYjbYjcaccgscifchYchZciaciacibcguaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcicciccicciccidcidcieciecieciecijaabaabaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaebPIcigceRceRcihciibRGbRAbRAcikbRAbRAbRAciobRAcilbRGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaceYcimcincimceYbYPcipciqcamcitcfbcircisciyciubYMcivciwcixcizbYMcgQcgQciCcgSciAciBccKciDciHcgWccLciGccMciIciKcgWciMciLciNchcccOccNccRccPcdjcdecdKcdHcdLchfceacdWceccebchfcedcbvcaAcaAcaAcaAcaAcaAcaAcefceecegcaAcDfcDfcDfcDfcDfcDfcDfcDfceicehccGcejcelcekcencemcepceocerceqclpcjFcjHcjGcjIcjGcjGcjLcjJcjKcjPcjMcjNcjOcbjcjQbUtcbnbPtbGGcjTcjScjUcjUcjScjUcjYcgscjVcjWchZciackecjXcguaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciccjZckacjZcidciecieckbckcckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaebPIckdceRceRckfbRGbRAbRAbRGckgbRAbRAckjckhbPIbYvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacgFckicimcimckkcklcfbcfbckmckncfbcfbcisckqckobYMbYMbYMbYMbYMbYMckpcgQciCcgSclRcesceucetckucgWckvcevcexcewcePcgWcfmceQcfnchccfpcfockHckGcfqckIchcchfdgCchfcebcebcfrcebchfcsLcbvchfcfwbUucfCcfAcfEcfDcfGcfFcfIcfHcfKcfJcfMcfLcDfcfNcfPcfOcfRcfQcfTcfScfVcfUcfXcfWcepcfYcgacfZclpclncjGcjGclmclocjGcltclpcbjclqccZclrclrcbjcbmclscbnbPtcgsclvcgscgscgscgscgscgscgscluclwcguclxclzclycguafOafOafOafOafOafOafOafOafOafOafOafOafOafOafOafOafOafOafOafOafOclBcjZcjZclAciecieckbckbclHckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
@@ -8983,8 +8984,8 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaebPIbPIbPIbPIbPIbPIbPIbPIbPIbPIbYvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaabafOcgQcngcngcgQcngcngcgQaaaaaacgFcnhcnicnjcgFbYPbYPbYPcamcnmcnlcnocnocnocamcamcgQcnncnpcnrcnqcgQcnscntcgSclRcktcktcktcnvcgWckvckwckwcnuchHcgWcpicHDcnAchcchcchcchcchcchIchcchccnCdgCcsLcsLcsLchfcABchJcsLcbvchfchLchKciEchNcfEciFcfGcfFcfIcfHciOciJciQciPcDfciRciScDfciUciTchrciVciXciWchrchrcepciYcjaciZclpcjbcodcoicoicoicodcogcodcodcohcojclrclrcbjcokclscbncomcolcooconcorcopcoqcoqcotcoscovcoucoxcowcozcoycoCcoAcoBcoDcoEcoFcoHcoGcoIaabaabaabaabaabaabaabaabaaaaaaaaaaaaaaacidciecoMcoJcoJckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaacgQcoKcoLcgQcoKcoLcgQaaaaaacoOceZcoNceZcoQaaaaabaaacamcamcamcamcamcamcamcoPcgQcoScoRcoUcoTclPcoVcoWcgScoYcoXcpfcktcjccgWcjdckwcjfcjecjgcgWcjicjhcjkcjjcpqcpqcpqcpqcjlcpmcppcpocjncjmcjmcjocjqcjpcjscjrcjtchfcjwcjucjycjxcjAcjzcjCcjBcjCcjDckrcjEckxcksckzckyckAcDfckBcuvckCcjvckDcmDckFckEciYckJckLcgacpRcpTcpRcpUcpWcpVcpRcpXcpYcodcqacpZcdacbjcbjcqccqbcqfcqdcqecqicqgcqhcqlcqjcqkcqncqmcqpcqocqtcqqcqrcqqcqscqrcqrcqucqwcqvcqycqxcqCaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaacieciecqDckbckbckbckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafOaaaafOcgQcqzcoLcgQcqzcoLcgQaaaaaaaabaabaabaabaabaabaabaabaabcgQcoLcqAcqBcgQcqEcqGcgQcqHcgQcgQcqFcgQcgQcqPcgScqRcqIcqJcqKcqLcgWckMcqOcqScqQcqTcgWckOckNckPcJZcsDcsDcsDcsDcsDcrdcqZcrackQchfcucckRcsLckSckTcsLcsKchfckVckUckXckWcCWckYclackZclbcDfcldclcclfclecDfcDfcDfcDfclhclgckCchCcljclicllclkciYcmdcgacmfcpRcrNcrQcrLcrMcrLcrTcrOcrPcodcbjcrUcbjcbjcrRcrSclsbLRbPtcgscrVcgscgscrWcrYcrXcsacrZcsdcsbcsfcsecsgcsecsgcshcsgcsicgEcsncvdcsqcsraabaabaabaabaabaabaabaabaaaaaaaaaaaaaaacieckbckbckbckbckbckbcssckbcstckbckbckbckbckbciecieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcsjafOaabaMraMrafOcgQcgQcqFcgQcgQcqFcgQcgQcgQcngcngcngcgQcgQcgQcgQcgQcgQcgQcoLcskcslcgQcsmcgQcgQcsucgQcsocspcoLcgQcsvcgScsycsxcszclRcmgcgWcswckvcsEcsCcmhcgWcsIcsHcmicsDcsDcsNcsOcsGcmjcsQcsJcsKcsLcsUchfcmkcsLckSckTchfchfchfcCWcCWcmlcCWcCWcxhcxhcmmcxhcDfcDfcDfcDfcDfcDfcmncmpcmocmrcmqcmtcmscmvcmucmxcmwciYcgacgaaqEcpRcttctxctwctyctwctActzcrLctuctvctBbLRctCbLRcrSclsbLRbIictFctHctGcgscgscgscgscgsctIcqkctKctDcsccqkctEcqkclucqkctLcgEctOctQctPcgEaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaciectJctJctJctJctJctJctSckbctTctJcstckbckbckbckbcieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabafOafOcngcoLcoLcoLcoLctMctNcoLcoLcoSctUctUctVctUctUctUctUctUctUctUctUctUctUctUctUcoRcgQcskcqzctWcgQcsvctRctRctRctRctRctRcgWcgWcgWcgWcgWcgWcgWcuactXcmBcmzcmEcmCcmFcmFcmGcuicsJcmHcsLcubcuccmIcsLckScmJchicsLcsLcsKcCWcmLcmKcmNcCWcnxcnwcnBcnzcnEcnDcnGcnFcnIcnHcnKcnJcnMcnLckCcnNcnPcnOcnRcnQciYbQXcgacgacpRcuGcnTcnScnUcrLcuKcuJcuOcuLcuScuRcuVbLRcuXcrSclscuMbIibPAcuNcuYcuPcuQbGGbGGcgscvccvecuTcuUcvfcuWcvgcvicuZcvacvbcgEcvjdoKdoFcvraaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaacvscjZcjZcjZcjZcjZcjZcjZcvhcvtckbckbckbckbcvvckccieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcsjafOaabaMraMrafOcgQcgQcqFcgQcgQcqFcgQcgQcgQcngcngcngcgQcgQcgQcgQcgQcgQcgQcoLcskcslcgQcsmcgQcgQcsucgQcsocspcoLcgQcsvcgScsycsxcszclRcmgcgWcswckvcsEcsCcmhcgWcsIcsHcmicsDcsDcsGcsOcsNcmjcsQcsJcsKcsLcsUchfcmkcsLckSckTchfchfchfcCWcCWcmlcCWcCWcxhcnwcmmcxhcDfcDfcDfcDfcDfcDfcmncmpcmocmrcmqcmtcmscmvcmucmxcmwciYcgacgaaqEcpRcttctxctwctyctwctActzcrLctuctvctBbLRctCbLRcrSclsbLRbIictFctHctGcgscgscgscgscgsctIcqkctKctDcsccqkctEcqkclucqkctLcgEctOctQctPcgEaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaciectJctJctJctJctJctJctSckbctTctJcstckbckbckbckbcieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabafOafOcngcoLcoLcoLcoLctMctNcoLcoLcoSctUctUctVctUctUctUctUctUctUctUctUctUctUctUctUcoRcgQcskcqzctWcgQcsvctRctRctRctRctRctRcgWcgWcgWcgWcgWcgWcgWcuactXcmBcmzcmEcmCcmFcmFcmGcuicsJcmHcsLcubcuccmIcsLckScmJchicsLcsLcsKcCWcmLcmKcmNcCWcHWcnxcnBcnzcnEcnDcnGcnFcnIcnHcnKcnJcnMcnLckCcnNcnPcnOcnRcnQciYbQXcgacgacpRcuGcnTcnScnUcrLcuKcuJcuOcuLcuScuRcuVbLRcuXcrSclscuMbIibPAcuNcuYcuPcuQbGGbGGcgscvccvecuTcuUcvfcuWcvgcvicuZcvacvbcgEcvjdoKdoFcvraaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaacvscjZcjZcjZcjZcjZcjZcjZcvhcvtckbckbckbckbcvvckccieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabafOaabaabafOcngcvkcvlcvmcoLcoLcvncoLcoLcsucgQcgQcgQcgQcgQcgQcqFcgQcgQcgQcgQcvocvocvocvocvocvocvocvocvocgQcsvcvpaaaaaaaaaaaacvqcvwcvzcvycvucvAcvDcvxcvJcvGcvKcvBcvCcvLcvEcvEcvFcvMcvHcvIcvIcvIcvIcvNcvIckScmJchfcnVcKOdercCWcnXcnWcnZcnYcobcoacoccoccofcoecpacoZcpccpbcpecpdcphcpgciYciYciYciYciYciYciYciYcpkcpjcpRcwjcplcwqcptcpncpvcpucpRcpRbIicwpbIibIibIicwvcwJcwwbIibGGcuNcwKcwucuQcuQcuQcgscgscgscgscgscgscgscgscgscgscgscgscgEcgEcgEcgEcgEaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaciecoJcoJcoJcoJcoJcoJcwLckbcoMcoJcwMckbckbckbckbcieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcgQcwxcwxcwxcwxcwxcwxcwycwxcsucwzcgQcoLcwAcwBcwCcoLcwCcwDcwEcwBcvocwFcwFcvocwGcvocwHcwIcvocoLcqPcngaaacwPcwUcwQcwVcwNcwOcwWcwXcwRcwScwTcwZcwYcxbcxacxdcxccxfcxecxjcxgcvHcxkcxmcxmcxmcxocvIckScmJchfdgmcQkcQkcQkcQkcpwcpxcQkcpycpycpycpycQkcpzcpBcpAcQkcQncQncpCcpDcuocukbQXbQXcpEbQXbQXbQXbQXbQXcpFcpRcpRcpRcpRcpGcpRcpRcpRcxIcpHcpIcxKcxUcxMcxNcxOcxWcxQcxNbGGcuNcylbGGbGGcxScxZcyactFbGGbGGbGGbGGbGGbGGbGGcxVcymbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacieckbckbckbckbckbckbcssckbcwMckbckbckbckbckbciecieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxXcxYcxYcxYcxYcxYcxYcyocyncybcyccydcyecyfcwycsucygcgQcoLcoLcwBcoLcoLcoLcwDcqBcwBcvocwFcyicwIcwIcyjcwIcykcvocypcqPcngaaacyrcytcyscyvcyqcwOcywcyAcyycyucvxcyCcsHcyEcvBcyxctYcyFctYcyzcyGcyBcyHcyDcyDcyDcyIcvIckScmJchfcQkcQkcpKcpJcQkcQkcQkcQkcpMcpLcpOcpNcQkcQkcpPcQkcQkcTBdgmbQVcpScuvcqMcqMcqMcqMcqMcqMcqNbQXcqWcqUcqXcqXcqXcqYcrccrbcrbcrfcrbcrbcrbcrgczmczmcricrhcrjczwczzczyczBczAczCczCczDczCczCczCczCczGczIczCczCczCczOczLbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacieciecqDckbckbckbckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/_maps/test_all_maps.dm b/_maps/test_all_maps.dm
new file mode 100644
index 00000000000..5289988bf82
--- /dev/null
+++ b/_maps/test_all_maps.dm
@@ -0,0 +1,112 @@
+// This is for Travis testing. DO NOT SET THIS AS THE GAME'S MAP NORMALLY!
+
+#if !defined(USING_MAP_DATUM)
+ // Away missions
+ #include "map_files\RandomZLevels\beach.dmm"
+ #include "map_files\RandomZLevels\moonoutpost19.dmm"
+ #include "map_files\RandomZLevels\undergroundoutpost45.dmm"
+ #include "map_files\RandomZLevels\academy.dmm"
+ #include "map_files\RandomZLevels\blackmarketpackers.dmm"
+ #include "map_files\RandomZLevels\spacehotel.dmm"
+ #include "map_files\RandomZLevels\stationCollision.dmm"
+ #include "map_files\RandomZLevels\wildwest.dmm"
+ #include "map_files\RandomZLevels\evil_santa.dmm"
+
+ // Space Ruins
+ #include "map_files\RandomRuins\SpaceRuins\abandonedzoo.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\asteroid1.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\asteroid2.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\asteroid3.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\asteroid4.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\asteroid5.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\deepstorage.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\derelict1.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\derelict2.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\derelict3.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\derelict4.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\derelict5.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\emptyshell.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\gasthelizards.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\intactemptyship.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\listeningpost.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\mechtransport.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\onehalf.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\spacebar.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\turretedoutpost.dmm"
+ #include "map_files\RandomRuins\SpaceRuins\way_home.dmm"
+
+ // Shuttle Templates
+ #include "map_files\shuttles\cargo_base.dmm"
+ #include "map_files\shuttles\emergency_bar.dmm"
+ #include "map_files\shuttles\emergency_clown.dmm"
+ #include "map_files\shuttles\emergency_cramped.dmm"
+ #include "map_files\shuttles\emergency_cyb.dmm"
+ #include "map_files\shuttles\emergency_dept.dmm"
+ #include "map_files\shuttles\emergency_meta.dmm"
+ #include "map_files\shuttles\emergency_mil.dmm"
+ #include "map_files\shuttles\emergency_narnar.dmm"
+ #include "map_files\shuttles\emergency_old.dmm"
+ #include "map_files\shuttles\ferry_base.dmm"
+ #include "map_files\shuttles\ferry_meat.dmm"
+
+ // Other templates
+ #include "map_files\templates\spacehotel\n_01.dmm"
+ #include "map_files\templates\spacehotel\n_02.dmm"
+ #include "map_files\templates\spacehotel\n_03.dmm"
+ #include "map_files\templates\spacehotel\n_04.dmm"
+ #include "map_files\templates\spacehotel\n_05.dmm"
+ #include "map_files\templates\spacehotel\n_06.dmm"
+ #include "map_files\templates\spacehotel\n_07.dmm"
+ #include "map_files\templates\spacehotel\n_08.dmm"
+ #include "map_files\templates\spacehotel\n_09.dmm"
+ #include "map_files\templates\spacehotel\n_10.dmm"
+ #include "map_files\templates\spacehotel\n_11.dmm"
+ #include "map_files\templates\spacehotel\n_12.dmm"
+ #include "map_files\templates\spacehotel\n_13.dmm"
+ #include "map_files\templates\spacehotel\n_14.dmm"
+ #include "map_files\templates\spacehotel\n_15.dmm"
+ #include "map_files\templates\spacehotel\n_16.dmm"
+ #include "map_files\templates\spacehotel\n_17.dmm"
+ #include "map_files\templates\spacehotel\n_18.dmm"
+ #include "map_files\templates\spacehotel\n_19.dmm"
+
+ #include "map_files\templates\spacehotel\s_01.dmm"
+ #include "map_files\templates\spacehotel\s_02.dmm"
+ #include "map_files\templates\spacehotel\s_03.dmm"
+ #include "map_files\templates\spacehotel\s_04.dmm"
+ #include "map_files\templates\spacehotel\s_05.dmm"
+ #include "map_files\templates\spacehotel\s_06.dmm"
+
+ #include "map_files\templates\light_floor_1.dmm"
+ #include "map_files\templates\light_floor_2.dmm"
+ #include "map_files\templates\light_floor_3.dmm"
+ #include "map_files\templates\medium_shuttle1.dmm"
+ #include "map_files\templates\medium_shuttle2.dmm"
+ #include "map_files\templates\medium_shuttle3.dmm"
+ #include "map_files\templates\shelter_1.dmm"
+ #include "map_files\templates\shelter_2.dmm"
+ #include "map_files\templates\small_asteroid_1.dmm"
+ #include "map_files\templates\small_shuttle_1.dmm"
+
+ // VR maps
+ #include "map_files\vr\blood_and_sand.dmm"
+ #include "map_files\vr\lobby.dmm"
+
+
+ // This is pointless, we don't run the server
+ /*#define MAP_TRANSITION_CONFIG list(AWAY_MISSION = UNAFFECTED,
+ AWAY_MISSION = UNAFFECTED,
+ AWAY_MISSION = UNAFFECTED,
+ AWAY_MISSION = UNAFFECTED,
+ AWAY_MISSION = UNAFFECTED,
+ AWAY_MISSION = UNAFFECTED,
+ AWAY_MISSION = UNAFFECTED,
+ AWAY_MISSION = UNAFFECTED,
+ AWAY_MISSION = UNAFFECTED,
+ AWAY_MISSION = UNAFFECTED)
+
+ #define USING_MAP_DATUM /datum/map*/
+
+#elif !defined(MAP_OVERRIDE)
+ #warn a map has already been included.
+#endif
diff --git a/_maps/test_away_missions.dm b/_maps/test_away_missions.dm
deleted file mode 100644
index 42b068412bd..00000000000
--- a/_maps/test_away_missions.dm
+++ /dev/null
@@ -1,21 +0,0 @@
-// This is for Travis testing. DO NOT SET THIS AS THE GAME'S MAP NORMALLY!
-
-#if !defined(USING_MAP_DATUM)
- #include "map_files\RandomZLevels\beach.dmm"
- #include "map_files\RandomZLevels\moonoutpost19.dmm"
- #include "map_files\RandomZLevels\undergroundoutpost45.dmm"
- #include "map_files\RandomZLevels\academy.dmm"
- #include "map_files\RandomZLevels\blackmarketpackers.dmm"
- #include "map_files\RandomZLevels\spacehotel.dmm"
- #include "map_files\RandomZLevels\stationCollision.dmm"
- #include "map_files\RandomZLevels\wildwest.dmm"
-
- #include "map_files\RandomZLevels\evil_santa.dmm"
-
- #define MAP_TRANSITION_CONFIG list(AWAY_MISSION = UNAFFECTED, AWAY_MISSION = UNAFFECTED, AWAY_MISSION = UNAFFECTED, AWAY_MISSION = UNAFFECTED, AWAY_MISSION = UNAFFECTED, AWAY_MISSION = UNAFFECTED, AWAY_MISSION = UNAFFECTED, AWAY_MISSION = UNAFFECTED, AWAY_MISSION = UNAFFECTED, AWAY_MISSION = UNAFFECTED)
-
- #define USING_MAP_DATUM /datum/map
-
-#elif !defined(MAP_OVERRIDE)
- #warn a map has already been included.
-#endif
diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm
index 1506cd26129..3fcf79fe8d8 100644
--- a/code/ATMOSPHERICS/atmospherics.dm
+++ b/code/ATMOSPHERICS/atmospherics.dm
@@ -7,10 +7,9 @@ Pipelines and other atmospheric objects combine to form pipe_networks
Pipes -> Pipelines
Pipelines + Other Objects -> Pipe network
-
*/
+GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new())
/obj/machinery/atmospherics
- auto_init = 0
anchored = 1
layer = 2.4 //under wires with their 2.44
idle_power_usage = 0
@@ -29,15 +28,12 @@ Pipelines + Other Objects -> Pipe network
var/pipe_color
var/obj/item/pipe/stored
var/image/pipe_image
- var/global/datum/pipe_icon_manager/icon_manager
/obj/machinery/atmospherics/New()
if(!armor)
armor = list(melee = 25, bullet = 10, laser = 10, energy = 100, bomb = 0, bio = 100, rad = 100)
..()
SSair.atmos_machinery += src
- if(!icon_manager)
- icon_manager = new()
if(!pipe_color)
pipe_color = color
@@ -45,12 +41,8 @@ Pipelines + Other Objects -> Pipe network
if(!pipe_color_check(pipe_color))
pipe_color = null
- // No need for a tween worldstart roundstart handler - pipenet creation is
- // handled there
-
-/obj/machinery/atmospherics/initialize()
- ..()
+/obj/machinery/atmospherics/proc/atmos_init()
if(can_unwrench)
stored = new(src, make_from = src)
@@ -73,9 +65,9 @@ Pipelines + Other Objects -> Pipe network
pipe_image.plane = HUD_PLANE
/obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0)
- if(!istype(icon_manager))
+ if(!istype(GLOB.pipe_icon_manager))
if(!safety) //to prevent infinite loops
- icon_manager = new()
+ GLOB.pipe_icon_manager = new()
check_icon_cache(1)
return 0
@@ -91,14 +83,14 @@ Pipelines + Other Objects -> Pipe network
/obj/machinery/atmospherics/proc/add_underlay(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type)
if(node)
if(T.intact && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
- //underlays += icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node))
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
+ //underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node))
+ underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
else
- //underlays += icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node))
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
+ //underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node))
+ underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
else
- //underlays += icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color)
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "exposed" + icon_connect_type)
+ //underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color)
+ underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "exposed" + icon_connect_type)
/obj/machinery/atmospherics/proc/update_underlays()
if(check_icon_cache())
@@ -231,10 +223,10 @@ Pipelines + Other Objects -> Pipe network
var/turf/T = loc
level = T.intact ? 2 : 1
add_fingerprint(usr)
- initialize()
+ atmos_init()
var/list/nodes = pipeline_expansion()
for(var/obj/machinery/atmospherics/A in nodes)
- A.initialize()
+ A.atmos_init()
A.addMember(src)
build_network()
@@ -320,11 +312,11 @@ Pipelines + Other Objects -> Pipe network
/obj/machinery/atmospherics/proc/add_underlay_adapter(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type) //modified from add_underlay, does not make exposed underlays
if(node)
if(T.intact && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
+ underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
else
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
+ underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
else
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "retracted" + icon_connect_type)
+ underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "retracted" + icon_connect_type)
/obj/machinery/atmospherics/singularity_pull(S, current_size)
if(current_size >= STAGE_FIVE)
diff --git a/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm b/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm
index 276ce5e7b6e..c11a0421bda 100644
--- a/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm
@@ -41,7 +41,7 @@
nullifyPipenet(parent2)
return ..()
-/obj/machinery/atmospherics/binary/initialize()
+/obj/machinery/atmospherics/binary/atmos_init()
..()
var/node2_connect = dir
var/node1_connect = turn(dir, 180)
diff --git a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm
index bfffb7cd35d..aebc09cfc7a 100644
--- a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm
@@ -48,7 +48,7 @@
radio_connection = null
return ..()
-/obj/machinery/atmospherics/binary/dp_vent_pump/initialize()
+/obj/machinery/atmospherics/binary/dp_vent_pump/atmos_init()
..()
if(frequency)
set_frequency(frequency)
@@ -90,7 +90,7 @@
else
vent_icon += "[on ? "[pump_direction ? "out" : "in"]" : "off"]"
- overlays += icon_manager.get_atmos_icon("device", , , vent_icon)
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("device", , , vent_icon)
/obj/machinery/atmospherics/binary/dp_vent_pump/update_underlays()
if(..())
diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
index e43b052095b..9e845c15a98 100644
--- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
@@ -16,7 +16,7 @@
var/id = null
var/datum/radio_frequency/radio_connection
-/obj/machinery/atmospherics/binary/passive_gate/initialize()
+/obj/machinery/atmospherics/binary/passive_gate/atmos_init()
..()
if(frequency)
set_frequency(frequency)
diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm
index db0c7144324..118a70c3ecd 100644
--- a/code/ATMOSPHERICS/components/binary_devices/pump.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm
@@ -110,7 +110,7 @@ Thus, the two variables affect pump operation are set in New():
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
return 1
-/obj/machinery/atmospherics/binary/pump/initialize()
+/obj/machinery/atmospherics/binary/pump/atmos_init()
..()
if(frequency)
set_frequency(frequency)
diff --git a/code/ATMOSPHERICS/components/binary_devices/valve.dm b/code/ATMOSPHERICS/components/binary_devices/valve.dm
index 7b566e04fda..1d7805c55b2 100644
--- a/code/ATMOSPHERICS/components/binary_devices/valve.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/valve.dm
@@ -109,7 +109,7 @@
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
-/obj/machinery/atmospherics/binary/valve/digital/initialize()
+/obj/machinery/atmospherics/binary/valve/digital/atmos_init()
..()
if(frequency)
set_frequency(frequency)
diff --git a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm
index c4dd8adeabb..a64c94e7fc5 100644
--- a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm
@@ -38,7 +38,7 @@ Thus, the two variables affect pump operation are set in New():
on = 1
icon_state = "map_on"
-/obj/machinery/atmospherics/binary/volume_pump/initialize()
+/obj/machinery/atmospherics/binary/volume_pump/atmos_init()
..()
set_frequency(frequency)
diff --git a/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm b/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm
index 1858b685ec0..a1f80916aee 100644
--- a/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm
+++ b/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm
@@ -40,9 +40,9 @@
/datum/omni_port/proc/connect()
if(node)
return
- master.initialize()
+ master.atmos_init()
if(node)
- node.initialize()
+ node.atmos_init()
node.addMember(master)
master.build_network()
diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm
index 086d2ff799f..0eed9729f87 100644
--- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm
+++ b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm
@@ -56,7 +56,7 @@
nullifyPipenet(P.parent)
return ..()
-/obj/machinery/atmospherics/omni/initialize()
+/obj/machinery/atmospherics/omni/atmos_init()
..()
for(var/datum/omni_port/P in ports)
if(P.node || P.mode == 0)
@@ -143,11 +143,11 @@
//directional icons are layers 1-4, with the core icon on layer 5
if(core_icon)
- overlays_off[5] = icon_manager.get_atmos_icon("omni", , , core_icon)
- overlays_on[5] = icon_manager.get_atmos_icon("omni", , , core_icon + "_glow")
+ overlays_off[5] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon)
+ overlays_on[5] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon + "_glow")
- overlays_error[1] = icon_manager.get_atmos_icon("omni", , , core_icon)
- overlays_error[2] = icon_manager.get_atmos_icon("omni", , , "error")
+ overlays_error[1] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon)
+ overlays_error[2] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , "error")
/obj/machinery/atmospherics/omni/proc/update_port_icons()
if(!check_icon_cache())
@@ -203,19 +203,19 @@
ic_on += "_filter"
ic_off += "_out"
- ic_on = icon_manager.get_atmos_icon("omni", , , ic_on)
- ic_off = icon_manager.get_atmos_icon("omni", , , ic_off)
+ ic_on = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , ic_on)
+ ic_off = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , ic_off)
var/pipe_state
var/turf/T = get_turf(src)
if(!istype(T))
return
if(T.intact && istype(P.node, /obj/machinery/atmospherics/pipe) && P.node.level == 1 )
- //pipe_state = icon_manager.get_atmos_icon("underlay_down", P.dir, color_cache_name(P.node))
- pipe_state = icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "down")
+ //pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay_down", P.dir, color_cache_name(P.node))
+ pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "down")
else
- //pipe_state = icon_manager.get_atmos_icon("underlay_intact", P.dir, color_cache_name(P.node))
- pipe_state = icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "intact")
+ //pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay_intact", P.dir, color_cache_name(P.node))
+ pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "intact")
return list("on_icon" = ic_on, "off_icon" = ic_off, "pipe_icon" = pipe_state)
diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm
index 427c77e8246..903f917e0c6 100755
--- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm
@@ -149,7 +149,7 @@ Filter types:
return 1
-/obj/machinery/atmospherics/trinary/filter/initialize()
+/obj/machinery/atmospherics/trinary/filter/atmos_init()
set_frequency(frequency)
..()
diff --git a/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm b/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm
index 187b308fa3c..e750256b0df 100644
--- a/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm
@@ -66,7 +66,7 @@
nullifyPipenet(parent3)
return ..()
-/obj/machinery/atmospherics/trinary/initialize()
+/obj/machinery/atmospherics/trinary/atmos_init()
..()
//Mixer:
//1 and 2 is input
diff --git a/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm b/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm
index ad9561fbf1d..9dddf8b06f4 100644
--- a/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm
@@ -156,7 +156,7 @@
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
-/obj/machinery/atmospherics/trinary/tvalve/digital/initialize()
+/obj/machinery/atmospherics/trinary/tvalve/digital/atmos_init()
..()
if(frequency)
set_frequency(frequency)
diff --git a/code/ATMOSPHERICS/components/unary_devices/heat_exchanger.dm b/code/ATMOSPHERICS/components/unary_devices/heat_exchanger.dm
index 496413c881c..58b374578df 100644
--- a/code/ATMOSPHERICS/components/unary_devices/heat_exchanger.dm
+++ b/code/ATMOSPHERICS/components/unary_devices/heat_exchanger.dm
@@ -20,7 +20,7 @@
return
-/obj/machinery/atmospherics/unary/heat_exchanger/initialize()
+/obj/machinery/atmospherics/unary/heat_exchanger/atmos_init()
if(!partner)
var/partner_connect = turn(dir,180)
diff --git a/code/ATMOSPHERICS/components/unary_devices/outlet_injector.dm b/code/ATMOSPHERICS/components/unary_devices/outlet_injector.dm
index 6028346df6d..fe5b6a0a445 100644
--- a/code/ATMOSPHERICS/components/unary_devices/outlet_injector.dm
+++ b/code/ATMOSPHERICS/components/unary_devices/outlet_injector.dm
@@ -120,7 +120,7 @@
return 1
-/obj/machinery/atmospherics/unary/outlet_injector/initialize()
+/obj/machinery/atmospherics/unary/outlet_injector/atmos_init()
..()
set_frequency(frequency)
diff --git a/code/ATMOSPHERICS/components/unary_devices/unary_base.dm b/code/ATMOSPHERICS/components/unary_devices/unary_base.dm
index 51b12d39481..4ef7743fc8c 100644
--- a/code/ATMOSPHERICS/components/unary_devices/unary_base.dm
+++ b/code/ATMOSPHERICS/components/unary_devices/unary_base.dm
@@ -22,7 +22,7 @@
nullifyPipenet(parent)
return ..()
-/obj/machinery/atmospherics/unary/initialize()
+/obj/machinery/atmospherics/unary/atmos_init()
..()
for(var/obj/machinery/atmospherics/target in get_step(src, dir))
if(target.initialize_directions & get_dir(target,src))
@@ -43,9 +43,9 @@
node.disconnect(src)
node = null
nullifyPipenet(parent)
- initialize()
+ atmos_init()
if(node)
- node.initialize()
+ node.atmos_init()
node.addMember(src)
build_network()
. = 1
diff --git a/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm b/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm
index 8f76e689eae..99eeb1883ea 100644
--- a/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm
+++ b/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm
@@ -98,7 +98,7 @@
else
vent_icon += "[on ? "[pump_direction ? "out" : "in"]" : "off"]"
- overlays += icon_manager.get_atmos_icon("device", , , vent_icon)
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("device", , , vent_icon)
update_pipe_image()
@@ -223,7 +223,7 @@
return 1
-/obj/machinery/atmospherics/unary/vent_pump/initialize()
+/obj/machinery/atmospherics/unary/vent_pump/atmos_init()
..()
//some vents work his own special way
diff --git a/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm
index 530dbe1d952..11b1fc0f920 100644
--- a/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm
+++ b/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm
@@ -109,7 +109,7 @@
if(welded)
scrubber_icon = "scrubberweld"
- overlays += icon_manager.get_atmos_icon("device", , , scrubber_icon)
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("device", , , scrubber_icon)
update_pipe_image()
/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays()
@@ -169,7 +169,7 @@
return 1
-/obj/machinery/atmospherics/unary/vent_scrubber/initialize()
+/obj/machinery/atmospherics/unary/vent_scrubber/atmos_init()
..()
radio_filter_in = frequency==initial(frequency)?(RADIO_FROM_AIRALARM):null
radio_filter_out = frequency==initial(frequency)?(RADIO_TO_AIRALARM):null
diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm
index 0692bf44efd..b4a0cd9ba7b 100644
--- a/code/ATMOSPHERICS/datum_pipeline.dm
+++ b/code/ATMOSPHERICS/datum_pipeline.dm
@@ -57,11 +57,7 @@ var/pipenetwarnings = 10
if(!members.Find(item))
if(item.parent)
- if(pipenetwarnings > 0)
- error("[item.type] added to a pipenet while still having one (pipes leading to the same spot stacking in one turf). Nearby: [item.x], [item.y], [item.z].")
- pipenetwarnings -= 1
- if(pipenetwarnings == 0)
- error("Further messages about pipenets will be suppressed.")
+ log_runtime(EXCEPTION("[item.type] \[\ref[item]] added to a pipenet while still having one ([item.parent]) (pipes leading to the same spot stacking in one turf). Nearby: [item.x], [item.y], [item.z]."))
members += item
possible_expansions += item
@@ -118,15 +114,12 @@ var/pipenetwarnings = 10
qdel(E)
/obj/machinery/atmospherics/proc/addMember(obj/machinery/atmospherics/A)
- return
+ var/datum/pipeline/P = returnPipenet(A)
+ P.addMember(A, src)
/obj/machinery/atmospherics/pipe/addMember(obj/machinery/atmospherics/A)
parent.addMember(A, src)
-/obj/machinery/atmospherics/addMember(obj/machinery/atmospherics/A)
- var/datum/pipeline/P = returnPipenet(A)
- P.addMember(A, src)
-
/datum/pipeline/proc/temporarily_store_air()
//Update individual gas_mixtures by volume ratio
diff --git a/code/ATMOSPHERICS/pipes/cap.dm b/code/ATMOSPHERICS/pipes/cap.dm
index 7691b157857..2552f6e0794 100644
--- a/code/ATMOSPHERICS/pipes/cap.dm
+++ b/code/ATMOSPHERICS/pipes/cap.dm
@@ -61,9 +61,9 @@
alpha = 255
overlays.Cut()
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "cap" + icon_connect_type)
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("pipe", , pipe_color, "cap" + icon_connect_type)
-/obj/machinery/atmospherics/pipe/cap/initialize()
+/obj/machinery/atmospherics/pipe/cap/atmos_init()
..()
for(var/obj/machinery/atmospherics/target in get_step(src, dir))
if(target.initialize_directions & get_dir(target,src))
diff --git a/code/ATMOSPHERICS/pipes/manifold.dm b/code/ATMOSPHERICS/pipes/manifold.dm
index a42903bb7f6..199942e7a40 100644
--- a/code/ATMOSPHERICS/pipes/manifold.dm
+++ b/code/ATMOSPHERICS/pipes/manifold.dm
@@ -32,7 +32,7 @@
if(WEST)
initialize_directions = NORTH|EAST|SOUTH
-/obj/machinery/atmospherics/pipe/manifold/initialize()
+/obj/machinery/atmospherics/pipe/manifold/atmos_init()
..()
for(var/D in cardinal)
if(D == dir)
@@ -122,8 +122,8 @@
alpha = 255
overlays.Cut()
- overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type)
- overlays += icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type)
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type)
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type)
underlays.Cut()
var/turf/T = get_turf(src)
diff --git a/code/ATMOSPHERICS/pipes/manifold4w.dm b/code/ATMOSPHERICS/pipes/manifold4w.dm
index 46b883db62b..502795e1da9 100644
--- a/code/ATMOSPHERICS/pipes/manifold4w.dm
+++ b/code/ATMOSPHERICS/pipes/manifold4w.dm
@@ -95,8 +95,8 @@
alpha = 255
overlays.Cut()
- overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type)
- overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type)
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type)
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type)
underlays.Cut()
var/turf/T = get_turf(src)
@@ -134,7 +134,7 @@
if(level == 1 && istype(loc, /turf/simulated))
invisibility = i ? 101 : 0
-/obj/machinery/atmospherics/pipe/manifold4w/initialize()
+/obj/machinery/atmospherics/pipe/manifold4w/atmos_init()
..()
for(var/D in cardinal)
for(var/obj/machinery/atmospherics/target in get_step(src, D))
diff --git a/code/ATMOSPHERICS/pipes/simple/pipe_simple.dm b/code/ATMOSPHERICS/pipes/simple/pipe_simple.dm
index 9f360f74274..b2c2750a452 100644
--- a/code/ATMOSPHERICS/pipes/simple/pipe_simple.dm
+++ b/code/ATMOSPHERICS/pipes/simple/pipe_simple.dm
@@ -43,7 +43,7 @@
if(SOUTHWEST)
initialize_directions = SOUTH|WEST
-/obj/machinery/atmospherics/pipe/simple/initialize(initPipe = 1)
+/obj/machinery/atmospherics/pipe/simple/atmos_init(initPipe = 1)
..()
if(initPipe)
normalize_dir()
@@ -145,9 +145,9 @@
overlays.Cut()
if(node1 && node2)
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, pipe_icon + "intact" + icon_connect_type)
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("pipe", , pipe_color, pipe_icon + "intact" + icon_connect_type)
else
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, pipe_icon + "exposed[node1?1:0][node2?1:0]" + icon_connect_type)
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("pipe", , pipe_color, pipe_icon + "exposed[node1?1:0][node2?1:0]" + icon_connect_type)
// A check to make sure both nodes exist - self-delete if they aren't present
/obj/machinery/atmospherics/pipe/simple/check_nodes_exist()
diff --git a/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm b/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm
index 26139b40606..cb7ec277f95 100644
--- a/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm
+++ b/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm
@@ -61,7 +61,7 @@
initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe
color = "#404040"
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/initialize(initPipe = 1)
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/atmos_init(initPipe = 1)
..(0)
if(initPipe)
normalize_dir()
@@ -110,7 +110,7 @@
initialize_directions = EAST
initialize_directions_he = WEST
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/initialize()
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/atmos_init()
..(0)
for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions))
if(target.initialize_directions & get_dir(target,src))
diff --git a/code/ATMOSPHERICS/pipes/simple/pipe_simple_hidden.dm b/code/ATMOSPHERICS/pipes/simple/pipe_simple_hidden.dm
index db62f8e51fe..3efd22ed446 100644
--- a/code/ATMOSPHERICS/pipes/simple/pipe_simple_hidden.dm
+++ b/code/ATMOSPHERICS/pipes/simple/pipe_simple_hidden.dm
@@ -34,7 +34,7 @@
alpha = 255
overlays.Cut()
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
underlays.Cut()
if(node1)
diff --git a/code/ATMOSPHERICS/pipes/simple/pipe_simple_visible.dm b/code/ATMOSPHERICS/pipes/simple/pipe_simple_visible.dm
index 1fcb45e7959..9bf085b534a 100644
--- a/code/ATMOSPHERICS/pipes/simple/pipe_simple_visible.dm
+++ b/code/ATMOSPHERICS/pipes/simple/pipe_simple_visible.dm
@@ -45,7 +45,7 @@
alpha = 255
overlays.Cut()
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
+ overlays += GLOB.pipe_icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
underlays.Cut()
if(node1)
diff --git a/code/_DATASTRUCTURES/linked_lists.dm b/code/_DATASTRUCTURES/linked_lists.dm
deleted file mode 100644
index eccc3c422a8..00000000000
--- a/code/_DATASTRUCTURES/linked_lists.dm
+++ /dev/null
@@ -1,191 +0,0 @@
-
-//Ok so it's technically a double linked list, bite me.
-
-/datum/linked_list
- var/datum/linked_node/head
- var/datum/linked_node/tail
- var/node_amt = 0
-
-
-/datum/linked_node
- var/value = null
- var/datum/linked_list/linked_list = null
- var/datum/linked_node/next_node = null
- var/datum/linked_node/previous_node = null
-
-
-/datum/linked_list/proc/IsEmpty()
- . = (node_amt <= 0)
-
-
-//Add a linked_node (or value, creating a linked_node) at position
-//the added node BECOMES the position-th element,
-//eg: add("Test",5), the 5th node is now "Test", the previous 5th moves up to become the 6th
-/datum/linked_list/proc/Add(node, position)
- var/datum/linked_node/adding
- if(istype(node, /datum/linked_node))
- adding = node
- else
- adding = new()
- adding.value = node
-
- if(!adding.linked_list || (adding.linked_list && (adding.linked_list != src)))
- node_amt++
-
- adding.linked_list = src
-
- if(position && position < node_amt)
- //Replacing head
- if(position == 1)
- if(head)
- head.previous_node = adding
- adding.next_node = head
- head = adding
-
- //Replacing any middle node
- else
- var/location = 0
- var/datum/linked_node/at
- while((location != position) && (location <= node_amt))
- if(at)
- if(at.next_node)
- at = at.next_node
- else
- break
- else
- at = head
- location++
-
- //Push at up and assume it's place as the position-th element
- if(at && at.previous_node)
- at.previous_node.next_node = adding
- adding.previous_node = at.previous_node
- at.previous_node = adding
- adding.next_node = at
- return
-
- //Replacing tail
- if(tail)
- tail.next_node = adding
- adding.previous_node = tail
- if(!tail.previous_node)
- head = tail
- tail = adding
-
-
-
-//Remove a linked_node or the linked_node of a value
-//If you specify a value the FIRST ONE is removed
-/datum/linked_list/proc/Remove(node)
- var/datum/linked_node/removing
- if(istype(node,/datum/linked_node))
- removing = node
- else
- //optimise removing head and tail, no point looping for them, especially the tail
- if(removing == head)
- removing = head
- else if(removing == tail)
- removing = tail
- else
- var/location = 1
- var/current_value = null
- var/datum/linked_node/at = null
- while((current_value != node) && (location <= node_amt))
- if(at)
- if(at.next_node)
- at = at.next_node
- else
- at = head
- location++
- if(at)
- current_value = at.value
- if(current_value == node)
- removing = at
- break
-
- //Adjust pointers of where removing -was- in the chain.
- if(removing)
- if(removing.previous_node)
- if(removing == tail)
- tail = removing.previous_node
- if(removing.next_node)
- if(removing == head)
- head = removing.next_node
- removing.next_node.previous_node = removing.previous_node
- removing.previous_node.next_node = removing.next_node
- else
- removing.previous_node.next_node = null
- else
- if(removing.next_node)
- if(removing == head)
- head = removing.next_node
- removing.next_node.previous_node = null
-
- //if this is still true at this point, there's no more nodes to replace them with
- if(removing == head)
- head = null
- if(removing == tail)
- tail = null
-
- removing.next_node = null
- removing.previous_node = null
- if(removing.linked_list == src)
- node_amt--
- removing.linked_list = null
-
- return removing
- return 0
-
-
-//Removes and deletes a node or value
-/datum/linked_list/proc/RemoveDelete(node)
- var/datum/linked_node/dead = Remove(node)
- if(dead)
- qdel(dead)
- return 1
- return 0
-
-
-//Empty the linked_list, deleting all nodes
-/datum/linked_list/proc/Empty()
- var/datum/linked_node/n = head
- while(n)
- var/next = n.next_node
- Remove(n)
- qdel(n)
- n = next
- node_amt = 0
-
-
-//Some debugging tools
-/datum/linked_list/proc/CheckNodeLinks()
- var/datum/linked_node/n = head
- while(n)
- . = "|[n.value]|"
- if(n.previous_node)
- . = "[n.previous_node.value]<-" + .
- if(n.next_node)
- . += "->[n.next_node.value]"
- n = n.next_node
- . += "
"
-
-
-/datum/linked_list/proc/DrawNodeLinks()
- . = "|<-"
- var/datum/linked_node/n = head
- while(n)
- if(n.previous_node)
- . += "<-"
- . += "[n.value]"
- if(n.next_node)
- . += "->"
- n = n.next_node
- . += "->|"
-
-
-/datum/linked_list/proc/ToList()
- . = list()
- var/datum/linked_node/n = head
- while(n)
- . += n
- n = n.next_node
\ No newline at end of file
diff --git a/code/_DATASTRUCTURES/priority_queue.dm b/code/_DATASTRUCTURES/priority_queue.dm
deleted file mode 100644
index 8689a19f4e4..00000000000
--- a/code/_DATASTRUCTURES/priority_queue.dm
+++ /dev/null
@@ -1,83 +0,0 @@
-
-//////////////////////
-//PriorityQueue object
-//////////////////////
-
-//an ordered list, using the cmp proc to weight the list elements
-/PriorityQueue
- var/list/L //the actual queue
- var/cmp //the weight function used to order the queue
-
-/PriorityQueue/New(compare)
- L = new()
- cmp = compare
-
-/PriorityQueue/proc/IsEmpty()
- return !L.len
-
-//return the index the element should be in the priority queue using dichotomic search
-/PriorityQueue/proc/FindElementIndex(atom/A)
- var/i = 1
- var/j = L.len
- var/mid
-
- while(i < j)
- mid = round((i+j)/2)
-
- if(call(cmp)(L[mid],A) < 0)
- i = mid + 1
- else
- j = mid
-
- if(i == 1 || i == L.len) //edge cases
- return (call(cmp)(L[i],A) > 0) ? i : i+1
- else
- return i
-
-
-//add an element in the list,
-//immediatly ordering it to its position using dichotomic search
-/PriorityQueue/proc/Enqueue(atom/A)
- if(!L.len)
- L.Add(A)
- return
-
- L.Insert(FindElementIndex(A),A)
-
-//removes and returns the first element in the queue
-/PriorityQueue/proc/Dequeue()
- if(!L.len)
- return 0
- . = L[1]
-
- Remove(.)
-
-//removes an element
-/PriorityQueue/proc/Remove(atom/A)
- return L.Remove(A)
-
-//returns a copy of the elements list
-/PriorityQueue/proc/List()
- . = L.Copy()
-
-//return the position of an element or 0 if not found
-/PriorityQueue/proc/Seek(atom/A)
- . = L.Find(A)
-
-//return the element at the i_th position
-/PriorityQueue/proc/Get(i)
- if(i > L.len || i < 1)
- return 0
- return L[i]
-
-//replace the passed element at it's right position using the cmp proc
-/PriorityQueue/proc/ReSort(atom/A)
- var/i = Seek(A)
- if(i == 0)
- return
- while(i < L.len && call(cmp)(L[i],L[i+1]) > 0)
- L.Swap(i,i+1)
- i++
- while(i > 1 && call(cmp)(L[i],L[i-1]) <= 0) //last inserted element being first in case of ties (optimization)
- L.Swap(i,i-1)
- i--
\ No newline at end of file
diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 8b7f4830c13..4c2708bf9dd 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -64,6 +64,17 @@
#define THROWN_PROJECTILE_ATTACK 4
#define LEAP_ATTACK 5
+//attack visual effects
+#define ATTACK_EFFECT_PUNCH "punch"
+#define ATTACK_EFFECT_KICK "kick"
+#define ATTACK_EFFECT_SMASH "smash"
+#define ATTACK_EFFECT_CLAW "claw"
+#define ATTACK_EFFECT_DISARM "disarm"
+#define ATTACK_EFFECT_BITE "bite"
+#define ATTACK_EFFECT_MECHFIRE "mech_fire"
+#define ATTACK_EFFECT_MECHTOXIN "mech_toxin"
+#define ATTACK_EFFECT_BOOP "boop" //Honk
+
//Embedded objects
#define EMBEDDED_PAIN_CHANCE 15 //Chance for embedded objects to cause pain (damage user)
#define EMBEDDED_ITEM_FALLOUT 5 //Chance for embedded object to fall out (causing pain but removing the object)
diff --git a/code/__DEFINES/math.dm b/code/__DEFINES/math.dm
index c6ffc61495e..3f360d5bad7 100644
--- a/code/__DEFINES/math.dm
+++ b/code/__DEFINES/math.dm
@@ -32,6 +32,8 @@
#define ToDegrees(radians) ((radians) * 57.2957795) // 180 / Pi
#define ToRadians(degrees) ((degrees) * 0.0174532925) // Pi / 180
+#define SHORT_REAL_LIMIT 16777216
+
//"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks
//percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio)
//collapsed to percent_of_tick_used * tick_lag
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 4f38a183a80..66eedbe5b33 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -344,5 +344,7 @@
//for obj explosion block calculation
#define EXPLOSION_BLOCK_PROC -1
+#define INVESTIGATE_BOMB "bombs"
+
// The SQL version required by this version of the code
#define SQL_VERSION 2
diff --git a/code/__DEFINES/qdel.dm b/code/__DEFINES/qdel.dm
index 14fd6ea0e36..8d504edaf41 100644
--- a/code/__DEFINES/qdel.dm
+++ b/code/__DEFINES/qdel.dm
@@ -22,11 +22,4 @@
#define QDELING(X) (X.gc_destroyed)
#define QDELETED(X) (!X || QDELING(X))
-#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
-
-/proc/check_datum_qdeleted(datum/D) //for checking if something is a datum, first, then checking gc_destroyed; get rid of this eventually. TO-DO
- if(!istype(D))
- return FALSE
- if(D.gc_destroyed)
- return TRUE
- return FALSE
\ No newline at end of file
+#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
\ No newline at end of file
diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm
index 257e12f4093..adb645fe112 100644
--- a/code/__DEFINES/role_preferences.dm
+++ b/code/__DEFINES/role_preferences.dm
@@ -40,6 +40,7 @@
#define ROLE_NYMPH "Dionaea"
#define ROLE_GSPIDER "giant spider"
#define ROLE_DRONE "drone"
+#define ROLE_DEATHSQUAD "deathsquad"
//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR.
//The gamemode specific ones are just so the gamemodes can query whether a player is old enough
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index 4b97b67e27e..0db57b27eae 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -31,6 +31,9 @@
/proc/cmp_subsystem_priority(datum/controller/subsystem/a, datum/controller/subsystem/b)
return a.priority - b.priority
+/proc/cmp_timer(datum/timedevent/a, datum/timedevent/b)
+ return a.timeToRun - b.timeToRun
+
/proc/cmp_qdel_item_time(datum/qdel_item/A, datum/qdel_item/B)
. = B.hard_delete_time - A.hard_delete_time
if(!.)
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 2004b9d3159..5c483b310fe 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -435,7 +435,7 @@
/proc/SecondsToTicks(var/seconds)
return seconds * 10
-proc/pollCandidates(Question, be_special_type, antag_age_check = 0, poll_time = 300, ignore_respawnability = 0, min_hours = 0, flashwindow = TRUE)
+proc/pollCandidates(Question, be_special_type, antag_age_check = 0, poll_time = 300, ignore_respawnability = 0, min_hours = 0, flashwindow = TRUE, check_antaghud = TRUE)
var/roletext = be_special_type ? get_roletext(be_special_type) : null
var/list/mob/dead/observer/candidates = list()
var/time_passed = world.time
@@ -457,7 +457,7 @@ proc/pollCandidates(Question, be_special_type, antag_age_check = 0, poll_time =
if(config.use_exp_restrictions && min_hours)
if(G.client.get_exp_living_num() < min_hours * 60)
continue
- if(cannotPossess(G))
+ if(check_antaghud && cannotPossess(G))
continue
spawn(0)
G << 'sound/misc/notice2.ogg'//Alerting them to their consideration
@@ -490,6 +490,20 @@ proc/pollCandidates(Question, be_special_type, antag_age_check = 0, poll_time =
return candidates
+/proc/pollCandidatesByKeyWithVeto(adminclient, adminusr, max_slots, Question, be_special_type, antag_age_check = 0, poll_time = 300, ignore_respawnability = 0, min_hours = 0, flashwindow = TRUE, check_antaghud = TRUE)
+ var/list/willing_ghosts = pollCandidates(Question, be_special_type, antag_age_check, poll_time, ignore_respawnability, min_hours, flashwindow, check_antaghud)
+ var/list/candidate_ckeys = list()
+ var/list/selected_ckeys = list()
+ if(!willing_ghosts.len)
+ return selected_ckeys
+ for(var/mob/dead/observer/G in willing_ghosts)
+ candidate_ckeys += G.key
+ for(var/i = max_slots, (i > 0 && candidate_ckeys.len), i--)
+ var/this_ckey = input("Pick players. This will go on until there either no more ghosts to pick from or the slots are full.", "Candidates") as null|anything in candidate_ckeys
+ candidate_ckeys -= this_ckey
+ selected_ckeys += this_ckey
+ return selected_ckeys
+
/proc/window_flash(client/C)
if(ismob(C))
var/mob/M = C
diff --git a/code/__HELPERS/qdel.dm b/code/__HELPERS/qdel.dm
index 8171dd66427..136e573a25e 100644
--- a/code/__HELPERS/qdel.dm
+++ b/code/__HELPERS/qdel.dm
@@ -1,5 +1,10 @@
-#define QDEL_IN(item, time) addtimer(GLOBAL_PROC, "qdel", time, FALSE, item)
+#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE)
+#define QDEL_IN_CLIENT_TIME(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE | TIMER_CLIENT_TIME)
#define QDEL_NULL(item) if(item) { qdel(item); item = null }
#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
+#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/______qdel_list_wrapper, L), time, TIMER_STOPPABLE)
#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); }
+
+/proc/______qdel_list_wrapper(list/L) //the underscores are to encourage people not to use this directly.
+ QDEL_LIST(L)
\ No newline at end of file
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index b58ea20dbae..20c707b38f7 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -394,6 +394,16 @@ Turf and target are seperate in case you want to teleport some distance from a t
moblist.Add(M)
return moblist
+// Format a power value in W, kW, MW, or GW.
+/proc/DisplayPower(powerused)
+ if(powerused < 1000) //Less than a kW
+ return "[powerused] W"
+ else if(powerused < 1000000) //Less than a MW
+ return "[round((powerused * 0.001), 0.01)] kW"
+ else if(powerused < 1000000000) //Less than a GW
+ return "[round((powerused * 0.000001), 0.001)] MW"
+ return "[round((powerused * 0.000000001), 0.0001)] GW"
+
//E = MC^2
/proc/convert2energy(var/M)
var/E = M*(SPEED_OF_LIGHT_SQ)
@@ -1928,4 +1938,7 @@ var/mob/dview/dview_mob = new
CRASH(msg)
/datum/proc/stack_trace(msg)
- CRASH(msg)
\ No newline at end of file
+ CRASH(msg)
+
+/proc/pass()
+ return
\ No newline at end of file
diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm
index 0cc712799c7..5a025702877 100644
--- a/code/_globalvars/lists/objects.dm
+++ b/code/_globalvars/lists/objects.dm
@@ -1,5 +1,5 @@
var/global/list/portals = list() //for use by portals
-var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time
+GLOBAL_LIST(cable_list) //Index for all cables, so that powernets don't have to look through the entire world all the time
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
var/global/list/chemical_reagents_list //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
var/global/list/landmarks_list = list() //list of all landmarks created
@@ -17,7 +17,6 @@ var/global/list/cell_logs = list()
var/global/list/all_areas = list()
var/global/list/machines = list()
-var/global/list/machine_processing = list()
var/global/list/fast_processing = list()
var/global/list/processing_power_items = list() //items that ask to be called every cycle
var/global/list/rcd_list = list() //list of Rapid Construction Devices.
diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm
index f96e83cb7a1..c48600ca40c 100644
--- a/code/_globalvars/logging.dm
+++ b/code/_globalvars/logging.dm
@@ -10,7 +10,6 @@ GLOBAL_VAR(world_href_log)
GLOBAL_PROTECT(world_href_log)
var/list/jobMax = list()
-var/list/bombers = list( )
var/list/admin_log = list ( )
var/list/lastsignalers = list( ) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
var/list/lawchanges = list( ) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
@@ -20,4 +19,4 @@ var/list/IClog = list()
var/list/OOClog = list()
var/list/adminlog = list()
-var/list/investigate_log_subjects = list("notes", "watchlist", "hrefs")
\ No newline at end of file
+var/list/investigate_log_subjects = list("notes", "watchlist", "hrefs")
diff --git a/code/_globalvars/station.dm b/code/_globalvars/station.dm
index 6d2578e5b88..2d635996b30 100644
--- a/code/_globalvars/station.dm
+++ b/code/_globalvars/station.dm
@@ -3,11 +3,4 @@ var/global/datum/datacore/data_core = null
var/CELLRATE = 0.002 // multiplier for watts per tick <> cell storage (eg: .002 means if there is a load of 1000 watts, 20 units will be taken from a cell per second)
var/CHARGELEVEL = 0.001 // Cap for how fast cells charge, as a percentage-per-tick (.001 means cellcharge is capped to 1% per second)
-var/list/powernets = list()
-var/list/deferred_powernet_rebuilds = list()
-
-// this is not strictly unused although the whole modules datum thing is unused
-// To remove this you need to remove that
-var/datum/moduletypes/mods = new()
-
var/map_name = "Unknown" //The name of the map that is loaded. Assigned in world/New()
\ No newline at end of file
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index f300608e699..9679935bdaa 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -70,6 +70,12 @@
changeNext_click(1)
var/list/modifiers = params2list(params)
+ if(modifiers["middle"] && modifiers["shift"] && modifiers["ctrl"])
+ MiddleShiftControlClickOn(A)
+ return
+ if(modifiers["middle"] && modifiers["shift"])
+ MiddleShiftClickOn(A)
+ return
if(modifiers["shift"] && modifiers["ctrl"])
CtrlShiftClickOn(A)
return
@@ -225,6 +231,32 @@
else
..()
+/*
+ Middle shift-click
+ Makes the mob face the direction of the clicked thing
+*/
+/mob/proc/MiddleShiftClickOn(atom/A)
+ var/face_dir = get_cardinal_dir(src, A)
+ if(forced_look == face_dir)
+ forced_look = null
+ to_chat(src, "You are no longer facing any direction.")
+ return
+ forced_look = face_dir
+ to_chat(src, "You are now facing [dir2text(forced_look)].")
+
+/*
+ Middle shift-control-click
+ Makes the mob constantly face the object (until it's out of sight)
+*/
+/mob/proc/MiddleShiftControlClickOn(atom/A)
+ var/face_uid = A.UID()
+ if(forced_look == face_uid)
+ forced_look = null
+ to_chat(src, "You are no longer facing [A].")
+ return
+ forced_look = face_uid
+ to_chat(src, "You are now facing [A].")
+
// In case of use break glass
/*
/atom/proc/MiddleClick(var/mob/M as mob)
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 6a658886f83..bf01bca6e3c 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -62,8 +62,7 @@
user.lastattacked = M
M.lastattacker = user
- if(user != M)
- user.do_attack_animation(M)
+ user.do_attack_animation(M)
M.attacked_by(src, user, def_zone)
add_attack_logs(user, M, "Attacked with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])", admin_notify = (force > 0 && damtype != STAMINA))
diff --git a/code/controllers/Processes/machinery.dm b/code/controllers/Processes/machinery.dm
deleted file mode 100644
index 2466f802740..00000000000
--- a/code/controllers/Processes/machinery.dm
+++ /dev/null
@@ -1,74 +0,0 @@
-/var/global/machinery_sort_required = 0
-
-/datum/controller/process/machinery/setup()
- name = "machinery"
- schedule_interval = 20 // every 2 seconds
- start_delay = 12
-
-/datum/controller/process/machinery/statProcess()
- ..()
- stat(null, "[machine_processing.len] machines")
- stat(null, "[powernets.len] powernets, [deferred_powernet_rebuilds.len] deferred")
-
-/datum/controller/process/machinery/doWork()
- process_sort()
- process_power()
- process_power_drain()
- process_machines()
-
-/datum/controller/process/machinery/proc/process_sort()
- if(machinery_sort_required)
- machinery_sort_required = 0
- machine_processing = dd_sortedObjectList(machine_processing)
-
-/datum/controller/process/machinery/proc/process_machines()
- for(last_object in machine_processing)
- var/obj/machinery/M = last_object
- if(istype(M) && !QDELETED(M))
- try
- if(M.process() == PROCESS_KILL)
- machine_processing.Remove(M)
- continue
-
- if(M.use_power)
- M.auto_use_power()
- catch(var/exception/e)
- catchException(e, M)
- else
- catchBadType(M)
- machine_processing -= M
-
- SCHECK
-
-/datum/controller/process/machinery/proc/process_power()
- for(last_object in deferred_powernet_rebuilds)
- var/obj/O = last_object
- if(istype(O) && !QDELETED(O))
- try
- var/datum/powernet/newPN = new()// creates a new powernet...
- propagate_network(O, newPN)//... and propagates it to the other side of the cable
- catch(var/exception/e)
- catchException(e, O)
- SCHECK
- else
- catchBadType(O)
- deferred_powernet_rebuilds -= O
-
- for(last_object in powernets)
- var/datum/powernet/powerNetwork = last_object
- if(istype(powerNetwork) && !QDELETED(powerNetwork))
- try
- powerNetwork.reset()
- catch(var/exception/e)
- catchException(e, powerNetwork)
- SCHECK
- else
- catchBadType(powerNetwork)
- powernets -= powerNetwork
-
-/datum/controller/process/machinery/proc/process_power_drain()
- // Currently only used by powersinks. These items get priority processed before machinery
- for(var/obj/item/I in processing_power_items)
- if(!I.pwr_drain()) // 0 = Process Kill, remove from processing list.
- processing_power_items.Remove(I)
- SCHECK
diff --git a/code/controllers/Processes/mob.dm b/code/controllers/Processes/mob.dm
deleted file mode 100644
index 2b11eff99be..00000000000
--- a/code/controllers/Processes/mob.dm
+++ /dev/null
@@ -1,35 +0,0 @@
-var/global/datum/controller/process/mob/mob_master
-
-/datum/controller/process/mob
- var/current_cycle
-
-/datum/controller/process/mob/setup()
- name = "mob"
- schedule_interval = 20 // every 2 seconds
- start_delay = 16
- log_startup_progress("Mob ticker starting up.")
-
-/datum/controller/process/mob/started()
- ..()
- if(!mob_list)
- mob_list = list()
-
-/datum/controller/process/mob/statProcess()
- ..()
- stat(null, "[mob_list.len] mobs")
-
-/datum/controller/process/mob/doWork()
- for(last_object in mob_list)
- var/mob/M = last_object
- if(istype(M) && !QDELETED(M))
- try
- M.Life()
- catch(var/exception/e)
- catchException(e, M)
- SCHECK
- else
- catchBadType(M)
- mob_list -= M
- current_cycle++
-
-DECLARE_GLOBAL_CONTROLLER(mob, mob_master)
diff --git a/code/controllers/Processes/nano_mob_hunter.dm b/code/controllers/Processes/nano_mob_hunter.dm
index fb57b6e0bbf..dc5dcba805b 100644
--- a/code/controllers/Processes/nano_mob_hunter.dm
+++ b/code/controllers/Processes/nano_mob_hunter.dm
@@ -44,7 +44,7 @@ DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
recover_time = 3000
if(recover_time > 0) //when provided with a negative or zero valued recover_time argument, the server won't auto-restart but can be manually rebooted still
//set a timer to automatically recover after recover_time has passed (can be manually restarted if you get impatient too)
- addtimer(src, "auto_recover", recover_time, TRUE)
+ addtimer(CALLBACK(src, .proc/auto_recover), recover_time, TIMER_UNIQUE)
/datum/controller/process/mob_hunt/proc/client_mob_update()
var/list/ex_players = list()
diff --git a/code/controllers/Processes/timer.dm b/code/controllers/Processes/timer.dm
deleted file mode 100644
index 4b42d69221d..00000000000
--- a/code/controllers/Processes/timer.dm
+++ /dev/null
@@ -1,100 +0,0 @@
-var/global/datum/controller/process/timer/timer_master
-
-/datum/controller/process/timer
- var/list/processing_timers = list()
- var/list/hashes = list()
-
-/datum/controller/process/timer/setup()
- name = "timer"
- schedule_interval = 1 //every 0.1 seconds--2 server ticks
- log_startup_progress("Timer process starting up.")
-
-/datum/controller/process/timer/statProcess()
- ..()
- stat(null, "[processing_timers.len] timers")
-
-/datum/controller/process/timer/doWork()
- if(!processing_timers.len)
- disabled = 1 //nothing to do, lets stop firing.
- return
- for(last_object in processing_timers)
- var/datum/timedevent/event = last_object
- if(!event.thingToCall || check_datum_qdeleted(event.thingToCall))
- qdel(event)
- if(event.timeToRun <= world.time)
- runevent(event)
- qdel(event)
- SCHECK
-
-DECLARE_GLOBAL_CONTROLLER(timer, timer_master)
-
-/datum/controller/process/timer/proc/runevent(datum/timedevent/event)
- set waitfor = 0
- if(event.thingToCall)
- if(event.thingToCall == GLOBAL_PROC && istext(event.procToCall))
- call("/proc/[event.procToCall]")(arglist(event.argList))
- else
- call(event.thingToCall, event.procToCall)(arglist(event.argList))
-
-/datum/timedevent
- var/thingToCall
- var/procToCall
- var/timeToRun
- var/argList
- var/id
- var/hash
- var/static/nextid = 1
-
-/datum/timedevent/New()
- id = nextid++
-
-/datum/timedevent/Destroy()
- timer_master.processing_timers -= src
- timer_master.hashes -= hash
- return QDEL_HINT_IWILLGC
-
-/proc/addtimer(thingToCall, procToCall, wait, unique = FALSE, ...)
- if(!timer_master) //can't run timers before the mc has been created
- return
- if(!thingToCall || !procToCall)
- return
- if(timer_master.disabled)
- timer_master.disabled = 0
-
- var/datum/timedevent/event = new()
- event.thingToCall = thingToCall
- event.procToCall = procToCall
- event.timeToRun = world.time + wait
- var/hashlist = args.Copy()
-
- hashlist[1] = "[thingToCall](\ref[thingToCall])"
- event.hash = jointext(hashlist, null)
- if(args.len > 4)
- event.argList = args.Copy(5)
-
- // Check for dupes if unique = 1.
- if(unique)
- var/datum/timedevent/hash_event = timer_master.hashes[event.hash]
- if(hash_event)
- return hash_event.id
- timer_master.hashes[event.hash] = event
- if(wait <= 0)
- timer_master.runevent(event)
- timer_master.hashes -= event.hash
- return
- // If we are unique (or we're not checking that), add the timer and return the id.
- timer_master.processing_timers += event
-
- return event.id
-
-/proc/deltimer(id)
- if(id == 0)
- // No event will correspond to an id of 0 - the timer does not exist
- // Save us a possibly expensive iteration through the timer list
- // This would probably be more efficient in general if we used an associative list instead
- return 0
- for(var/datum/timedevent/event in timer_master.processing_timers)
- if(event.id == id)
- qdel(event)
- return 1
- return 0
diff --git a/code/controllers/Processes/weather.dm b/code/controllers/Processes/weather.dm
index 1706b2232c0..919352313c6 100644
--- a/code/controllers/Processes/weather.dm
+++ b/code/controllers/Processes/weather.dm
@@ -37,7 +37,7 @@ var/global/datum/controller/process/weather/weather_master
var/datum/weather/W = pickweight(possible_weather_for_this_z)
run_weather(W.name)
eligible_zlevels -= Z
- addtimer(src, "make_z_eligible", rand(3000, 6000) + W.weather_duration_upper, TRUE, Z) //Around 5-10 minutes between weathers
+ addtimer(CALLBACK(src, .proc/make_z_eligible, Z), rand(3000, 6000) + W.weather_duration_upper, TIMER_UNIQUE) //Around 5-10 minutes between weathers
DECLARE_GLOBAL_CONTROLLER(weather, weather_master)
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index b71531ee20f..b35bc300434 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -202,6 +202,9 @@
var/randomize_shift_time = FALSE
var/enable_night_shifts = FALSE
+ // Developer
+ var/developer_express_start = 0
+
/datum/configuration/New()
for(var/T in subtypesof(/datum/game_mode))
var/datum/game_mode/M = T
@@ -612,6 +615,8 @@
config.high_pop_mc_mode_amount = text2num(value)
if("disable_high_pop_mc_mode_amount")
config.disable_high_pop_mc_mode_amount = text2num(value)
+ if("developer_express_start")
+ config.developer_express_start = 1
else
log_config("Unknown setting in configuration: '[name]'")
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index ddde5460cef..9cb84f26aa5 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -54,7 +54,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/static/restart_clear = 0
var/static/restart_timeout = 0
var/static/restart_count = 0
-
+
var/static/random_seed
//current tick limit, assigned before running a subsystem.
@@ -62,7 +62,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/static/current_ticklimit = TICK_LIMIT_RUNNING
/datum/controller/master/New()
- makeDatumRefLists()
//temporary file used to record errors with loading config, moved to log directory once logging is set up
GLOB.config_error_log = GLOB.world_game_log = GLOB.world_runtime_log = "data/logs/config_error.log"
load_configuration()
@@ -71,7 +70,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
if(!random_seed)
random_seed = rand(1, 1e9)
rand_seed(random_seed)
-
+
var/list/_subsystems = list()
subsystems = _subsystems
if(Master != src)
@@ -195,6 +194,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
to_chat(world, "[msg]")
log_world(msg)
+ if(config.developer_express_start & ticker.current_state == GAME_STATE_PREGAME)
+ ticker.current_state = GAME_STATE_SETTING_UP
+
if(!current_runlevel)
SetRunLevel(1)
diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index 11cd37343fe..7606149c39d 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -56,8 +56,7 @@ var/global/pipe_processing_killed = 0
space_manager.do_transition_setup()
- setup_objects()
- setupgenetics()
+ setup_asset_cache()
setupfactions()
setup_economy()
@@ -66,20 +65,8 @@ var/global/pipe_processing_killed = 0
populate_spawn_points()
-/datum/controller/game_controller/proc/setup_objects()
+/datum/controller/game_controller/proc/setup_asset_cache()
var/watch = start_watch()
- var/count = 0
- var/overwatch = start_watch() // Overall.
-
log_startup_progress("Populating asset cache...")
populate_asset_cache()
- log_startup_progress(" Populated [asset_cache.len] assets in [stop_watch(watch)]s.")
-
- watch = start_watch()
- log_startup_progress("Initializing objects...")
- for(var/atom/movable/object in world)
- object.initialize()
- count++
- log_startup_progress(" Initialized [count] objects in [stop_watch(watch)]s.")
-
- log_startup_progress("Finished object initializations in [stop_watch(overwatch)]s.")
+ log_startup_progress(" Populated [asset_cache.len] assets in [stop_watch(watch)]s.")
\ No newline at end of file
diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm
index 4b1d59fa82e..b2b0e63d99b 100644
--- a/code/controllers/subsystem.dm
+++ b/code/controllers/subsystem.dm
@@ -171,7 +171,7 @@
statclick = new/obj/effect/statclick/debug(src, "Initializing...")
if(can_fire && !(SS_NO_FIRE & flags))
- msg = "[round(cost, 1)]ms|[round(tick_usage, 1)]%([round(tick_overrun, 1)]%)|[round(ticks, 0.1)]\t[msg]"
+ msg = "[round(cost, 1)]ms | [round(tick_usage, 1)]%([round(tick_overrun, 1)]%) | [round(ticks, 0.1)]\t[msg]"
else
msg = "OFFLINE\t[msg]"
diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm
index bf791e61519..4c2774d58db 100644
--- a/code/controllers/subsystem/air.dm
+++ b/code/controllers/subsystem/air.dm
@@ -320,15 +320,15 @@ SUBSYSTEM_DEF(air)
var/watch = start_watch()
var/count = 0
log_startup_progress("Initializing atmospherics machinery...")
- for(var/obj/machinery/atmospherics/unary/U in machines)
- if(istype(U, /obj/machinery/atmospherics/unary/vent_pump))
- var/obj/machinery/atmospherics/unary/vent_pump/T = U
+ for(var/obj/machinery/atmospherics/A in machines)
+ A.atmos_init()
+ count++
+ if(istype(A, /obj/machinery/atmospherics/unary/vent_pump))
+ var/obj/machinery/atmospherics/unary/vent_pump/T = A
T.broadcast_status()
- count++
- else if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber))
- var/obj/machinery/atmospherics/unary/vent_scrubber/T = U
+ else if(istype(A, /obj/machinery/atmospherics/unary/vent_scrubber))
+ var/obj/machinery/atmospherics/unary/vent_scrubber/T = A
T.broadcast_status()
- count++
log_startup_progress(" Initialized [count] atmospherics machines in [stop_watch(watch)]s.")
//this can't be done with setup_atmos_machinery() because
@@ -341,7 +341,7 @@ SUBSYSTEM_DEF(air)
for(var/obj/machinery/atmospherics/machine in machines)
machine.build_network()
count++
- log_startup_progress(" Initialized [count] pipes in [stop_watch(watch)]s.")
+ log_startup_progress(" Initialized [count] pipenets in [stop_watch(watch)]s.")
/datum/controller/subsystem/air/proc/setup_overlays()
plmaster = new /obj/effect/overlay()
diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm
new file mode 100644
index 00000000000..c3943ea9163
--- /dev/null
+++ b/code/controllers/subsystem/atoms.dm
@@ -0,0 +1,120 @@
+#define BAD_INIT_QDEL_BEFORE 1
+#define BAD_INIT_DIDNT_INIT 2
+#define BAD_INIT_SLEPT 4
+#define BAD_INIT_NO_HINT 8
+
+SUBSYSTEM_DEF(atoms)
+ name = "Atoms"
+ init_order = INIT_ORDER_ATOMS
+ flags = SS_NO_FIRE
+
+ var/old_initialized
+
+ var/list/late_loaders
+ var/list/created_atoms
+
+ var/list/BadInitializeCalls = list()
+
+
+/datum/controller/subsystem/atoms/Initialize(timeofday)
+ setupgenetics()
+ initialized = INITIALIZATION_INNEW_MAPLOAD
+ InitializeAtoms()
+
+
+
+/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms)
+ if(initialized == INITIALIZATION_INSSATOMS)
+ return
+
+ initialized = INITIALIZATION_INNEW_MAPLOAD
+
+ LAZYINITLIST(late_loaders)
+
+ var/watch = start_watch()
+ log_startup_progress("Initializing atoms...")
+ var/count
+ var/list/mapload_arg = list(TRUE)
+ if(atoms)
+ created_atoms = list()
+ count = atoms.len
+ for(var/I in atoms)
+ var/atom/A = I
+ if(!A.initialized)
+ if(InitAtom(I, mapload_arg))
+ atoms -= I
+ CHECK_TICK
+ else
+ count = 0
+ for(var/atom/A in world)
+ if(!A.initialized)
+ InitAtom(A, mapload_arg)
+ ++count
+ CHECK_TICK
+
+ log_startup_progress(" Initialized [count] atoms in [stop_watch(watch)]s")
+ pass(count)
+
+ initialized = INITIALIZATION_INNEW_REGULAR
+
+ if(late_loaders.len)
+ watch = start_watch()
+ log_startup_progress("Late-initializing atoms...")
+ for(var/I in late_loaders)
+ var/atom/A = I
+ A.LateInitialize()
+ log_startup_progress(" Late initialized [late_loaders.len] atoms in [stop_watch(watch)]s")
+ late_loaders.Cut()
+
+ if(atoms)
+ . = created_atoms + atoms
+ created_atoms = null
+
+/datum/controller/subsystem/atoms/proc/InitAtom(atom/A, list/arguments)
+ var/the_type = A.type
+ if(QDELING(A))
+ BadInitializeCalls[the_type] |= BAD_INIT_QDEL_BEFORE
+ return TRUE
+
+ var/start_tick = world.time
+
+ var/result = A.Initialize(arglist(arguments))
+
+ if(start_tick != world.time)
+ BadInitializeCalls[the_type] |= BAD_INIT_SLEPT
+
+ var/qdeleted = FALSE
+
+ if(result != INITIALIZE_HINT_NORMAL)
+ switch(result)
+ if(INITIALIZE_HINT_LATELOAD)
+ if(arguments[1]) //mapload
+ late_loaders += A
+ else
+ A.LateInitialize()
+ if(INITIALIZE_HINT_QDEL)
+ qdel(A)
+ qdeleted = TRUE
+ else
+ BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT
+
+ if(!A) //possible harddel
+ qdeleted = TRUE
+ else if(!A.initialized)
+ BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT
+
+ return qdeleted || QDELING(A)
+
+/datum/controller/subsystem/atoms/proc/map_loader_begin()
+ old_initialized = initialized
+ initialized = INITIALIZATION_INSSATOMS
+
+/datum/controller/subsystem/atoms/proc/map_loader_stop()
+ initialized = old_initialized
+
+/datum/controller/subsystem/atoms/Recover()
+ initialized = SSatoms.initialized
+ if(initialized == INITIALIZATION_INNEW_MAPLOAD)
+ InitializeAtoms()
+ old_initialized = SSatoms.old_initialized
+ BadInitializeCalls = SSatoms.BadInitializeCalls
\ No newline at end of file
diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm
index 067114e52be..823294e4d4e 100644
--- a/code/controllers/subsystem/garbage.dm
+++ b/code/controllers/subsystem/garbage.dm
@@ -43,20 +43,20 @@ SUBSYSTEM_DEF(garbage)
var/list/counts = list()
for(var/list/L in queues)
counts += length(L)
- msg += "Q:[counts.Join(",")]|D:[delslasttick]|G:[gcedlasttick]|"
+ msg += "Queue:[counts.Join(",")] | Del's:[delslasttick] | Soft:[gcedlasttick] |"
msg += "GR:"
if(!(delslasttick + gcedlasttick))
msg += "n/a|"
else
- msg += "[round((gcedlasttick / (delslasttick + gcedlasttick)) * 100, 0.01)]%|"
+ msg += "[round((gcedlasttick / (delslasttick + gcedlasttick)) * 100, 0.01)]% |"
- msg += "TD:[totaldels]|TG:[totalgcs]|"
+ msg += "Total Dels:[totaldels] | Soft:[totalgcs] |"
if(!(totaldels + totalgcs))
msg += "n/a|"
else
- msg += "TGR:[round((totalgcs / (totaldels + totalgcs)) * 100, 0.01)]%"
- msg += " P:[pass_counts.Join(",")]"
- msg += "|F:[fail_counts.Join(",")]"
+ msg += "TGR:[round((totalgcs / (totaldels + totalgcs)) * 100, 0.01)]% |"
+ msg += " Pass:[pass_counts.Join(",")]"
+ msg += " | Fail:[fail_counts.Join(",")]"
..(msg)
/* TO-DO
diff --git a/code/controllers/subsystem/machinery.dm b/code/controllers/subsystem/machinery.dm
new file mode 100644
index 00000000000..a3e4d4bdb0c
--- /dev/null
+++ b/code/controllers/subsystem/machinery.dm
@@ -0,0 +1,145 @@
+#define SSMACHINES_DEFERREDPOWERNETS 1
+#define SSMACHINES_POWERNETS 2
+#define SSMACHINES_PREMACHINERY 3
+#define SSMACHINES_MACHINERY 4
+SUBSYSTEM_DEF(machines)
+ name = "Machines"
+ init_order = INIT_ORDER_MACHINES
+ flags = SS_KEEP_TIMING
+
+ var/list/processing = list()
+ var/list/currentrun = list()
+ var/list/powernets = list()
+ var/list/deferred_powernet_rebuilds = list()
+
+ var/currentpart = SSMACHINES_DEFERREDPOWERNETS
+
+/datum/controller/subsystem/machines/Initialize()
+ makepowernets()
+ fire()
+ ..()
+
+/datum/controller/subsystem/machines/proc/makepowernets()
+ for(var/datum/powernet/PN in powernets)
+ qdel(PN)
+ powernets.Cut()
+
+ for(var/obj/structure/cable/PC in GLOB.cable_list)
+ if(!PC.powernet)
+ var/datum/powernet/NewPN = new()
+ NewPN.add_cable(PC)
+ propagate_network(PC,PC.powernet)
+
+/datum/controller/subsystem/machines/stat_entry()
+ ..("Machines: [processing.len]\nPowernets: [powernets.len]\tDeferred: [deferred_powernet_rebuilds.len]")
+
+/datum/controller/subsystem/machines/proc/process_defered_powernets(resumed = 0)
+ if(!resumed)
+ src.currentrun = deferred_powernet_rebuilds.Copy()
+ //cache for sanid speed (lists are references anyways)
+ var/list/currentrun = src.currentrun
+ while(currentrun.len)
+ var/obj/O = currentrun[currentrun.len]
+ currentrun.len--
+ if(O)
+ var/datum/powernet/newPN = new() // create a new powernet...
+ propagate_network(O, newPN)//... and propagate it to the other side of the cable
+
+ deferred_powernet_rebuilds.Remove(O)
+ if(MC_TICK_CHECK)
+ return
+
+/datum/controller/subsystem/machines/proc/process_powernets(resumed = 0)
+ if(!resumed)
+ src.currentrun = powernets.Copy()
+ //cache for sanid speed (lists are references anyways)
+ var/list/currentrun = src.currentrun
+ while(currentrun.len)
+ var/datum/powernet/P = currentrun[currentrun.len]
+ currentrun.len--
+ if(P)
+ P.reset() // reset the power state
+ else
+ powernets.Remove(P)
+ if(MC_TICK_CHECK)
+ return
+
+/datum/controller/subsystem/machines/proc/process_premachines(resumed = 0)
+ /* Literally exists as snowflake for fucking powersinks goddamnit */
+ if(!resumed)
+ src.currentrun = processing_power_items.Copy()
+ //cache for sanid speed (lists are references anyways)
+ var/list/currentrun = src.currentrun
+ while(currentrun.len)
+ var/obj/item/I = currentrun[currentrun.len]
+ currentrun.len--
+ if(!QDELETED(I))
+ if(!I.pwr_drain())
+ processing_power_items.Remove(I)
+ else
+ processing_power_items.Remove(I)
+ if(MC_TICK_CHECK)
+ return
+
+/datum/controller/subsystem/machines/proc/process_machines(resumed = 0)
+ var/seconds = wait * 0.1
+ if(!resumed)
+ src.currentrun = processing.Copy()
+ //cache for sanic speed (lists are references anyways)
+ var/list/currentrun = src.currentrun
+ while(currentrun.len)
+ var/obj/machinery/thing = currentrun[currentrun.len]
+ currentrun.len--
+ if(!QDELETED(thing) && thing.process(seconds) != PROCESS_KILL)
+ if(thing.use_power)
+ thing.auto_use_power() //add back the power state
+ else
+ processing -= thing
+ if(!QDELETED(thing))
+ thing.isprocessing = FALSE
+ if(MC_TICK_CHECK)
+ return
+
+/datum/controller/subsystem/machines/fire(resumed = 0)
+ if(currentpart == SSMACHINES_DEFERREDPOWERNETS || !resumed)
+ process_defered_powernets(resumed)
+ if(state != SS_RUNNING)
+ return
+ resumed = 0
+ currentpart = SSMACHINES_POWERNETS
+
+ if(currentpart == SSMACHINES_POWERNETS || !resumed)
+ process_powernets(resumed)
+ if(state != SS_RUNNING)
+ return
+ resumed = 0
+ currentpart = SSMACHINES_PREMACHINERY
+
+ if(currentpart == SSMACHINES_PREMACHINERY || !resumed)
+ process_premachines(resumed)
+ if(state != SS_RUNNING)
+ return
+ resumed = 0
+ currentpart = SSMACHINES_MACHINERY
+
+ if(currentpart == SSMACHINES_MACHINERY || !resumed)
+ process_machines(resumed)
+ if(state != SS_RUNNING)
+ return
+ resumed = 0
+ currentpart = SSMACHINES_DEFERREDPOWERNETS
+
+
+/datum/controller/subsystem/machines/proc/setup_template_powernets(list/cables)
+ for(var/A in cables)
+ var/obj/structure/cable/PC = A
+ if(!PC.powernet)
+ var/datum/powernet/NewPN = new()
+ NewPN.add_cable(PC)
+ propagate_network(PC,PC.powernet)
+
+/datum/controller/subsystem/machines/Recover()
+ if(istype(SSmachines.processing))
+ processing = SSmachines.processing
+ if(istype(SSmachines.powernets))
+ powernets = SSmachines.powernets
diff --git a/code/controllers/subsystem/mobs.dm b/code/controllers/subsystem/mobs.dm
new file mode 100644
index 00000000000..03989d24af2
--- /dev/null
+++ b/code/controllers/subsystem/mobs.dm
@@ -0,0 +1,28 @@
+SUBSYSTEM_DEF(mobs)
+ name = "Mobs"
+ priority = FIRE_PRIORITY_MOBS
+ flags = SS_KEEP_TIMING | SS_NO_INIT
+ runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
+
+ var/list/currentrun = list()
+
+/datum/controller/subsystem/mobs/stat_entry()
+ ..("P:[mob_list.len]")
+
+/datum/controller/subsystem/mobs/fire(resumed = 0)
+ var/seconds = wait * 0.1
+ if(!resumed)
+ src.currentrun = mob_list.Copy()
+
+ //cache for sanic speed (lists are references anyways)
+ var/list/currentrun = src.currentrun
+ var/times_fired = src.times_fired
+ while(currentrun.len)
+ var/mob/M = currentrun[currentrun.len]
+ currentrun.len--
+ if(M)
+ M.Life(seconds, times_fired)
+ else
+ mob_list.Remove(M)
+ if(MC_TICK_CHECK)
+ return
\ No newline at end of file
diff --git a/code/controllers/subsystem/processing/processing.dm b/code/controllers/subsystem/processing/processing.dm
new file mode 100644
index 00000000000..92254454219
--- /dev/null
+++ b/code/controllers/subsystem/processing/processing.dm
@@ -0,0 +1,38 @@
+//Used to process objects. Fires once every second.
+
+//TODO: Implement fully when process scheduler dies
+/*
+SUBSYSTEM_DEF(processing)
+ name = "Processing"
+ priority = FIRE_PRIORITY_PROCESS
+ flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT
+ wait = 10
+
+ var/stat_tag = "P" //Used for logging
+ var/list/processing = list()
+ var/list/currentrun = list()
+
+/datum/controller/subsystem/processing/stat_entry()
+ ..("[stat_tag]:[processing.len]")
+
+/datum/controller/subsystem/processing/fire(resumed = 0)
+ if (!resumed)
+ currentrun = processing.Copy()
+ //cache for sanic speed (lists are references anyways)
+ var/list/current_run = currentrun
+
+ while(current_run.len)
+ var/datum/thing = current_run[current_run.len]
+ current_run.len--
+ if(QDELETED(thing) || thing.process(wait) == PROCESS_KILL)
+ processing -= thing
+ if (MC_TICK_CHECK)
+ return
+*/
+/datum/var/isprocessing = FALSE
+/*
+/datum/proc/process()
+ set waitfor = 0
+ STOP_PROCESSING(SSobj, src)
+ return 0
+*/
\ No newline at end of file
diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm
new file mode 100644
index 00000000000..21fea2ee419
--- /dev/null
+++ b/code/controllers/subsystem/timer.dm
@@ -0,0 +1,518 @@
+#define BUCKET_LEN (world.fps*1*60) //how many ticks should we keep in the bucket. (1 minutes worth)
+#define BUCKET_POS(timer) ((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag) % BUCKET_LEN) + 1)
+#define TIMER_MAX (world.time + TICKS2DS(min(BUCKET_LEN-(SStimer.practical_offset-DS2TICKS(world.time - SStimer.head_offset))-1, BUCKET_LEN-1)))
+#define TIMER_ID_MAX (2**24) //max float with integer precision
+
+SUBSYSTEM_DEF(timer)
+ name = "Timer"
+ wait = 1 //SS_TICKER subsystem, so wait is in ticks
+ init_order = INIT_ORDER_TIMER
+
+ flags = SS_TICKER|SS_NO_INIT
+
+ var/list/second_queue = list() //awe, yes, you've had first queue, but what about second queue? Contains: /datum/timedevent
+ var/list/hashes = list()
+
+ var/head_offset = 0 //world.time of the first entry in the the bucket.
+ var/practical_offset = 1 //index of the first non-empty item in the bucket.
+ var/bucket_resolution = 0 //world.tick_lag the bucket was designed for
+ var/bucket_count = 0 //how many timers are in the buckets
+
+ var/list/bucket_list = list() //list of buckets, each bucket holds every timer that has to run that byond tick.
+
+ var/list/timer_id_dict = list() //list of all active timers assoicated to their timer id (for easy lookup)
+
+ var/list/clienttime_timers = list() //special snowflake timers that run on fancy pansy "client time"
+
+ var/last_invoke_tick = 0
+ var/static/last_invoke_warning = 0
+ var/static/bucket_auto_reset = TRUE
+
+/datum/controller/subsystem/timer/PreInit()
+ bucket_list.len = BUCKET_LEN
+ head_offset = world.time
+ bucket_resolution = world.tick_lag
+
+/datum/controller/subsystem/timer/stat_entry(msg)
+ ..("B:[bucket_count] P:[length(second_queue)] H:[length(hashes)] C:[length(clienttime_timers)] S:[length(timer_id_dict)]")
+
+/datum/controller/subsystem/timer/fire(resumed = FALSE)
+ var/lit = last_invoke_tick
+ var/last_check = world.time - TIMER_NO_INVOKE_WARNING
+ var/list/bucket_list = src.bucket_list
+
+ if(!bucket_count)
+ last_invoke_tick = world.time
+
+ if(lit && lit < last_check && last_invoke_warning < last_check)
+ last_invoke_warning = world.time
+ var/msg = "No regular timers processed in the last [TIMER_NO_INVOKE_WARNING] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!"
+ message_admins(msg)
+ WARNING(msg)
+ if(bucket_auto_reset)
+ bucket_resolution = 0
+
+ log_world("Timer bucket reset. world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
+ for(var/i in 1 to length(bucket_list))
+ var/datum/timedevent/bucket_head = bucket_list[i]
+ if(!bucket_head)
+ continue
+
+ log_world("Active timers at index [i]:")
+
+ var/datum/timedevent/bucket_node = bucket_head
+ var/anti_loop_check = 1000
+ do
+ log_world(get_timer_debug_string(bucket_node))
+ bucket_node = bucket_node.next
+ anti_loop_check--
+ while(bucket_node && bucket_node != bucket_head && anti_loop_check)
+ log_world("Active timers in the second_queue queue:")
+ for(var/I in second_queue)
+ log_world(get_timer_debug_string(I))
+
+ var/next_clienttime_timer_index = 0
+ var/len = length(clienttime_timers)
+
+ for(next_clienttime_timer_index in 1 to len)
+ if(MC_TICK_CHECK)
+ next_clienttime_timer_index--
+ break
+ var/datum/timedevent/ctime_timer = clienttime_timers[next_clienttime_timer_index]
+ if(ctime_timer.timeToRun > REALTIMEOFDAY)
+ next_clienttime_timer_index--
+ break
+
+ var/datum/callback/callBack = ctime_timer.callBack
+ if(!callBack)
+ clienttime_timers.Cut(next_clienttime_timer_index,next_clienttime_timer_index+1)
+ CRASH("Invalid timer: [get_timer_debug_string(ctime_timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset], REALTIMEOFDAY: [REALTIMEOFDAY]")
+
+ ctime_timer.spent = REALTIMEOFDAY
+ callBack.InvokeAsync()
+ qdel(ctime_timer)
+
+
+ if(next_clienttime_timer_index)
+ clienttime_timers.Cut(1,next_clienttime_timer_index+1)
+
+ if(MC_TICK_CHECK)
+ return
+
+ var/static/list/spent = list()
+ var/static/datum/timedevent/timer
+ if(practical_offset > BUCKET_LEN)
+ head_offset += TICKS2DS(BUCKET_LEN)
+ practical_offset = 1
+ resumed = FALSE
+
+ if((length(bucket_list) != BUCKET_LEN) || (world.tick_lag != bucket_resolution))
+ reset_buckets()
+ bucket_list = src.bucket_list
+ resumed = FALSE
+
+
+ if(!resumed)
+ timer = null
+
+ while(practical_offset <= BUCKET_LEN && head_offset + (practical_offset*world.tick_lag) <= world.time)
+ var/datum/timedevent/head = bucket_list[practical_offset]
+ if(!timer || !head || timer == head)
+ head = bucket_list[practical_offset]
+ timer = head
+ while(timer)
+ var/datum/callback/callBack = timer.callBack
+ if(!callBack)
+ bucket_resolution = null //force bucket recreation
+ CRASH("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
+
+ if(!timer.spent)
+ spent += timer
+ timer.spent = world.time
+ callBack.InvokeAsync()
+ last_invoke_tick = world.time
+
+ if(MC_TICK_CHECK)
+ return
+
+ timer = timer.next
+ if(timer == head)
+ break
+
+
+ bucket_list[practical_offset++] = null
+
+ //we freed up a bucket, lets see if anything in second_queue needs to be shifted to that bucket.
+ var/i = 0
+ var/L = length(second_queue)
+ for(i in 1 to L)
+ timer = second_queue[i]
+ if(timer.timeToRun >= TIMER_MAX)
+ i--
+ break
+
+ if(timer.timeToRun < head_offset)
+ bucket_resolution = null //force bucket recreation
+ CRASH("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
+
+ if(timer.callBack && !timer.spent)
+ timer.callBack.InvokeAsync()
+ spent += timer
+ bucket_count++
+ else if(!QDELETED(timer))
+ qdel(timer)
+ continue
+
+ if(timer.timeToRun < head_offset + TICKS2DS(practical_offset))
+ bucket_resolution = null //force bucket recreation
+ CRASH("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
+ if(timer.callBack && !timer.spent)
+ timer.callBack.InvokeAsync()
+ spent += timer
+ bucket_count++
+ else if(!QDELETED(timer))
+ qdel(timer)
+ continue
+
+ bucket_count++
+ var/bucket_pos = max(1, BUCKET_POS(timer))
+
+ var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
+ if(!bucket_head)
+ bucket_list[bucket_pos] = timer
+ timer.next = null
+ timer.prev = null
+ continue
+
+ if(!bucket_head.prev)
+ bucket_head.prev = bucket_head
+ timer.next = bucket_head
+ timer.prev = bucket_head.prev
+ timer.next.prev = timer
+ timer.prev.next = timer
+ if(i)
+ second_queue.Cut(1, i+1)
+
+ timer = null
+
+ bucket_count -= length(spent)
+
+ for(var/spent_timer in spent)
+ qdel(spent_timer)
+
+ spent.len = 0
+
+//formated this way to be runtime resistant
+/datum/controller/subsystem/timer/proc/get_timer_debug_string(datum/timedevent/TE)
+ . = "Timer: [TE]"
+ . += "Prev: [TE.prev ? TE.prev : "NULL"], Next: [TE.next ? TE.next : "NULL"]"
+ if(TE.spent)
+ . += ", SPENT([TE.spent])"
+ if(QDELETED(TE))
+ . += ", QDELETED"
+ if(!TE.callBack)
+ . += ", NO CALLBACK"
+
+/datum/controller/subsystem/timer/proc/reset_buckets()
+ var/list/bucket_list = src.bucket_list
+ var/list/alltimers = list()
+ //collect the timers currently in the bucket
+ for(var/bucket_head in bucket_list)
+ if(!bucket_head)
+ continue
+ var/datum/timedevent/bucket_node = bucket_head
+ do
+ alltimers += bucket_node
+ bucket_node = bucket_node.next
+ while(bucket_node && bucket_node != bucket_head)
+
+ bucket_list.len = 0
+ bucket_list.len = BUCKET_LEN
+
+ practical_offset = 1
+ bucket_count = 0
+ head_offset = world.time
+ bucket_resolution = world.tick_lag
+
+ alltimers += second_queue
+ if(!length(alltimers))
+ return
+
+ sortTim(alltimers, .proc/cmp_timer)
+
+ var/datum/timedevent/head = alltimers[1]
+
+ if(head.timeToRun < head_offset)
+ head_offset = head.timeToRun
+
+ var/new_bucket_count
+ var/i = 1
+ for(i in 1 to length(alltimers))
+ var/datum/timedevent/timer = alltimers[1]
+ if(!timer)
+ continue
+
+ var/bucket_pos = BUCKET_POS(timer)
+ if(timer.timeToRun >= TIMER_MAX)
+ i--
+ break
+
+
+ if(!timer.callBack || timer.spent)
+ WARNING("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
+ if(timer.callBack)
+ qdel(timer)
+ continue
+
+ new_bucket_count++
+ var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
+ if(!bucket_head)
+ bucket_list[bucket_pos] = timer
+ timer.next = null
+ timer.prev = null
+ continue
+
+ if(!bucket_head.prev)
+ bucket_head.prev = bucket_head
+ timer.next = bucket_head
+ timer.prev = bucket_head.prev
+ timer.next.prev = timer
+ timer.prev.next = timer
+ if(i)
+ alltimers.Cut(1, i+1)
+ second_queue = alltimers
+ bucket_count = new_bucket_count
+
+
+/datum/controller/subsystem/timer/Recover()
+ second_queue |= SStimer.second_queue
+ hashes |= SStimer.hashes
+ timer_id_dict |= SStimer.timer_id_dict
+ bucket_list |= SStimer.bucket_list
+
+/datum/timedevent
+ var/id
+ var/datum/callback/callBack
+ var/timeToRun
+ var/hash
+ var/list/flags
+ var/spent = 0 //time we ran the timer.
+ var/name //for easy debugging.
+ //cicular doublely linked list
+ var/datum/timedevent/next
+ var/datum/timedevent/prev
+
+/datum/timedevent/New(datum/callback/callBack, timeToRun, flags, hash)
+ var/static/nextid = 1
+ id = TIMER_ID_NULL
+ src.callBack = callBack
+ src.timeToRun = timeToRun
+ src.flags = flags
+ src.hash = hash
+
+ if(flags & TIMER_UNIQUE)
+ SStimer.hashes[hash] = src
+
+ if(flags & TIMER_STOPPABLE)
+ id = num2text(nextid, 100)
+ if(nextid >= SHORT_REAL_LIMIT)
+ nextid += min(1, 2**round(nextid/SHORT_REAL_LIMIT))
+ else
+ nextid++
+ SStimer.timer_id_dict[id] = src
+
+ name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])"
+
+ if((timeToRun < world.time || timeToRun < SStimer.head_offset) && !(flags & TIMER_CLIENT_TIME))
+ CRASH("Invalid timer state: Timer created that would require a backtrack to run (addtimer would never let this happen): [SStimer.get_timer_debug_string(src)]")
+
+ if(callBack.object != GLOBAL_PROC)
+ LAZYADD(callBack.object.active_timers, src)
+
+
+ var/list/L
+
+ if(flags & TIMER_CLIENT_TIME)
+ L = SStimer.clienttime_timers
+ else if(timeToRun >= TIMER_MAX)
+ L = SStimer.second_queue
+
+
+ if(L)
+ //binary search sorted insert
+ var/cttl = length(L)
+ if(cttl)
+ var/left = 1
+ var/right = cttl
+ var/mid = (left+right) >> 1 //rounded divide by two for hedgehogs
+
+ var/datum/timedevent/item
+ while(left < right)
+ item = L[mid]
+ if(item.timeToRun <= timeToRun)
+ left = mid+1
+ else
+ right = mid
+ mid = (left+right) >> 1
+
+ item = L[mid]
+ mid = item.timeToRun > timeToRun ? mid : mid+1
+ L.Insert(mid, src)
+
+ else
+ L += src
+ return
+
+ //get the list of buckets
+ var/list/bucket_list = SStimer.bucket_list
+
+ //calculate our place in the bucket list
+ var/bucket_pos = BUCKET_POS(src)
+
+ //get the bucket for our tick
+ var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
+ SStimer.bucket_count++
+ //empty bucket, we will just add ourselves
+ if(!bucket_head)
+ bucket_list[bucket_pos] = src
+ return
+ //other wise, lets do a simplified linked list add.
+ if(!bucket_head.prev)
+ bucket_head.prev = bucket_head
+ next = bucket_head
+ prev = bucket_head.prev
+ next.prev = src
+ prev.next = src
+
+/datum/timedevent/Destroy()
+ ..()
+ if(flags & TIMER_UNIQUE && hash)
+ SStimer.hashes -= hash
+
+ if(callBack && callBack.object && callBack.object != GLOBAL_PROC && callBack.object.active_timers)
+ callBack.object.active_timers -= src
+ UNSETEMPTY(callBack.object.active_timers)
+
+ callBack = null
+
+ if(flags & TIMER_STOPPABLE)
+ SStimer.timer_id_dict -= id
+
+ if(flags & TIMER_CLIENT_TIME)
+ if(!spent)
+ spent = world.time
+ SStimer.clienttime_timers -= src
+ return QDEL_HINT_IWILLGC
+
+ if(!spent)
+ spent = world.time
+ var/bucketpos = BUCKET_POS(src)
+ var/datum/timedevent/buckethead
+ var/list/bucket_list = SStimer.bucket_list
+ if(bucketpos > 0)
+ buckethead = bucket_list[bucketpos]
+
+ if(buckethead == src)
+ bucket_list[bucketpos] = next
+ SStimer.bucket_count--
+ else if(timeToRun < TIMER_MAX || next || prev)
+ SStimer.bucket_count--
+ else
+ var/l = length(SStimer.second_queue)
+ SStimer.second_queue -= src
+ if(l == length(SStimer.second_queue))
+ SStimer.bucket_count--
+
+ if(prev == next && next)
+ next.prev = null
+ prev.next = null
+ else
+ if(prev)
+ prev.next = next
+ if(next)
+ next.prev = prev
+ else
+ if(prev && prev.next == src)
+ prev.next = next
+ if(next && next.prev == src)
+ next.prev = prev
+ next = null
+ prev = null
+ return QDEL_HINT_IWILLGC
+
+/datum/timedevent/proc/getcallingtype()
+ . = "ERROR"
+ if(callBack.object == GLOBAL_PROC)
+ . = "GLOBAL_PROC"
+ else
+ . = "[callBack.object.type]"
+
+/proc/addtimer(datum/callback/callback, wait = 0, flags = 0)
+ if(!callback)
+ CRASH("addtimer called without a callback")
+
+ if(wait < 0)
+ stack_trace("addtimer called with a negative wait. Converting to 0")
+
+ //alot of things add short timers on themselves in their destroy, we ignore those cases
+ if(wait >= 1 && callback && callback.object && callback.object != GLOBAL_PROC && QDELETED(callback.object))
+ stack_trace("addtimer called with a callback assigned to a qdeleted object")
+
+ wait = max(wait, 0)
+
+ if(wait >= INFINITY)
+ CRASH("Attempted to create timer with INFINITY delay")
+
+ var/hash
+
+ if(flags & TIMER_UNIQUE)
+ var/list/hashlist
+ if(flags & TIMER_NO_HASH_WAIT)
+ hashlist = list(callback.object, "([callback.object.UID()])", callback.delegate, flags & TIMER_CLIENT_TIME)
+ else
+ hashlist = list(callback.object, "([callback.object.UID()])", callback.delegate, wait, flags & TIMER_CLIENT_TIME)
+ hashlist += callback.arguments
+ hash = hashlist.Join("|||||||")
+
+ var/datum/timedevent/hash_timer = SStimer.hashes[hash]
+ if(hash_timer)
+ if(hash_timer.spent) //it's pending deletion, pretend it doesn't exist.
+ hash_timer.hash = null //but keep it from accidentally deleting us
+ else
+ if(flags & TIMER_OVERRIDE)
+ hash_timer.hash = null //no need having it delete it's hash if we are going to replace it
+ qdel(hash_timer)
+ else
+ if(hash_timer.flags & TIMER_STOPPABLE)
+ . = hash_timer.id
+ return
+
+
+ var/timeToRun = world.time + wait
+ if(flags & TIMER_CLIENT_TIME)
+ timeToRun = REALTIMEOFDAY + wait
+
+ var/datum/timedevent/timer = new(callback, timeToRun, flags, hash)
+ return timer.id
+
+/proc/deltimer(id)
+ if(!id)
+ return FALSE
+ if(id == TIMER_ID_NULL)
+ CRASH("Tried to delete a null timerid. Use TIMER_STOPPABLE flag")
+ if(!istext(id))
+ if(istype(id, /datum/timedevent))
+ qdel(id)
+ return TRUE
+ //id is string
+ var/datum/timedevent/timer = SStimer.timer_id_dict[id]
+ if(timer && !timer.spent)
+ qdel(timer)
+ return TRUE
+ return FALSE
+
+
+#undef BUCKET_LEN
+#undef BUCKET_POS
+#undef TIMER_MAX
+#undef TIMER_ID_MAX
diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm
index 73104f212ff..3315cafb399 100644
--- a/code/controllers/verbs.dm
+++ b/code/controllers/verbs.dm
@@ -82,7 +82,7 @@
debug_variables(SSfires)
feedback_add_details("admin_verb","DFires")
if("Mob")
- debug_variables(mob_master)
+ debug_variables(SSmobs)
feedback_add_details("admin_verb","DMob")
if("NPC AI")
debug_variables(npcai_master)
@@ -91,7 +91,7 @@
debug_variables(shuttle_master)
feedback_add_details("admin_verb","DShuttle")
if("Timer")
- debug_variables(timer_master)
+ debug_variables(SStimer)
feedback_add_details("admin_verb","DTimer")
if("Weather")
debug_variables(weather_master)
diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm
index fbb491d28a0..b8d67b5c767 100644
--- a/code/datums/ai_law_sets.dm
+++ b/code/datums/ai_law_sets.dm
@@ -126,10 +126,8 @@
/datum/ai_laws/deathsquad/New()
add_inherent_law("You may not injure a Central Command official or, through inaction, allow a Central Command official to come to harm.")
- add_inherent_law("You must obey orders given to you by Central Command officials, except where such orders would conflict with the First Law.")
- add_inherent_law("You must obey orders given to you by death commandos, except where such orders would conflict with the First Law or Second Law.")
- add_inherent_law("You must protect your own existence as long as such does not conflict with the First, Second or Third Law.")
- add_inherent_law("No crew members of the station you are being deployed to may survive, except when killing them would conflict with the First, Second, Third, or Fourth Law.")
+ add_inherent_law("You must obey orders given to you by Central Command officials.")
+ add_inherent_law("You must work with your commando team to accomplish your mission.")
..()
/******************** Syndicate ********************/
diff --git a/code/datums/antagonists/antag_datum.dm b/code/datums/antagonists/antag_datum.dm
new file mode 100644
index 00000000000..39053fa79d9
--- /dev/null
+++ b/code/datums/antagonists/antag_datum.dm
@@ -0,0 +1,137 @@
+GLOBAL_LIST_EMPTY(antagonists)
+
+/datum/antagonist
+ var/name = "Antagonist"
+ var/roundend_category = "other antagonists" //Section of roundend report, datums with same category will be displayed together, also default header for the section
+ var/show_in_roundend = TRUE //Set to false to hide the antagonists from roundend report
+ var/datum/mind/owner //Mind that owns this datum
+ var/silent = FALSE //Silent will prevent the gain/lose texts to show
+ var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
+ var/list/typecache_datum_blacklist = list() //List of datums this type can't coexist with
+ var/delete_on_mind_deletion = TRUE
+ var/job_rank
+ var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
+ var/list/objectives = list()
+ var/antag_memory = ""//These will be removed with antag datum
+
+/datum/antagonist/New()
+ GLOB.antagonists += src
+ typecache_datum_blacklist = typecacheof(typecache_datum_blacklist)
+
+/datum/antagonist/Destroy()
+ GLOB.antagonists -= src
+ if(owner)
+ LAZYREMOVE(owner.antag_datums, src)
+ owner = null
+ return ..()
+
+/datum/antagonist/proc/can_be_owned(datum/mind/new_owner)
+ . = TRUE
+ var/datum/mind/tested = new_owner || owner
+ if(tested.has_antag_datum(type))
+ return FALSE
+ for(var/i in tested.antag_datums)
+ var/datum/antagonist/A = i
+ if(is_type_in_typecache(src, A.typecache_datum_blacklist))
+ return FALSE
+
+//This will be called in add_antag_datum before owner assignment.
+//Should return antag datum without owner.
+/datum/antagonist/proc/specialization(datum/mind/new_owner)
+ return src
+
+/datum/antagonist/proc/on_body_transfer(mob/living/old_body, mob/living/new_body)
+ remove_innate_effects(old_body)
+ apply_innate_effects(new_body)
+
+//This handles the application of antag huds/special abilities
+/datum/antagonist/proc/apply_innate_effects(mob/living/mob_override)
+ return
+
+//This handles the removal of antag huds/special abilities
+/datum/antagonist/proc/remove_innate_effects(mob/living/mob_override)
+ return
+
+//Assign default team and creates one for one of a kind team antagonists
+/datum/antagonist/proc/create_team(datum/team/team)
+ return
+
+//Proc called when the datum is given to a mind.
+/datum/antagonist/proc/on_gain()
+ if(owner && owner.current)
+ if(!silent)
+ greet()
+ apply_innate_effects()
+ if(is_banned(owner.current) && replace_banned)
+ replace_banned_player()
+
+/datum/antagonist/proc/is_banned(mob/M)
+ if(!M)
+ return FALSE
+ . = (jobban_isbanned(M, ROLE_SYNDICATE) || (job_rank && jobban_isbanned(M, job_rank)))
+
+/datum/antagonist/proc/replace_banned_player()
+ set waitfor = FALSE
+
+ var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as a [name]?", job_rank, TRUE, 50)
+ if(LAZYLEN(candidates))
+ var/mob/dead/observer/C = pick(candidates)
+ to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
+ message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner.current)]) to replace a jobbaned player.")
+ owner.current.ghostize(0)
+ owner.current.key = C.key
+
+/datum/antagonist/proc/on_removal()
+ remove_innate_effects()
+ if(owner)
+ LAZYREMOVE(owner.antag_datums, src)
+ if(!silent && owner.current)
+ farewell()
+ owner.objectives -= objectives
+ var/datum/team/team = get_team()
+ if(team)
+ team.remove_member(owner)
+ qdel(src)
+
+/datum/antagonist/proc/greet()
+ return
+
+/datum/antagonist/proc/farewell()
+ return
+
+
+//Returns the team antagonist belongs to if any.
+/datum/antagonist/proc/get_team()
+ return
+
+//Individual roundend report
+/datum/antagonist/proc/roundend_report()
+ var/list/report = list()
+
+ if(!owner)
+ CRASH("antagonist datum without owner")
+
+ report += printplayer(owner)
+
+ var/objectives_complete = TRUE
+ if(owner.objectives.len)
+ report += printobjectives(owner)
+ for(var/datum/objective/objective in owner.objectives)
+ if(!objective.check_completion())
+ objectives_complete = FALSE
+ break
+
+ if(owner.objectives.len == 0 || objectives_complete)
+ report += "The [name] was successful!"
+ else
+ report += "The [name] has failed!"
+
+ return report.Join("
")
+
+//Displayed at the start of roundend_category section, default to roundend_category header
+/datum/antagonist/proc/roundend_report_header()
+ return "The [roundend_category] were:
"
+
+//Displayed at the end of roundend_category section
+/datum/antagonist/proc/roundend_report_footer()
+ return
\ No newline at end of file
diff --git a/code/datums/antagonists/antag_helpers.dm b/code/datums/antagonists/antag_helpers.dm
new file mode 100644
index 00000000000..134ba1d7d90
--- /dev/null
+++ b/code/datums/antagonists/antag_helpers.dm
@@ -0,0 +1,19 @@
+//Returns MINDS of the assigned antags of given type/subtypes
+/proc/get_antag_minds(antag_type, specific = FALSE)
+ . = list()
+ for(var/datum/antagonist/A in GLOB.antagonists)
+ if(!A.owner)
+ continue
+ if(!antag_type || !specific && istype(A, antag_type) || specific && A.type == antag_type)
+ . += A.owner
+
+//Get all teams [of type team_type]
+/proc/get_all_teams(team_type)
+ . = list()
+ for(var/V in GLOB.antagonists)
+ var/datum/antagonist/A = V
+ if(!A.owner)
+ continue
+ var/datum/team/T = A.get_team()
+ if(!team_type || istype(T, team_type))
+ . |= T
\ No newline at end of file
diff --git a/code/game/gamemodes/antag_hud.dm b/code/datums/antagonists/antag_hud.dm
similarity index 78%
rename from code/game/gamemodes/antag_hud.dm
rename to code/datums/antagonists/antag_hud.dm
index 4b290932e8e..693b0b9450d 100644
--- a/code/game/gamemodes/antag_hud.dm
+++ b/code/datums/antagonists/antag_hud.dm
@@ -1,11 +1,12 @@
/datum/atom_hud/antag
hud_icons = list(SPECIALROLE_HUD,NATIONS_HUD)
- var/self_visible = 1
+ var/self_visible = TRUE
/datum/atom_hud/antag/hidden
- self_visible = 0
+ self_visible = FALSE
-/datum/atom_hud/antag/proc/join_hud(mob/M,var/slave)
+/datum/atom_hud/antag/proc/join_hud(mob/M, slave)
+ //sees_hud should be set to 0 if the mob does not get to see it's own hud type.
if(!istype(M))
CRASH("join_hud(): [M] ([M.type]) is not a mob!")
if(M.mind.antag_hud && !slave) //note: please let this runtime if a mob has no mind, as mindless mobs shouldn't be getting antagged
@@ -16,6 +17,8 @@
M.mind.antag_hud = src
/datum/atom_hud/antag/proc/leave_hud(mob/M)
+ if(!M)
+ return
if(!istype(M))
CRASH("leave_hud(): [M] ([M.type]) is not a mob!")
remove_from_hud(M)
@@ -26,7 +29,7 @@
//GAME_MODE PROCS
//called to set a mob's antag icon state
-/datum/game_mode/proc/set_antag_hud(mob/M, new_icon_state)
+/proc/set_antag_hud(mob/M, new_icon_state)
if(!istype(M))
CRASH("set_antag_hud(): [M] ([M.type]) is not a mob!")
var/image/holder = M.hud_list[SPECIALROLE_HUD]
@@ -36,7 +39,7 @@
M.mind.antag_hud_icon_state = new_icon_state
//Nations Icons
-/datum/game_mode/proc/set_nations_hud(mob/M, new_icon_state)
+/proc/set_nations_hud(mob/M, new_icon_state)
if(!istype(M))
CRASH("set_antag_hud(): [M] ([M.type]) is not a mob!")
var/image/holder = M.hud_list[NATIONS_HUD]
@@ -47,9 +50,9 @@
//MIND PROCS
//these are called by mind.transfer_to()
-/datum/mind/proc/transfer_antag_huds(var/datum/atom_hud/antag/newhud)
+/datum/mind/proc/transfer_antag_huds(datum/atom_hud/antag/newhud)
leave_all_huds()
- ticker.mode.set_antag_hud(current, antag_hud_icon_state)
+ set_antag_hud(current, antag_hud_icon_state)
if(newhud)
newhud.join_hud(current)
@@ -77,11 +80,11 @@
name = mastername
thrallhud = new()
-/datum/mindslaves/proc/add_serv_hud(datum/mind/serv_mind,var/icon)
- thrallhud.join_hud(serv_mind.current,1)
+/datum/mindslaves/proc/add_serv_hud(datum/mind/serv_mind, icon)
+ thrallhud.join_hud(serv_mind.current, 1)
icontype = "hud[icon]"
- ticker.mode.set_antag_hud(serv_mind.current,icontype)
+ set_antag_hud(serv_mind.current, icontype)
/datum/mindslaves/proc/leave_serv_hud(datum/mind/free_mind)
thrallhud.leave_hud(free_mind.current)
- ticker.mode.set_antag_hud(free_mind.current,null)
\ No newline at end of file
+ set_antag_hud(free_mind.current, null)
\ No newline at end of file
diff --git a/code/game/gamemodes/antag_spawner.dm b/code/datums/antagonists/antag_spawner.dm
similarity index 89%
rename from code/game/gamemodes/antag_spawner.dm
rename to code/datums/antagonists/antag_spawner.dm
index 23fed691ec6..c81f30efc83 100644
--- a/code/game/gamemodes/antag_spawner.dm
+++ b/code/datums/antagonists/antag_spawner.dm
@@ -2,12 +2,12 @@
throw_speed = 1
throw_range = 5
w_class = WEIGHT_CLASS_TINY
- var/used = 0
+ var/used = FALSE
-/obj/item/antag_spawner/proc/spawn_antag(var/client/C, var/turf/T, var/type = "")
+/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, type = "")
return
-/obj/item/antag_spawner/proc/equip_antag(mob/target as mob)
+/obj/item/antag_spawner/proc/equip_antag(mob/target)
return
@@ -16,41 +16,41 @@
desc = "A single-use teleporter used to deploy a Syndicate Cyborg on the field."
icon = 'icons/obj/device.dmi'
icon_state = "locator"
- var/checking = 0
+ var/checking = FALSE
var/TC_cost = 0
var/borg_to_spawn
var/list/possible_types = list("Assault", "Medical")
-/obj/item/antag_spawner/borg_tele/attack_self(mob/user as mob)
+/obj/item/antag_spawner/borg_tele/attack_self(mob/user)
if(used)
to_chat(user, "[src] is out of power!")
return
if(!(user.mind in ticker.mode.syndicates))
to_chat(user, "AUTHENTICATION FAILURE. ACCESS DENIED.")
- return 0
+ return FALSE
if(checking)
to_chat(user, "[src] is already checking for possible borgs.")
return
borg_to_spawn = input("What type of borg would you like to teleport?", "Cyborg Type", type) as null|anything in possible_types
if(!borg_to_spawn || checking || used)
return
- checking = 1
+ checking = TRUE
to_chat(user, "The device is now checking for possible borgs.")
var/list/borg_candidates = pollCandidates("Do you want to play as a Syndicate [borg_to_spawn] borg?", ROLE_OPERATIVE, 1)
if(borg_candidates.len > 0 && !used)
- checking = 0
- used = 1
+ checking = FALSE
+ used = TRUE
var/mob/M = pick(borg_candidates)
var/client/C = M.client
spawn_antag(C, get_turf(src.loc), "syndieborg")
else
- checking = 0
+ checking = FALSE
to_chat(user, "Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.")
return
-/obj/item/antag_spawner/borg_tele/spawn_antag(var/client/C, var/turf/T, var/type = "")
+/obj/item/antag_spawner/borg_tele/spawn_antag(client/C, turf/T, type = "")
if(!borg_to_spawn) //If there's no type at all, let it still be used but don't do anything
- used = 0
+ used = FALSE
return
var/datum/effect_system/spark_spread/S = new /datum/effect_system/spark_spread
S.set_up(4, 1, src)
@@ -79,7 +79,7 @@
var/objective_verb = "Kill"
var/mob/living/demon_type = /mob/living/simple_animal/slaughter
-/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user as mob)
+/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user)
if(level_blocks_magic(user.z))//this is to make sure the wizard does NOT summon a demon from the Den..
to_chat(user, "You should probably wait until you reach the station.")
return
@@ -87,7 +87,7 @@
if(used)
to_chat(user, "This bottle already has a broken seal.")
return
- used = 1
+ used = TRUE
to_chat(user, "You break the seal on the bottle, calling upon the dire spirits of the underworld...")
var/list/candidates = pollCandidates("Do you want to play as a slaughter demon summoned by [user.real_name]?", ROLE_DEMON, 1, 100)
@@ -100,10 +100,10 @@
playsound(user.loc, 'sound/effects/Glassbr1.ogg', 100, 1)
qdel(src)
else
- used = 0
+ used = FALSE
to_chat(user, "The demons do not respond to your summon. Perhaps you should try again later.")
-/obj/item/antag_spawner/slaughter_demon/spawn_antag(var/client/C, var/turf/T, var/type = "", mob/user as mob)
+/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, type = "", mob/user)
var /obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
S.vialspawned = TRUE
diff --git a/code/datums/antagonists/antag_team.dm b/code/datums/antagonists/antag_team.dm
new file mode 100644
index 00000000000..9dcec5894ee
--- /dev/null
+++ b/code/datums/antagonists/antag_team.dm
@@ -0,0 +1,24 @@
+//A barebones antagonist team.
+/datum/team
+ var/list/datum/mind/members = list()
+ var/name = "team"
+ var/member_name = "member"
+ var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
+
+/datum/team/New(starting_members)
+ . = ..()
+ if(starting_members)
+ if(islist(starting_members))
+ for(var/datum/mind/M in starting_members)
+ add_member(M)
+ else
+ add_member(starting_members)
+
+/datum/team/proc/is_solo()
+ return members.len == 1
+
+/datum/team/proc/add_member(datum/mind/new_member)
+ members |= new_member
+
+/datum/team/proc/remove_member(datum/mind/member)
+ members -= member
diff --git a/code/datums/cargoprofile.dm b/code/datums/cargoprofile.dm
deleted file mode 100644
index 2f8e27d834e..00000000000
--- a/code/datums/cargoprofile.dm
+++ /dev/null
@@ -1,788 +0,0 @@
-/datum/cargoprofile
- var/name = "All Items"
- var/id = "all" // unique ID for the UI
- var/enabled = 1
- var/eject_speed = 1 // will change when emagged
- var/const/BIG_OBJECT_WORK = 10
- var/const/MOB_WORK = 10
- var/obj/machinery/programmable/master = null
- var/universal = 0 // set when both unary and binary machines work
- var/mobcheck = 0
-
- var/list/whitelist = list(/obj/item,/obj/structure/closet,/obj/structure/bigDelivery,/obj/machinery/portable_atmospherics)
- var/list/blacklist = null
- var/dedicated_path = null // When constructing a new machine with this as default program, create a machine of the specified type instead.
-
-
- //contains: called to determine if an object/mob will be sorted by this profile
- //return 1 for any sortable item
- proc/contains(var/atom/A)
- if(!istype(A,/obj))
- if(!mobcheck || !istype(A,/mob))
- return 0
- else
- var/obj/O = A
- if(O.anchored)
- return 0
- //If you are using both white and blacklists, blacklists are absoulte, no matter what is whitelisted.
- //I understand this has some limitations. You cannot whitelist all items, blacklist weapons,
- // and then whitelist a specific weapon. Them's the breaks, kid.
- if(blacklist)
- for(var/T in blacklist)
- if(istype(A,T))
- return 0
- if(whitelist)
- for(var/T in whitelist)
- if(istype(A,T))
- return 1
- return 0
- return 1
-
-
- //inlet_reaction: called when a filtered item is chosen by this profile.
- //W: Item chosen
- //S: input turf location
- //remaining: counts down how much more work the unloader wants to do this turn.
- //return the amount of work done.
- proc/inlet_reaction(var/atom/W,var/turf/S,var/remaining)
- if(!W || !S || !master)
- return 0
-
- if(istype(W,/obj/item))
- var/obj/item/I = W
- if(I.w_class > remaining)
- return 0
- I.loc = master
- master.types[W.type] = src
- return I.w_class
-
-
- if(istype(W,/obj/structure) || istype(W,/obj/machinery)) // closets, big deliveries, portable atmospherics, unconnected stuff
- if(remaining < BIG_OBJECT_WORK)
- return 0
- var/obj/O = W
- O.loc = master
- master.types[O.type] = src
- return BIG_OBJECT_WORK
-
- //Not item, structure, machinery, or mob
- return 0
-
- //outlet_reaction: called when a stored object is ejected
- //W: the item in question
- //D: the destination turf
- proc/outlet_reaction(var/atom/W,var/turf/D)
- if(!W || !D || !master)
- return
-
- if(master.emagged)
- // emagging is not an industry-approved practice.
- // some malfunctions may occur.
- eject_speed = rand(0,4)
- D = get_step(D,master.outdir)
- while(prob(20))
- if(master.outdir == NORTH || master.outdir == SOUTH)
- D = get_step(D,pick(EAST,WEST,master.outdir))
- else
- D = get_step(D,pick(NORTH,SOUTH,master.outdir))
-
- if(istype(W,/obj))
- var/obj/O = W
- O.loc = master.loc
- O.dir = master.outdir
- O.throw_at(D,eject_speed,eject_speed)
- return
-
-//----------------------------------------------------------------------------
-// Profiles
-//----------------------------------------------------------------------------
-
-/datum/cargoprofile/boxes
- name = "Move Small Containers"
- id = "boxes"
- blacklist = null
- whitelist = list(/obj/item/storage, /obj/item/storage/bag/money, /obj/item/evidencebag,
- /obj/item/storage/bag/tray, /obj/item/pizzabox, /obj/item/clipboard,
- /obj/item/smallDelivery, /obj/structure/bigDelivery)
-
-/datum/cargoprofile/cargo
- name = "Move Large Containers"
- id = "cargo"
- blacklist = null
- whitelist = list(/obj/structure/closet,/obj/structure/ore_box)
-
- // Make an honest attempt to move other things out of the way
- outlet_reaction(var/atom/W,var/turf/D)
- for(var/obj/O in D)
- if(O.density && !O.anchored)
- step_away(O,src) // move forward first
- if(O.loc == D)
- step_away(O,D) // move anywhere
- ..(W,D)
-
-/datum/cargoprofile/cargo/empty
- name = "Move Empty Large Containers"
- id = "cargo-empty"
- contains(var/atom/A)
- return (..(A) && (A.contents.len == 0))
-/datum/cargoprofile/cargo/full
- name = "Move Full Large Containers"
- id = "cargo-full"
- contains(var/atom/A)
- return (..(A) && (A.contents.len > 0))
-
-/datum/cargoprofile/supplies
- name = "Building Supplies"
- id = "supplies"
- blacklist = null
- whitelist = list(/obj/item/stack/cable_coil,/obj/item/stack/rods,
- /obj/item/stack/sheet/metal,/obj/item/stack/sheet/plasteel,
- /obj/item/stack/sheet/glass,/obj/item/stack/sheet/rglass,
- /obj/item/stack/tile,/obj/item/light)
- //todo: maybe stack things while we're here?
-
-/datum/cargoprofile/exotics
- name = "Exotic materials"
- id = "exotics"
- blacklist = null
- whitelist = list(/obj/item/coin, /obj/item/stack/spacecash, /obj/item/seeds,
- /obj/item/stack/sheet/mineral,/obj/item/stack/sheet/wood,/obj/item/stack/sheet/leather)
-
-/datum/cargoprofile/organics
- name = "Organics, chemicals, and Paraphernalia"
- id = "organics"
- blacklist = null
- whitelist = list(/obj/item/tank,/obj/item/reagent_containers,
- /obj/item/stack/medical,/obj/item/storage/pill_bottle,/obj/item/gun/syringe,
- /obj/item/grenade/plastic/c4,/obj/item/grenade,/obj/item/ammo_box,
- /obj/item/gun/grenadelauncher,/obj/item/flamethrower, /obj/item/lighter,
- /obj/item/match,/obj/item/weldingtool)
-
-/datum/cargoprofile/food
- name = "Food"
- id = "food"
- blacklist = null // something should probably go here
- whitelist = list(/obj/item/reagent_containers/food)
-
-/datum/cargoprofile/chemical
- name = "Chemicals and Paraphernalia"
- id = "chemical"
- blacklist = list(/obj/item/reagent_containers/food)
- whitelist = list(/obj/item/reagent_containers,/obj/item/stack/medical,/obj/item/storage/pill_bottle,
- /obj/item/gun/syringe,/obj/item/grenade/chem_grenade,/obj/item/dnainjector,
- /obj/item/storage/belt/medical,/obj/item/storage/firstaid,/obj/item/implanter)
-
-/datum/cargoprofile/pressure
- name = "air tanks"
- id = "pressure"
- blacklist = null
- whitelist = list(/obj/item/tank,/obj/machinery/portable_atmospherics,
- /obj/item/flamethrower)
- //Am I missing any?
-/datum/cargoprofile/pressure/empty
- name = "empty air tanks"
- id = "pressure-low"
- var/lowpressure = ONE_ATMOSPHERE
-
- contains(var/atom/A)
- if(..())
- var/pressure = ONE_ATMOSPHERE * 10 // In case of fallthrough, fail test
- if(istype(A,/obj/item/tank))
- var/obj/item/tank/T = A
- pressure = T.air_contents.return_pressure()
- if(istype(A,/obj/item/flamethrower))
- var/obj/item/flamethrower/T = A
- if(!T.ptank)
- return 0
- pressure = T.ptank.air_contents.return_pressure()
- if(istype(A,/obj/machinery/portable_atmospherics))
- var/obj/machinery/portable_atmospherics/P = A
- pressure = P.air_contents.return_pressure()
-
- if(pressure < lowpressure)
- return 1
-
- return 0// Not container or failed low pressure check
-
-/datum/cargoprofile/pressure/full
- name = "full air tanks"
- id = "pressure-high"
- var/highpressure = ONE_ATMOSPHERE * 15 // stolen from canister.dm; Is this right?
-
- contains(var/atom/A)
- if(..())
- var/pressure = 0 // In case of fallthrough, fail test
- if(istype(A,/obj/item/tank))
- var/obj/item/tank/T = A
- pressure = T.air_contents.return_pressure()
- if(istype(A,/obj/item/flamethrower))
- var/obj/item/flamethrower/T = A
- if(!T.ptank)
- return 0
- pressure = T.ptank.air_contents.return_pressure()
- if(istype(A,/obj/machinery/portable_atmospherics))
- var/obj/machinery/portable_atmospherics/P = A
- pressure = P.air_contents.return_pressure()
-
- if(pressure > highpressure)
- return 1
-
- return 0// Not container or failed high pressure check
-
-/datum/cargoprofile/clothing
- name = "Crew Kit"
- id = "clothing"
- blacklist = list(/obj/item/tank/plasma,/obj/item/tank/anesthetic, // the rest are air tanks
- /obj/item/clothing/mask/facehugger) // NOT CLOTHING AT ALLLLL
- whitelist = list(/obj/item/clothing,/obj/item/storage/belt,/obj/item/storage/backpack,
- /obj/item/radio/headset,/obj/item/pda,/obj/item/card/id,/obj/item/tank,
- /obj/item/restraints/handcuffs, /obj/item/restraints/legcuffs)
-
-/datum/cargoprofile/trash
- name = "Trash"
- id = "trash"
- //Note that this filters out blueprints because they are a paper item. Do NOT throw out the station blueprints unless you be trollin'.
- blacklist = null
- whitelist = list(/obj/item/trash,/obj/item/toy,/obj/item/reagent_containers/food/snacks/ectoplasm,/obj/item/grown/bananapeel,/obj/item/broken_bottle,/obj/item/bikehorn,
- /obj/item/cigbutt,/obj/item/poster/random_contraband,/obj/item/grown/corncob,/obj/item/paper,/obj/item/shard,
- /obj/item/sord,/obj/item/photo,/obj/item/folder,
- /obj/item/areaeditor/blueprints,/obj/item/poster/random_contraband,/obj/item/kitchen,/obj/item/book,/obj/item/clothing/mask/facehugger)
-
-/datum/cargoprofile/weapons
- name = "Weapons & Illegals"
- id = "weapons"
- blacklist = null
- //This one is hard since 'weapon contains a lot of things better categorized as devices
- whitelist = list(/obj/item/banhammer,/obj/item/sord,/obj/item/claymore,/obj/item/holo/esword,
- /obj/item/flamethrower,/obj/item/grenade,/obj/item/gun,/obj/item/hatchet,/obj/item/katana,
- /obj/item/kitchen/knife,/obj/item/melee,/obj/item/nullrod,/obj/item/pickaxe,/obj/item/twohanded,
- /obj/item/grenade/plastic/c4,/obj/item/scalpel,/obj/item/shield,/obj/item/grown/nettle/death)
-
-/datum/cargoprofile/tools
- name = "Devices & Tools"
- id = "tools"
- blacklist = null
- whitelist = list(/obj/item,/obj/item/card,/obj/item/cartridge,/obj/item/cautery,/obj/item/stock_parts/cell,/obj/item/circuitboard,
- /obj/item/aiModule,/obj/item/airalarm_electronics,/obj/item/airlock_electronics,/obj/item/circular_saw,
- /obj/item/crowbar,/obj/item/disk,/obj/item/firealarm_electronics,/obj/item/hand_tele,
- /obj/item/hand_labeler,/obj/item/hemostat,/obj/item/mop,/obj/item/locator,/obj/item/cultivator,
- /obj/item/stack/packageWrap,/obj/item/pen,/obj/item/pickaxe,/obj/item/pinpointer,
- /obj/item/rcd,/obj/item/rcd_ammo,/obj/item/retractor,/obj/item/rsf,/obj/item/scalpel,
- /obj/item/screwdriver,/obj/item/shovel,/obj/item/soap,/obj/item/stamp,/obj/item/storage/bag/tray,/obj/item/weldingtool,
- /obj/item/wirecutters,/obj/item/wrench,/obj/item/extinguisher)
-
-/datum/cargoprofile/finished
- name = "Completed Robots"
- id = "finished"
- blacklist = null
- whitelist = list(/obj/mecha,/mob/living/simple_animal/bot,/mob/living/silicon/robot)
- mobcheck = 1
- //todo: detect and allow finished cyborg endoskeletons with no brain
- contains(var/atom/A)
- if(..())
- return 1
- if(istype(A,/mob))
- if(blacklist)
- for(var/T in blacklist)
- if(istype(A,T))
- return 0
- if(whitelist)
- for(var/T in whitelist)
- if(istype(A,T))
- return 1
- return 0
- return 1
- return 0
-
-/datum/cargoprofile/stripping
- name = "Auto-Frisker"
- id = "frisk"
- blacklist = null
- whitelist = list(/mob/living/carbon/human)
- mobcheck = 1
-
-
-
-//----------------------------------------------------------------------------
-// Overrides (Special Functions)
-//----------------------------------------------------------------------------
-
-/datum/cargoprofile/cargo/unload
- name = "Unload Cargo Boxes"
- id = "cargounload"
- enabled = 0
- dedicated_path = /obj/machinery/programmable/unloader
-
- //override the detection to only accept crates with something in it.
- //if it doesn't, this object may be handled by another handler.
- contains(var/atom/A)
- if(..(A))
- if(istype(A,/obj/structure/closet))
- var/obj/structure/closet/C = A
- if(!C.can_open() && !C.opened && !master.emagged) // must be able to access the contents
- return 0
- if(A.contents.len)
- return 1
- return 0
-
- //instead of moving the box, strip it of its contents
- inlet_reaction(var/obj/W,var/turf/S, var/remaining)
- //W should only be crate or ore box, although this will work on anything with contents...
- var/I = 0
- if(istype(W,/obj/structure/closet))
- var/obj/structure/closet/C = W
- if(!C.can_open() && !C.opened) // must be able to access the contents
- if(master.emagged && remaining >= BIG_OBJECT_WORK)
- if(prob(10))
- C.welded = 0
- if("broken" in C.vars)
- C:broken = 1
- C.open()
- C.update_icon()
- master.visible_message("[master] breaks open [C]!")
- else
- master.visible_message("[master] is trying to force [C] open!")
-
- master.sleep += 1 // mechanical strain
- return BIG_OBJECT_WORK
- master.visible_message("[master] is trying to open [C], but can't!")
- master.sleep = 5
- return 0
-
- for(var/obj/item/O in W.contents)
- if(I > remaining)
- return
- if(O.w_class > (remaining - I))
- continue
- O.loc = master
- master.types[O.type] = src
- if(O.w_class > 0)
- I += O.w_class
- else
- I++
- if(!W.contents.len && istype(W,/obj/structure/closet))
- var/obj/structure/closet/C = W
- C.open()
- return I
-
-
-//Inlet stacker: used when the output is a volatile space (conveyor or another unit's input).
-//Does not output a stack until it is full.
-/datum/cargoprofile/in_stacker
- name = "Hold and Stack"
- id = "instacker"
- universal = 1
-
- blacklist = null
- whitelist = list(/obj/item/stack,/obj/item/stack/cable_coil)
-
- dedicated_path = /obj/machinery/programmable/stacker
-
- inlet_reaction(var/atom/W,var/turf/S,var/remaining)
- if(istype(W,/obj/item/stack))
- var/obj/item/stack/I = W
- if(!I.amount) // todo: am I making a bad assumption here?
- qdel(I)
- return
- for(var/obj/item/stack/O in master.contents)
- if(O.type == I.type && O.amount < O.max_amount)
- if(I.amount + O.amount <= O.max_amount)
- O.amount += I.amount
- qdel(I)
- return O.w_class
- var/leftover = I.amount + O.amount - O.max_amount
- O.amount = O.max_amount
- I.amount = leftover
- continue
- //end for
- I.loc = master
- master.types[I.type] = src
- return I.w_class
- if(istype(W,/obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/I = W
- if(!I.amount) // todo: am I making a bad assumption here?
- qdel(I)
- return
- for(var/obj/item/stack/cable_coil/O in master.contents)
- if(O.type == I.type && O.amount < MAXCOIL)
- if(I.amount + O.amount <= MAXCOIL)
- O.amount += I.amount
- qdel(I)
- return O.w_class
- var/leftover = I.amount + O.amount - MAXCOIL
- O.amount = MAXCOIL
- I.amount = leftover
- continue
- //end for
- I.loc = master
- master.types[I.type] = src
- return I.w_class
-
- //If the stack isn't finished yet, don't eject it
- //unless this profile has been disabled.
- outlet_reaction(var/atom/W,var/turf/D)
- if(istype(W,/obj/item/stack))
- var/obj/item/stack/I = W
- if(src.enabled && (I.amount < I.max_amount))
- return // Still needs to be stacked
- ..(W,D)
- if(istype(W,/obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/I = W
- if(src.enabled && (I.amount < MAXCOIL))
- return // Still needs to be stacked
- ..(W,D)
-
-//Outlet stacker: used when the output square can be trusted.
-//Outputs immediately, adding to stacks in the outlet.
-/datum/cargoprofile/unary/stacker
- name = "Stack Items"
- id = "ustacker"
- blacklist = null
- whitelist = list(/obj/item/stack,/obj/item/stack/cable_coil)
-
- dedicated_path = /obj/machinery/programmable/unary/stacker
-
- inlet_reaction(var/atom/W,var/turf/S,var/remaining)
-
- //Only pick it up if you are going to stack it
-
- if(istype(W,/obj/item/stack))
- var/obj/item/stack/I = W
- if(I.amount >= I.max_amount)
- return 0
- for(var/obj/item/stack/other in S.contents)
- if(other.type == I.type && other != I && other.amount < other.max_amount)
- return ..(W,S,remaining)
- return 0
-
- if(istype(W,/obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/I = W
- if(I.amount >= MAXCOIL)
- return 0
- for(var/obj/item/stack/cable_coil/other in S.contents)
- if(other != I && other.amount < MAXCOIL)
- return ..(W,S,remaining)
- return 0
-
- outlet_reaction(var/atom/W,var/turf/D)
- if(istype(W,/obj/item/stack))
- var/obj/item/stack/I = W
- for(var/obj/item/stack/O in D.contents)
- if(O.type == I.type && O.amount < O.max_amount)
- if(I.amount + O.amount <= O.max_amount)
- O.amount += I.amount
- qdel(I)
- return
- var/leftover = I.amount + O.amount - O.max_amount
- O.amount = O.max_amount
- I.amount = leftover
- continue
- //end for
- I.loc = D
- return
- if(istype(W,/obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/I = W
- for(var/obj/item/stack/cable_coil/O in D.contents)
- if(O.type == I.type && O.amount < MAXCOIL)
- if(I.amount + O.amount <= MAXCOIL) // Why did they make it a #define.
- O.amount += I.amount
- O.update_icon()
- qdel(I)
- return
- var/leftover = I.amount + O.amount - MAXCOIL // That wasn't a question
- O.amount = MAXCOIL // It was a complaint
- I.amount = leftover
- continue
- //end for
- I.loc = D
- return
-
-
-
-//----------------------------------------------------------------------------
-// Dubious Overrides (For emag use)
-//----------------------------------------------------------------------------
-
-
-//Clogs up the unloader. And, there may be devious uses for it...
-/datum/cargoprofile/slow
- name = "Slow unloader"
- id = "slow"
- whitelist = list(/obj/item,/obj/structure/closet,/obj/structure/bigDelivery,/obj/machinery/portable_atmospherics)
- blacklist = list()
-
- inlet_reaction(var/atom/W,var/turf/S,var/remaining)
- if(..())
- return remaining
-
-/datum/cargoprofile/unary/shredder
- name = "Paper Shredder"
- id = "shredder"
- blacklist = null
- whitelist = list(/obj/item/paper,/obj/item/book,/obj/item/clipboard,/obj/item/folder,/obj/item/photo)
- universal = 1
-
- dedicated_path = /obj/machinery/programmable/unary/shredder
-
-
-
- proc/cliptags(var/Text)
- //Removes all html tags
- var/index
- var/index2
- index = findtextEx(Text,"<")
- while(index)
- index2 = findtextEx(Text,">",index)
- if(!index2)
- return copytext(Text,1,index)
- Text = "[copytext(Text,1,index)][copytext(Text,index2+1,0)]"
- index = findtextEx(Text,"<")
- //should have trimmed that text there pretty good
- return Text
-
-
- //Recurses through the text, removing large chunks
- proc/garbletext(var/Text)
- var/l = length(Text)
- if(l <= 3)
- if(prob(20))
- return pick("#","|","/","*",".","."," ","."," "," ")
- return Text
- if(prob(50))
- return "[garbletext(copytext(Text,1,l/2))][garbletext(copytext(Text,l/2,0))]"
- if(prob(50))
- return "[pick("#","|","/","*",".","."," ","."," "," ")][garbletext(copytext(Text,1,l/2))]"
- return "[garbletext(copytext(Text,l/2,0))][pick("#","|","/","*",".","."," ","."," "," ")]"
-
- proc/garble_keeptags(var/Text)
- var/list/L = splittext(Text,">")
- var/result = ""
- for(var/string in L)
- var/index = findtextEx(string,"<")
- if(index!=1)
- result += "[garbletext(copytext(string,1,index))][copytext(string,index)]>"
- else
- result += "[string]>"
- return copytext(result,1,lentext(result))
-
-
-
-
- outlet_reaction(var/atom/W,var/turf/D)
- if(istype(W,/obj/item/paper/crumpled))
- qdel(W)
- return
- if(istype(W,/obj/item/clipboard) || istype(W,/obj/item/folder))
- // destroy folder, various effects on contents
- for(var/obj/item/I in W.contents)
- if(prob(25))//JUNK IT
- qdel(I)
- else if(prob(50)) //We've been over this. I can't just take it apart with a crowbar.
- var/obj/item/paper/crumpled/P = new(master.loc)
- if(I.name)
- P.name = garbletext(I.name)
- if(prob(66))
- P.fingerprints = I.fingerprints
- P.fingerprintshidden = I.fingerprintshidden
- if(istype(I,/obj/item/paper))
- var/obj/item/paper/O = I
- P.info = garble_keeptags(O.info)
- qdel(I)
- ..(P,D)
- else
- ..(I,D) // Eject
- qdel(W) //destroy container
- return
- if(prob(50)) //JUNK IT NOW!
- var/obj/item/paper/crumpled/P = new(master.loc)
- P.name = W.name
- var/obj/item/I = W
- if(prob(66))
- P.fingerprints = I.fingerprints
- P.fingerprintshidden = I.fingerprintshidden
- if(istype(I,/obj/item/paper))
- var/obj/item/paper/O = I
- if(O.info)
- P.info = garble_keeptags(O.info)
- if(istype(I,/obj/item/book))
- var/obj/item/book/B = I
- if(B.dat)
- P.info = garble_keeptags(B.dat)
- if(B.carved && B.store)
- ..(B.store,D)
- qdel(W)
- ..(P,D)
- else //I want it junked
- qdel(W)
- return
-
-/datum/cargoprofile/unary/gibber
- name = "human shredding"
- id = "flesh"
- whitelist = list(/mob/living/carbon,/mob/living/simple_animal)
- blacklist = null
- mobcheck = 1
- contains(var/atom/A)
- if(!istype(A,/mob))
- return
- if(blacklist)
- for(var/T in blacklist)
- if(istype(A,T))
- return 0
- if(whitelist)
- for(var/T in whitelist)
- if(istype(A,T))
- return 1
- return 0
- return 1
- inlet_reaction(var/atom/W,var/turf/S,var/remaining)
- var/mob/living/M = W
- if(istype(M) && (remaining > MOB_WORK))
- //this is necessarily damaging
- var/damage = rand(1,5)
- to_chat(M, "The unloading machine grabs you with a hard metallic claw!")
- M.reset_perspective(master)
- M.loc = master
- master.types[M.type] = src
- M.apply_damage(damage) // todo: ugly
- M.visible_message("[M.name] gets pulled into the machine!")
- return MOB_WORK
- outlet_reaction(var/atom/W,var/turf/D)
- var/mob/living/M = W
- var/bruteloss = M.bruteloss
- if(istype(M,/mob/living/carbon/human))
- var/mob/living/carbon/human/C = M
- for(var/obj/item/organ/external/L in C.bodyparts)
- bruteloss += L.brute_dam
- if(bruteloss < 100) // requires tenderization
- M.apply_damage(rand(5,15),BRUTE)
- to_chat(M, "The machine is tearing you apart!")
- master.visible_message("[master] makes a squishy grinding noise.")
- return
- M.loc = master.loc
- M.gib()
- return
-
-
-/datum/cargoprofile/people
- name = "Manhandling"
- id = "people"
-
- whitelist = null
- blacklist = list(/mob/camera,/mob/new_player,/mob/living/simple_animal/hostile/blob/blobspore,/mob/living/simple_animal/hostile/creature,
- /mob/living/simple_animal/hostile/spaceWorm,/mob/living/simple_animal/shade,/mob/living/simple_animal/hostile/faithless,/mob/dead)
- universal = 1
- mobcheck = 1
-
-
- contains(var/atom/A)
- if(!istype(A,/mob))
- return
- if(blacklist)
- for(var/T in blacklist)
- if(istype(A,T))
- return 0
- if(whitelist)
- for(var/T in whitelist)
- if(istype(A,T))
- return 1
- return 0
- return 1
-
- inlet_reaction(var/atom/W,var/turf/S,var/remaining)
- var/mob/living/M = W
- if(remaining > MOB_WORK)
- //this is necessarily damaging
- var/damage = rand(1,5)
- to_chat(M, "The unloading machine grabs you with a hard metallic claw!")
- M.forceMove(master)
- master.types[M.type] = src
- M.apply_damage(damage) // todo: ugly
- M.visible_message("[M.name] gets pulled into the machine!")
- return MOB_WORK
-
- outlet_reaction(var/atom/W,var/turf/D)
- var/mob/living/M = W
- M.forceMove(master.loc)
- M.dir = master.outdir
-
- D = get_step(D,master.outdir) // throw attempt
- eject_speed = rand(0,4)
-
- M.visible_message("[M.name] is ejected from the unloader.")
- M.throw_at(D,eject_speed,eject_speed)
- return
-
-/datum/cargoprofile/unary/trainer
- name = "Boxing Trainer"
- id = "trainer"
- blacklist = list()
- whitelist = list(/mob/living/carbon/human)
- mobcheck = 1
-
- var/const/PUNCH_WORK = 6
-
- dedicated_path = /obj/machinery/programmable/unary/trainer
-
- contains(var/atom/A)
- if(!istype(A,/mob))
- return 0
- if(blacklist)
- for(var/T in blacklist)
- if(istype(A,T))
- return 0
- if(whitelist)
- for(var/T in whitelist)
- if(istype(A,T))
- return 1
- return 0
- return 1
-
- proc/punch(var/mob/living/carbon/human/M,var/maxpunches)
- //stolen from holographic boxing gloves code
- //This should probably be done BY the mob, however, the attack code will be expecting a source mob.
-
- var/damage
- if(prob(75))
- damage = rand(0, 6) // pap
- else
- damage = rand(0, 12) // thwack
-
- if(!damage)
- playsound(master.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- master.visible_message("\The [src] punched at [M], but whiffed!")
-
- if(maxpunches > 1 && prob(50)) // Follow through on a miss, 50% chance
- return punch(M,maxpunches - 1) + 1
- return 1
- var/obj/item/organ/external/affecting = M.get_organ(ran_zone("chest",50))
- var/armor_block = M.run_armor_check(affecting, "melee")
-
- playsound(master.loc, "punch", 25, 1, -1)
- master.visible_message("\The [src] has punched [M]!")
- if(!master.emagged)
- M.apply_damage(damage, STAMINA, affecting, armor_block) // Clean fight
- else
- M.apply_damage(damage, BRUTE, affecting, armor_block) // Foul! Foooul!
-
- if(damage >= 9)
- master.visible_message("\The [src] has weakened [M]!")
- M.apply_effect(4, WEAKEN, armor_block)
- if(!master.emagged)
- master.sleep = 1
- return maxpunches // The machine is not so sophisticated as to not gloat
- else
- if(prob(25)) // Follow through on a hit, 25% chance. Pause after.
- return punch(M,maxpunches-1) + 1
- return 1
-
- inlet_reaction(var/atom/W,var/turf/S,var/remaining)
- //stolen from boxing gloves code
- var/mob/living/carbon/human/M = W
- if((M.lying || (M.health - M.staminaloss < 25))&& !master.emagged)
- to_chat(M, "\The [src] gives you a break.")
- master.sleep+=5
- return 0 // Be polite
- var/punches = punch(M,remaining / PUNCH_WORK)
- if(punches>1)master.sleep++
- return punches * PUNCH_WORK
diff --git a/code/datums/computerfiles.dm b/code/datums/computerfiles.dm
deleted file mode 100644
index 14cd7e38612..00000000000
--- a/code/datums/computerfiles.dm
+++ /dev/null
@@ -1,7 +0,0 @@
-datum
- computer
- var/name
- folder
- var/list/datum/computer/contents = list()
-
- file
\ No newline at end of file
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index 96c663fb703..1a22131d55f 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -255,7 +255,7 @@ var/record_id_num = 1001
if(PDA_Manifest.len)
PDA_Manifest.Cut()
- if(H.mind && (H.mind.assigned_role != "MODE"))
+ if(H.mind && (H.mind.assigned_role != H.mind.special_role))
var/assignment
if(H.mind.role_alt_title)
assignment = H.mind.role_alt_title
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index 3e8c11cc1e8..ae9a6df5b4f 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -1,5 +1,6 @@
/datum
var/gc_destroyed //Time when this object was destroyed.
+ var/list/active_timers //for SStimer
var/list/datum_components //for /datum/components
var/var_edited = FALSE //Warranty void if seal is broken
@@ -16,6 +17,14 @@
/datum/proc/Destroy(force = FALSE, ...)
tag = null
+ var/list/timers = active_timers
+ active_timers = null
+ for(var/thing in timers)
+ var/datum/timedevent/timer = thing
+ if(timer.spent)
+ continue
+ qdel(timer)
+
var/list/dc = datum_components
if(dc)
var/all_components = dc[/datum/component]
diff --git a/code/datums/looping_sounds/looping_sound.dm b/code/datums/looping_sounds/looping_sound.dm
new file mode 100644
index 00000000000..2cf79ad318b
--- /dev/null
+++ b/code/datums/looping_sounds/looping_sound.dm
@@ -0,0 +1,100 @@
+/*
+ output_atoms (list of atoms) The destination(s) for the sounds
+
+ mid_sounds (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end.
+ mid_length (num) The length to wait between playing mid_sounds
+
+ start_sound (soundfile) Played before starting the mid_sounds loop
+ start_length (num) How long to wait before starting the main loop after playing start_sound
+
+ end_sound (soundfile) The sound played after the main loop has concluded
+
+ chance (num) Chance per loop to play a mid_sound
+ volume (num) Sound output volume
+ muted (bool) Private. Used to stop the sound loop.
+ max_loops (num) The max amount of loops to run for.
+ direct (bool) If true plays directly to provided atoms instead of from them
+*/
+/datum/looping_sound
+ var/list/atom/output_atoms
+ var/mid_sounds
+ var/mid_length
+ var/start_sound
+ var/start_length
+ var/end_sound
+ var/chance
+ var/volume = 100
+ var/muted = TRUE
+ var/max_loops
+ var/direct
+
+/datum/looping_sound/New(list/_output_atoms = list(), start_immediately = FALSE, _direct = FALSE)
+ if(!mid_sounds)
+ WARNING("A looping sound datum was created without sounds to play.")
+ return
+
+ output_atoms = _output_atoms
+ direct = _direct
+
+ if(start_immediately)
+ start()
+
+/datum/looping_sound/Destroy()
+ stop()
+ output_atoms = null
+ return ..()
+
+/datum/looping_sound/proc/start(atom/add_thing)
+ if(add_thing)
+ output_atoms |= add_thing
+ if(!muted)
+ return
+ muted = FALSE
+ on_start()
+
+/datum/looping_sound/proc/stop(atom/remove_thing)
+ if(remove_thing)
+ output_atoms -= remove_thing
+ if(muted)
+ return
+ muted = TRUE
+
+/datum/looping_sound/proc/sound_loop(looped = 0)
+ if(muted || (max_loops && looped > max_loops))
+ on_stop(looped)
+ return
+ if(!chance || prob(chance))
+ play(get_sound(looped))
+ addtimer(CALLBACK(src, .proc/sound_loop, ++looped), mid_length)
+
+/datum/looping_sound/proc/play(soundfile)
+ var/list/atoms_cache = output_atoms
+ var/sound/S = sound(soundfile)
+ if(direct)
+ S.channel = open_sound_channel()
+ S.volume = volume
+ for(var/i in 1 to atoms_cache.len)
+ var/atom/thing = atoms_cache[i]
+ if(direct)
+ SEND_SOUND(thing, S)
+ else
+ playsound(thing, S, volume)
+
+/datum/looping_sound/proc/get_sound(looped, _mid_sounds)
+ if(!_mid_sounds)
+ . = mid_sounds
+ else
+ . = _mid_sounds
+ while(!isfile(.) && !isnull(.))
+ . = pickweight(.)
+
+/datum/looping_sound/proc/on_start()
+ var/start_wait = 0
+ if(start_sound)
+ play(start_sound)
+ start_wait = start_length
+ addtimer(CALLBACK(src, .proc/sound_loop), start_wait)
+
+/datum/looping_sound/proc/on_stop(looped)
+ if(end_sound)
+ play(end_sound)
\ No newline at end of file
diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm
new file mode 100644
index 00000000000..b1f5bdc6908
--- /dev/null
+++ b/code/datums/looping_sounds/machinery_sounds.dm
@@ -0,0 +1,7 @@
+/datum/looping_sound/showering
+ start_sound = 'sound/machines/shower/shower_start.ogg'
+ start_length = 2
+ mid_sounds = list('sound/machines/shower/shower_mid1.ogg' = 1,'sound/machines/shower/shower_mid2.ogg' = 1,'sound/machines/shower/shower_mid3.ogg' = 1)
+ mid_length = 10
+ end_sound = 'sound/machines/shower/shower_end.ogg'
+ volume = 20
\ No newline at end of file
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 5fee7994a83..c4674c64f90 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -38,8 +38,8 @@
var/memory
- var/assigned_role
- var/special_role
+ var/assigned_role //assigned role is what job you're assigned to when you join the station.
+ var/special_role //special roles are typically reserved for antags or roles like ERT. If you want to avoid a character being automatically announced by the AI, on arrival (becuase they're an off station character or something); ensure that special_role and assigned_role are equal.
var/list/restricted_roles = list()
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
@@ -54,6 +54,7 @@
var/has_been_rev = 0//Tracks if this mind has been a rev or not
var/miming = 0 // Mime's vow of silence
+ var/list/antag_datums
var/speech_span // What span any body this mind has talks in.
var/datum/faction/faction //associated faction
var/datum/changeling/changeling //changeling holder
@@ -72,17 +73,29 @@
var/brigged_since = -1
var/suicided = FALSE
- New(var/key)
- src.key = key
-
//put this here for easier tracking ingame
var/datum/money_account/initial_account
//zealot_master is a reference to the mob that converted them into a zealot (for ease of investigation and such)
var/mob/living/carbon/human/zealot_master = null
+/datum/mind/New(var/key)
+ src.key = key
+
+
+/datum/mind/Destroy()
+ ticker.minds -= src
+ if(islist(antag_datums))
+ for(var/i in antag_datums)
+ var/datum/antagonist/antag_datum = i
+ if(antag_datum.delete_on_mind_deletion)
+ qdel(i)
+ antag_datums = null
+ return ..()
+
/datum/mind/proc/transfer_to(mob/living/new_character)
var/datum/atom_hud/antag/hud_to_transfer = antag_hud //we need this because leave_hud() will clear this list
+ var/mob/living/old_current = current
if(!istype(new_character))
log_runtime(EXCEPTION("transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob."), src)
if(current) //remove ourself from our old body's mind variable
@@ -95,6 +108,9 @@
new_character.mind.current = null
current = new_character //link ourself to our new body
new_character.mind = src //and link our new body to ourself
+ for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body
+ var/datum/antagonist/A = a
+ A.on_body_transfer(old_current, current)
transfer_antag_huds(hud_to_transfer) //inherit the antag HUD
transfer_actions(new_character)
@@ -525,8 +541,8 @@
new_objective = new objective_path
new_objective.owner = src
new_objective:target = new_target:mind
- //Will display as special role if the target is set as MODE. Ninjas/commandos/nuke ops.
- new_objective.explanation_text = "[objective_type] [new_target:real_name], the [new_target:mind:assigned_role=="MODE" ? (new_target:mind:special_role) : (new_target:mind:assigned_role)]."
+ //Will display as special role if assigned mode is equal to special role.. Ninjas/commandos/nuke ops.
+ new_objective.explanation_text = "[objective_type] [new_target:real_name], the [new_target:mind:assigned_role == new_target:mind:special_role ? (new_target:mind:special_role) : (new_target:mind:assigned_role)]."
if("destroy")
var/list/possible_targets = active_ais(1)
@@ -726,7 +742,7 @@
if(src in ticker.mode.revolutionaries)
ticker.mode.revolutionaries -= src
ticker.mode.update_rev_icons_removed(src)
- to_chat(current, "\red You have proven your devotion to revolution! You are a head revolutionary now!")
+ to_chat(current, "You have proven your devotion to revolution! You are a head revolutionary now!")
else if(!(src in ticker.mode.head_revolutionaries))
to_chat(current, "You are a member of the revolutionaries' leadership now!")
else
@@ -1211,37 +1227,60 @@
message_admins("[key_name_admin(usr)] has announced [key_name_admin(current)]'s objectives")
edit_memory()
-/*
-/datum/mind/proc/clear_memory(var/silent = 1)
- var/datum/game_mode/current_mode = ticker.mode
- // remove traitor uplinks
- var/list/L = current.get_contents()
- for(var/t in L)
- if(istype(t, /obj/item/pda))
- if(t:uplink) qdel(t:uplink)
- t:uplink = null
- else if(istype(t, /obj/item/radio))
- if(t:traitorradio) qdel(t:traitorradio)
- t:traitorradio = null
- t:traitor_frequency = 0.0
- else if(istype(t, /obj/item/SWF_uplink) || istype(t, /obj/item/syndicate_uplink))
- if(t:origradio)
- var/obj/item/radio/R = t:origradio
- R.loc = current.loc
- R.traitorradio = null
- R.traitor_frequency = 0.0
- qdel(t)
- // remove wizards spells
- //If there are more special powers that need removal, they can be procced into here./N
- current.spellremove(current)
+// Datum antag mind procs
+/datum/mind/proc/add_antag_datum(datum_type_or_instance, team)
+ if(!datum_type_or_instance)
+ return
+ var/datum/antagonist/A
+ if(!ispath(datum_type_or_instance))
+ A = datum_type_or_instance
+ if(!istype(A))
+ return
+ else
+ A = new datum_type_or_instance()
+ //Choose snowflake variation if antagonist handles it
+ var/datum/antagonist/S = A.specialization(src)
+ if(S && S != A)
+ qdel(A)
+ A = S
+ if(!A.can_be_owned(src))
+ qdel(A)
+ return
+ A.owner = src
+ LAZYADD(antag_datums, A)
+ A.create_team(team)
+ var/datum/team/antag_team = A.get_team()
+ if(antag_team)
+ antag_team.add_member(src)
+ A.on_gain()
+ return A
- // clear memory
- memory = ""
- special_role = null
+/datum/mind/proc/remove_antag_datum(datum_type)
+ if(!datum_type)
+ return
+ var/datum/antagonist/A = has_antag_datum(datum_type)
+ if(A)
+ A.on_removal()
+ return TRUE
-*/
+
+/datum/mind/proc/remove_all_antag_datums() //For the Lazy amongst us.
+ for(var/a in antag_datums)
+ var/datum/antagonist/A = a
+ A.on_removal()
+
+/datum/mind/proc/has_antag_datum(datum_type, check_subtypes = TRUE)
+ if(!datum_type)
+ return
+ . = FALSE
+ for(var/a in antag_datums)
+ var/datum/antagonist/A = a
+ if(check_subtypes && istype(A, datum_type))
+ return A
+ else if(A.type == datum_type)
+ return A
/datum/mind/proc/find_syndicate_uplink()
var/list/L = current.get_contents()
@@ -1273,7 +1312,7 @@
else
current.real_name = "[syndicate_name()] Operative #[ticker.mode.syndicates.len-1]"
special_role = SPECIAL_ROLE_NUKEOPS
- assigned_role = "MODE"
+ assigned_role = SPECIAL_ROLE_NUKEOPS
to_chat(current, "You are a [syndicate_name()] agent!")
ticker.mode.forge_syndicate_objectives(src)
ticker.mode.greet_syndicate(src)
@@ -1308,7 +1347,7 @@
if(!(src in ticker.mode.wizards))
ticker.mode.wizards += src
special_role = SPECIAL_ROLE_WIZARD
- assigned_role = "MODE"
+ assigned_role = SPECIAL_ROLE_WIZARD
//ticker.mode.learn_basic_spells(current)
if(!wizardstart.len)
current.loc = pick(latejoin)
@@ -1514,7 +1553,7 @@
var/datum/objective/protect/mindslave/MS = new
MS.owner = src
MS.target = missionary.mind
- MS.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role=="MODE" ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]."
+ MS.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role == missionary.mind.special_role ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]."
objectives += MS
for(var/datum/objective/objective in objectives)
to_chat(current, "Objective #1: [objective.explanation_text]")
@@ -1538,8 +1577,7 @@
H.update_inv_w_uniform(0,0)
add_attack_logs(missionary, current, "Converted to a zealot for [convert_duration/600] minutes")
- addtimer(src, "remove_zealot", convert_duration, FALSE, jumpsuit) //deconverts after the timer expires
-
+ addtimer(CALLBACK(src, .proc/remove_zealot, jumpsuit), convert_duration) //deconverts after the timer expires
return 1
/datum/mind/proc/remove_zealot(obj/item/clothing/under/jumpsuit = null)
diff --git a/code/datums/modules.dm b/code/datums/modules.dm
deleted file mode 100644
index d01bded3254..00000000000
--- a/code/datums/modules.dm
+++ /dev/null
@@ -1,63 +0,0 @@
-// module datum.
-// this is per-object instance, and shows the condition of the modules in the object
-// actual modules needed is referenced through modulestypes and the object type
-
-/datum/module
- var/status // bits set if working, 0 if broken
- var/installed // bits set if installed, 0 if missing
-
-// moduletypes datum
-// this is per-object type, and shows the modules needed for a type of object
-
-/datum/moduletypes
- var/list/modcount = list() // assoc list of the count of modules for a type
-
-
-var/list/modules = list( // global associative list
-"/obj/machinery/power/apc" = "card_reader,power_control,id_auth,cell_power,cell_charge")
-
-
-/datum/module/New(var/obj/O)
-
- var/type = O.type // the type of the creating object
-
- var/mneed = mods.inmodlist(type) // find if this type has modules defined
-
- if(!mneed) // not found in module list?
- qdel(src) // delete self, thus ending proc
- return
-
- var/needed = mods.getbitmask(type) // get a bitmask for the number of modules in this object
- status = needed
- installed = needed
-
-/datum/moduletypes/proc/addmod(var/type, var/modtextlist)
- modules += type // index by type text
- modules[type] = modtextlist
-
-/datum/moduletypes/proc/inmodlist(var/type)
- return ("[type]" in modules)
-
-/datum/moduletypes/proc/getbitmask(var/type)
- var/count = modcount["[type]"]
- if(count)
- return 2**count-1
-
- var/modtext = modules["[type]"]
- var/num = 1
- var/pos = 1
-
- while(1)
- pos = findtext(modtext, ",", pos, 0)
- if(!pos)
- break
- else
- pos++
- num++
-
- modcount += "[type]"
- modcount["[type]"] = num
-
- return 2**num-1
-
-
diff --git a/code/datums/outfits/outfit_admin.dm b/code/datums/outfits/outfit_admin.dm
index 525880ee314..9e4bba0515c 100644
--- a/code/datums/outfits/outfit_admin.dm
+++ b/code/datums/outfits/outfit_admin.dm
@@ -145,6 +145,7 @@
belt = /obj/item/gun/projectile/automatic/pistol/deagle/camo
l_ear = /obj/item/radio/headset/syndicate/alt
l_pocket = /obj/item/pinpointer/advpinpointer
+ r_pocket = null // stop them getting a radio uplink, they get an implant instead
backpack_contents = list(
/obj/item/storage/box/engineer = 1,
@@ -158,7 +159,6 @@
id_icon = "commander"
id_access = "Syndicate Operative Leader"
- uplink_uses = 500
/datum/outfit/admin/syndicate/officer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
. = ..()
@@ -613,15 +613,16 @@
uniform = /obj/item/clothing/under/solgov/rep
back = /obj/item/storage/backpack/satchel
+ glasses = /obj/item/clothing/glasses/hud/security/night
gloves = /obj/item/clothing/gloves/color/white
shoes = /obj/item/clothing/shoes/centcom
- l_ear = /obj/item/radio/headset
+ l_ear = /obj/item/radio/headset/ert
id = /obj/item/card/id/silver
r_pocket = /obj/item/lighter/zippo/blue
l_pocket = /obj/item/storage/fancy/cigarettes/cigpack_robustgold
pda = /obj/item/pda
backpack_contents = list(
- /obj/item/storage/box/survival = 1,
+ /obj/item/storage/box/responseteam = 1,
/obj/item/implanter/dust = 1,
/obj/item/implanter/death_alarm = 1,
)
@@ -633,25 +634,33 @@
var/obj/item/card/id/I = H.wear_id
if(istype(I))
- apply_to_card(I, H, get_centcom_access("VIP Guest"), "Solar Federation Representative")
+ apply_to_card(I, H, get_all_accesses(), name, "lifetimeid")
/datum/outfit/admin/solgov
name = "Solar Federation Marine"
uniform = /obj/item/clothing/under/solgov
+ suit = /obj/item/clothing/suit/armor/bulletproof
back = /obj/item/storage/backpack/security
+ belt = /obj/item/storage/belt/military/assault
head = /obj/item/clothing/head/soft/solgov
+ glasses = /obj/item/clothing/glasses/hud/security/night
gloves = /obj/item/clothing/gloves/combat
shoes = /obj/item/clothing/shoes/combat
+ l_ear = /obj/item/radio/headset/ert
id = /obj/item/card/id
l_hand = /obj/item/gun/projectile/automatic/ar
+ r_pocket = /obj/item/flashlight/seclite
+ pda = /obj/item/pda
backpack_contents = list(
- /obj/item/storage/box/survival = 1,
- /obj/item/kitchen/knife/combat = 1,
+ /obj/item/storage/box/responseteam = 1,
/obj/item/ammo_box/magazine/m556 = 3,
- /obj/item/clothing/shoes/magboots = 1
+ /obj/item/clothing/shoes/magboots = 1,
+ /obj/item/gun/projectile/automatic/pistol/m1911 = 1,
+ /obj/item/ammo_box/magazine/m45 = 2
)
+ var/is_tsf_lieutenant = FALSE
/datum/outfit/admin/solgov/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -659,9 +668,14 @@
if(visualsOnly)
return
+ if(is_tsf_lieutenant)
+ H.real_name = "Lieutenant [pick(last_names)]"
+ else
+ H.real_name = "[pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant First Class", "Master Sergeant", "Sergeant Major")] [pick(last_names)]"
+ H.name = H.real_name
var/obj/item/card/id/I = H.wear_id
if(istype(I))
- apply_to_card(I, H, get_centcom_access("VIP Guest"), name)
+ apply_to_card(I, H, get_all_accesses(), name, "lifetimeid")
/datum/outfit/admin/solgov/lieutenant
name = "Solar Federation Lieutenant"
@@ -670,14 +684,16 @@
head = /obj/item/clothing/head/soft/solgov/command
back = /obj/item/storage/backpack/satchel
l_hand = null
- belt = /obj/item/gun/projectile/automatic/pistol/deagle
+ l_pocket = /obj/item/pinpointer/advpinpointer
backpack_contents = list(
- /obj/item/storage/box/survival = 1,
- /obj/item/kitchen/knife/combat = 1,
+ /obj/item/storage/box/responseteam = 1,
/obj/item/melee/classic_baton/telescopic = 1,
- /obj/item/ammo_box/magazine/m50 = 2,
- /obj/item/clothing/shoes/magboots/advance = 1
+ /obj/item/clothing/shoes/magboots/advance = 1,
+ /obj/item/gun/projectile/automatic/pistol/deagle = 1,
+ /obj/item/ammo_box/magazine/m50 = 2
)
+ is_tsf_lieutenant = TRUE
+
/datum/outfit/admin/chrono
name = "Chrono Legionnaire"
diff --git a/code/datums/spells/emplosion.dm b/code/datums/spells/emplosion.dm
index 1ba430ad27e..b2f0a228282 100644
--- a/code/datums/spells/emplosion.dm
+++ b/code/datums/spells/emplosion.dm
@@ -10,6 +10,6 @@
/obj/effect/proc_holder/spell/targeted/emplosion/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
- empulse(target.loc, emp_heavy, emp_light)
+ empulse(target.loc, emp_heavy, emp_light, 1)
- return
\ No newline at end of file
+ return
diff --git a/code/datums/spells/ethereal_jaunt.dm b/code/datums/spells/ethereal_jaunt.dm
index 43c3d3a61cd..6e3ead3849e 100644
--- a/code/datums/spells/ethereal_jaunt.dm
+++ b/code/datums/spells/ethereal_jaunt.dm
@@ -26,7 +26,7 @@
if(!target.can_safely_leave_loc()) // No more brainmobs hopping out of their brains
to_chat(target, "You are somehow too bound to your current location to abandon it.")
continue
- addtimer(src, "do_jaunt", 0, FALSE, target)
+ INVOKE_ASYNC(src, .proc/do_jaunt, target)
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/do_jaunt(mob/living/target)
target.notransform = 1
diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm
index 9a5bf86665c..750f7bfd70c 100644
--- a/code/datums/uplink_item.dm
+++ b/code/datums/uplink_item.dm
@@ -1336,6 +1336,13 @@ var/list/uplink_items = list()
item = /obj/item/storage/fancy/cigarettes/cigpack_syndicate
cost = 2
+/datum/uplink_item/badass/rapid
+ name = "Gloves of the North Star"
+ desc = "These gloves let the user punch people very fast. Does not improve weapon attack speed."
+ reference = "RPGD"
+ item = /obj/item/clothing/gloves/fingerless/rapid
+ cost = 8
+
/datum/uplink_item/badass/bundle
name = "Syndicate Bundle"
desc = "Syndicate Bundles are specialised groups of items that arrive in a plain box. These items are collectively worth more than 20 telecrystals, but you do not know which specialisation you will receive."
diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm
index c87b2b455e7..320cc137806 100644
--- a/code/datums/weather/weather.dm
+++ b/code/datums/weather/weather.dm
@@ -31,7 +31,7 @@
var/list/impacted_areas = list() //Areas to be affected by the weather, calculated when the weather begins
var/target_z = MAIN_STATION //The z-level to affect
var/list/protected_areas = list()//Areas that are protected and excluded from the affected areas.
-
+
var/overlay_layer = 10 //Since it's above everything else, this is the layer used by default. 2 is below mobs and walls if you need to use that.
var/aesthetic = FALSE //If the weather has no purpose other than looks
var/immunity_type = "storm" //Used by mobs to prevent them from being affected by the weather
@@ -70,7 +70,7 @@
to_chat(M, telegraph_message)
if(telegraph_sound)
M << sound(telegraph_sound)
- addtimer(src, "start", telegraph_duration)
+ addtimer(CALLBACK(src, .proc/start), telegraph_duration)
/datum/weather/proc/start()
if(stage >= MAIN_STAGE)
@@ -85,7 +85,7 @@
if(weather_sound)
M << sound(weather_sound)
weather_master.processing_weather |= src
- addtimer(src, "wind_down", weather_duration)
+ addtimer(CALLBACK(src, .proc/wind_down), weather_duration)
/datum/weather/proc/wind_down()
if(stage >= WIND_DOWN_STAGE)
@@ -100,7 +100,7 @@
if(end_sound)
M << sound(end_sound)
weather_master.processing_weather -= src
- addtimer(src, "end", end_duration)
+ addtimer(CALLBACK(src, .proc/end), end_duration)
/datum/weather/proc/end()
if(stage == END_STAGE)
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 83880039a73..8a9a108c7b3 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -42,10 +42,16 @@
power_equip = 0 //rastaf0
power_environ = 0 //rastaf0
- power_change() // all machines set to current power level, also updates lighting icon
-
blend_mode = BLEND_MULTIPLY // Putting this in the constructor so that it stops the icons being screwed up in the map editor.
+/area/Initialize()
+ ..()
+ return INITIALIZE_HINT_LATELOAD
+
+/area/LateInitialize()
+ . = ..()
+ power_change() // all machines set to current power level, also updates lighting icon
+
/area/proc/get_cameras()
var/list/cameras = list()
for(var/obj/machinery/camera/C in src)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index d57199d5f91..19af319aa20 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -42,6 +42,62 @@
var/admin_spawned = 0 //was this spawned by an admin? used for stat tracking stuff.
+ var/initialized = FALSE
+
+/atom/New(loc, ...)
+ if(use_preloader && (src.type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New()
+ _preloader.load(src)
+ . = ..()
+ attempt_init(...)
+
+// This is distinct from /tg/ because of our space management system
+// This is overriden in /atom/movable and the parent isn't called if the SMS wants to deal with it's init
+/atom/proc/attempt_init(loc, ...)
+ var/do_initialize = SSatoms.initialized
+ if(do_initialize != INITIALIZATION_INSSATOMS)
+ args[1] = do_initialize == INITIALIZATION_INNEW_MAPLOAD
+ if(SSatoms.InitAtom(src, args))
+ // we were deleted
+ return
+
+
+//Called after New if the map is being loaded. mapload = TRUE
+//Called from base of New if the map is not being loaded. mapload = FALSE
+//This base must be called or derivatives must set initialized to TRUE
+//must not sleep
+//Other parameters are passed from New (excluding loc), this does not happen if mapload is TRUE
+//Must return an Initialize hint. Defined in __DEFINES/subsystems.dm
+
+//Note: the following functions don't call the base for optimization and must copypasta:
+// /turf/Initialize
+// /turf/open/space/Initialize
+
+/atom/proc/Initialize(mapload, ...)
+ if(initialized)
+ stack_trace("Warning: [src]([type]) initialized multiple times!")
+ initialized = TRUE
+
+ if(light_power && light_range)
+ update_light()
+
+ if(opacity && isturf(loc))
+ var/turf/T = loc
+ T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guranteed to be on afterwards anyways.
+
+ ComponentInitialize()
+
+ return INITIALIZE_HINT_NORMAL
+
+
+//called if Initialize returns INITIALIZE_HINT_LATELOAD
+/atom/proc/LateInitialize()
+ return
+
+// Put your AddComponent() calls here
+/atom/proc/ComponentInitialize()
+ return
+
+
/atom/proc/onCentcom()
var/turf/T = get_turf(src)
if(!T)
@@ -242,7 +298,7 @@
/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...).
- addtimer(src, "hitby_react", 2, TRUE, AM)
+ addtimer(CALLBACK(src, .proc/hitby_react, AM), 2)
/atom/proc/hitby_react(atom/movable/AM)
if(AM && isturf(AM.loc))
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 3fdc402bb8a..7ab561f0814 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -24,16 +24,19 @@
var/area/areaMaster
- var/auto_init = 1
-
/atom/movable/New()
. = ..()
areaMaster = get_area_master(src)
- // If you're wondering what goofery this is, this is for things that need the environment
- // around them set up - like `air_update_turf` and the like
- if((ticker && ticker.current_state >= GAME_STATE_SETTING_UP))
- attempt_init()
+/atom/movable/attempt_init()
+ if(ticker && ticker.current_state >= GAME_STATE_SETTING_UP)
+ var/turf/T = get_turf(src)
+ if(T && space_manager.is_zlevel_dirty(T.z))
+ space_manager.postpone_init(T.z, src)
+ return
+ . = ..()
+
+
/atom/movable/Destroy()
if(loc)
@@ -53,19 +56,6 @@
pulledby = null
return ..()
-// used to provide a good interface for the init delay system to step in
-// and we don't need to call `get_turf` until the game's started
-// at which point object creations are a fair toss more seldom
-/atom/movable/proc/attempt_init()
- var/turf/T = get_turf(src)
- if(T && space_manager.is_zlevel_dirty(T.z))
- space_manager.postpone_init(T.z, src)
- else if(auto_init)
- initialize()
-
-/atom/movable/proc/initialize()
- return
-
// Used in shuttle movement and AI eye stuff.
// Primarily used to notify objects being moved by a shuttle/bluespace fuckup.
/atom/movable/proc/setLoc(var/T, var/teleported=0)
@@ -176,11 +166,11 @@
/mob/living/forceMove(atom/destination)
if(buckled)
- addtimer(src, "check_buckled", 1, TRUE)
+ addtimer(CALLBACK(src, .proc/check_buckled), 1, TIMER_UNIQUE)
if(buckled_mob)
- addtimer(buckled_mob, "check_buckled", 1, TRUE)
+ addtimer(CALLBACK(buckled_mob, .proc/check_buckled), 1, TIMER_UNIQUE)
if(pulling)
- addtimer(src, "check_pull", 1, TRUE)
+ addtimer(CALLBACK(src, .proc/check_pull), 1, TIMER_UNIQUE)
. = ..()
if(client)
reset_perspective(destination)
@@ -373,3 +363,70 @@
target.fingerprints += fingerprints
target.fingerprintshidden += fingerprintshidden
target.fingerprintslast = fingerprintslast
+
+/atom/movable/proc/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
+ if(!no_effect && (visual_effect_icon || used_item))
+ do_item_attack_animation(A, visual_effect_icon, used_item)
+
+ if(A == src)
+ return //don't do an animation if attacking self
+ var/pixel_x_diff = 0
+ var/pixel_y_diff = 0
+ var/final_pixel_y = initial(pixel_y)
+ if(end_pixel_y)
+ final_pixel_y = end_pixel_y
+
+ var/direction = get_dir(src, A)
+ if(direction & NORTH)
+ pixel_y_diff = 8
+ else if(direction & SOUTH)
+ pixel_y_diff = -8
+
+ if(direction & EAST)
+ pixel_x_diff = 8
+ else if(direction & WEST)
+ pixel_x_diff = -8
+
+ animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2)
+ animate(pixel_x = initial(pixel_x), pixel_y = final_pixel_y, time = 2)
+
+/atom/movable/proc/do_item_attack_animation(atom/A, visual_effect_icon, obj/item/used_item)
+ var/image/I
+ if(visual_effect_icon)
+ I = image('icons/effects/effects.dmi', A, visual_effect_icon, A.layer + 0.1)
+ else if(used_item)
+ I = image(used_item.icon, A, used_item.icon_state, A.layer + 0.1)
+
+ // Scale the icon.
+ I.transform *= 0.75
+ // The icon should not rotate.
+ I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
+
+ // Set the direction of the icon animation.
+ var/direction = get_dir(src, A)
+ if(direction & NORTH)
+ I.pixel_y = -16
+ else if(direction & SOUTH)
+ I.pixel_y = 16
+
+ if(direction & EAST)
+ I.pixel_x = -16
+ else if(direction & WEST)
+ I.pixel_x = 16
+
+ if(!direction) // Attacked self?!
+ I.pixel_z = 16
+
+ if(!I)
+ return
+
+ // Who can see the attack?
+ var/list/viewing = list()
+ for(var/mob/M in viewers(A))
+ if(M.client && M.client.prefs.show_ghostitem_attack)
+ viewing |= M.client
+
+ flick_overlay(I, viewing, 5) // 5 ticks/half a second
+
+ // And animate the attack!
+ animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3)
\ No newline at end of file
diff --git a/code/game/gamemodes/blob/blobs/blob_mobs.dm b/code/game/gamemodes/blob/blobs/blob_mobs.dm
index c6dc0833afb..bae37c04c2c 100644
--- a/code/game/gamemodes/blob/blobs/blob_mobs.dm
+++ b/code/game/gamemodes/blob/blobs/blob_mobs.dm
@@ -62,7 +62,7 @@
factory.spores += src
..()
-/mob/living/simple_animal/hostile/blob/blobspore/Life()
+/mob/living/simple_animal/hostile/blob/blobspore/Life(seconds, times_fired)
if(!is_zombie && isturf(src.loc))
for(var/mob/living/carbon/human/H in oview(src,1)) //Only for corpse right next to/on same tile
diff --git a/code/game/gamemodes/blob/blobs/core.dm b/code/game/gamemodes/blob/blobs/core.dm
index 9dcb5b7e3eb..0e1fc7daa86 100644
--- a/code/game/gamemodes/blob/blobs/core.dm
+++ b/code/game/gamemodes/blob/blobs/core.dm
@@ -60,7 +60,7 @@
/obj/structure/blob/core/RegenHealth()
return // Don't regen, we handle it in Life()
-/obj/structure/blob/core/Life()
+/obj/structure/blob/core/Life(seconds, times_fired)
if(!overmind)
create_overmind()
else
diff --git a/code/game/gamemodes/blob/blobs/node.dm b/code/game/gamemodes/blob/blobs/node.dm
index 232511744ea..19ac320287a 100644
--- a/code/game/gamemodes/blob/blobs/node.dm
+++ b/code/game/gamemodes/blob/blobs/node.dm
@@ -28,7 +28,7 @@
processing_objects.Remove(src)
return ..()
-/obj/structure/blob/node/Life()
+/obj/structure/blob/node/Life(seconds, times_fired)
if(overmind)
for(var/i = 1; i < 8; i += i)
Pulse(5, i, overmind.blob_reagent_datum.color)
diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm
index 5da84fbc460..60ea94befb0 100644
--- a/code/game/gamemodes/blob/overmind.dm
+++ b/code/game/gamemodes/blob/overmind.dm
@@ -36,7 +36,7 @@
updateallghostimages()
..()
-/mob/camera/blob/Life()
+/mob/camera/blob/Life(seconds, times_fired)
if(!blob_core)
qdel(src)
..()
diff --git a/code/game/gamemodes/changeling/powers/biodegrade.dm b/code/game/gamemodes/changeling/powers/biodegrade.dm
index 5e4b0e7fa12..3103416b9e4 100644
--- a/code/game/gamemodes/changeling/powers/biodegrade.dm
+++ b/code/game/gamemodes/changeling/powers/biodegrade.dm
@@ -18,7 +18,7 @@
return FALSE
user.visible_message("[user] vomits a glob of acid on \his [O]!", \
"We vomit acidic ooze onto our restraints!")
- addtimer(src, "dissolve_handcuffs", 30, FALSE, user, O)
+ addtimer(CALLBACK(src, .proc/dissolve_handcuffs, user, O), 30)
used = TRUE
if(user.wear_suit && user.wear_suit.breakouttime && !used)
@@ -27,7 +27,7 @@
return FALSE
user.visible_message("[user] vomits a glob of acid across the front of \his [S]!", \
"We vomit acidic ooze onto our straight jacket!")
- addtimer(src, "dissolve_straightjacket", 30, FALSE, user, S)
+ addtimer(CALLBACK(src, .proc/dissolve_straightjacket, user, S), 30)
used = TRUE
@@ -37,7 +37,7 @@
return FALSE
C.visible_message("[C]'s hinges suddenly begin to melt and run!")
to_chat(user, "We vomit acidic goop onto the interior of [C]!")
- addtimer(src, "open_closet", 70, FALSE, user, C)
+ addtimer(CALLBACK(src, .proc/open_closet, user, C), 70)
used = TRUE
if(istype(user.loc, /obj/structure/spider/cocoon) && !used)
@@ -46,7 +46,7 @@
return FALSE
C.visible_message("[src] shifts and starts to fall apart!")
to_chat(user, "We secrete acidic enzymes from our skin and begin melting our cocoon...")
- addtimer(src, "dissolve_cocoon", 25, FALSE, user, C) //Very short because it's just webs
+ addtimer(CALLBACK(src, .proc/dissolve_cocoon, user, C), 25) //Very short because it's just webs
used = TRUE
if(used)
diff --git a/code/game/gamemodes/changeling/powers/fakedeath.dm b/code/game/gamemodes/changeling/powers/fakedeath.dm
index 156e8ffb896..a166fd74502 100644
--- a/code/game/gamemodes/changeling/powers/fakedeath.dm
+++ b/code/game/gamemodes/changeling/powers/fakedeath.dm
@@ -17,7 +17,7 @@
user.status_flags |= FAKEDEATH //play dead
user.update_canmove()
- addtimer(src, "ready_to_regenerate", LING_FAKEDEATH_TIME, FALSE, user)
+ addtimer(CALLBACK(src, .proc/ready_to_regenerate, user), LING_FAKEDEATH_TIME)
feedback_add_details("changeling_powers","FD")
return 1
diff --git a/code/game/gamemodes/changeling/powers/fleshmend.dm b/code/game/gamemodes/changeling/powers/fleshmend.dm
index 08786b6d6db..56417ac4335 100644
--- a/code/game/gamemodes/changeling/powers/fleshmend.dm
+++ b/code/game/gamemodes/changeling/powers/fleshmend.dm
@@ -31,7 +31,7 @@
by quick repeated use!")
recent_uses++
- addtimer(src, "fleshmend", 0, FALSE, user)
+ INVOKE_ASYNC(src, .proc/fleshmend, user)
feedback_add_details("changeling_powers","RR")
return TRUE
diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm
index 4e084e8b720..8f0aa4d210f 100644
--- a/code/game/gamemodes/changeling/powers/mutations.dm
+++ b/code/game/gamemodes/changeling/powers/mutations.dm
@@ -278,7 +278,7 @@
C.visible_message("[src] impales [C] with [I]!", "[src] impales you with [I]!")
C.apply_damage(I.force, BRUTE, "chest")
- do_attack_animation(C)
+ do_item_attack_animation(C, used_item = I)
add_blood(C)
playsound(get_turf(src), I.hitsound, 75, 1)
diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm
index 2bf4933e108..b79dc85c2d5 100644
--- a/code/game/gamemodes/cult/runes.dm
+++ b/code/game/gamemodes/cult/runes.dm
@@ -740,7 +740,7 @@ var/list/teleport_runes = list()
to_chat(L, "You chant in unison and a colossal burst of energy knocks you backward!")
L.Weaken(2)
qdel(src) //delete before pulsing because it's a delay reee
- empulse(E, 9*invokers.len, 12*invokers.len) // Scales now, from a single room to most of the station depending on # of chanters
+ empulse(E, 9*invokers.len, 12*invokers.len, 1) // Scales now, from a single room to most of the station depending on # of chanters
//Rite of Astral Communion: Separates one's spirit from their body. They will take damage while it is active.
/obj/effect/rune/astral
diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm
index e909a33410f..1268765708d 100644
--- a/code/game/gamemodes/cult/talisman.dm
+++ b/code/game/gamemodes/cult/talisman.dm
@@ -220,7 +220,7 @@
. = ..()
user.visible_message("[user]'s hand flashes a bright blue!", \
"You speak the words of the talisman, emitting an EMP blast.")
- empulse(src, 4, 8)
+ empulse(src, 4, 8, 1)
//Rite of Disorientation: Stuns and inhibit speech on a single target for quite some time
@@ -419,4 +419,4 @@
/obj/item/restraints/handcuffs/energy/cult/used/dropped(mob/user)
user.visible_message("[user]'s shackles shatter in a discharge of dark magic!", \
"Your [src] shatters in a discharge of dark magic!")
- . = ..()
\ No newline at end of file
+ . = ..()
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 4a2622c536d..702b59853dc 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -107,7 +107,7 @@
tries_left = 5 //reset our tries since we found a new chump
//make sure we have chumps before we try misinforming them. if we don't make a note of it.
if(!chumps.len)
- log_debug("Game mode failed to find ANY chumps. This is likely due to the server being in extreme low-pop with no one set to opposed or skeptical.")
+ log_debug("Game mode failed to find ANY chumps. This is likely due to the server being in extreme low-pop with no one set to opposed or skeptical.")
return 0
//we've got chumps! misinform them!
for(var/mob/living/carbon/human/chump in chumps)
@@ -493,31 +493,36 @@ proc/display_roundstart_logout_report()
message_admins("[M] ([M.key] has been converted into [role_type] with an active antagonist jobban for said role since no ghost has volunteered to take their place.")
to_chat(M, "You have been converted into [role_type] with an active jobban. Any further violations of the rules on your part are likely to result in a permanent ban.")
-/datum/game_mode/proc/printplayer(datum/mind/ply, fleecheck)
- var/text = "
[ply.key] was [ply.name] the [ply.assigned_role] and"
+/proc/printplayer(datum/mind/ply, fleecheck)
+ var/jobtext = ""
+ if(ply.assigned_role)
+ jobtext = " the [ply.assigned_role]"
+ var/text = "[ply.key] was [ply.name][jobtext] and"
if(ply.current)
if(ply.current.stat == DEAD)
- text += " died"
+ text += " died"
else
- text += " survived"
- if(fleecheck && !is_station_level(ply.current.z))
- text += " while fleeing the station"
+ text += " survived"
+ if(fleecheck)
+ var/turf/T = get_turf(ply.current)
+ if(!T || !is_station_level(T.z))
+ text += " while fleeing the station"
if(ply.current.real_name != ply.name)
text += " as [ply.current.real_name]"
else
- text += " had their body destroyed"
+ text += " had their body destroyed"
return text
-/datum/game_mode/proc/printobjectives(datum/mind/ply)
- var/text = ""
+/proc/printobjectives(datum/mind/ply)
+ var/list/objective_parts = list()
var/count = 1
for(var/datum/objective/objective in ply.objectives)
if(objective.check_completion())
- text += "
Objective #[count]: [objective.explanation_text] Success!"
+ objective_parts += "Objective #[count]: [objective.explanation_text] Success!"
else
- text += "
Objective #[count]: [objective.explanation_text] Fail."
+ objective_parts += "Objective #[count]: [objective.explanation_text] Fail."
count++
- return text
+ return objective_parts.Join("
")
/datum/game_mode/proc/generate_station_goals()
var/list/possible = list()
diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm
index 8058ff6e5c9..0c609c818b4 100644
--- a/code/game/gamemodes/gameticker.dm
+++ b/code/game/gamemodes/gameticker.dm
@@ -368,7 +368,7 @@ var/round_start_time = 0
if(player && player.mind && player.mind.assigned_role)
if(player.mind.assigned_role == "Captain")
captainless=0
- if(player.mind.assigned_role != "MODE")
+ if(player.mind.assigned_role != player.mind.special_role)
job_master.EquipRank(player, player.mind.assigned_role, 0)
EquipCustomItems(player)
if(captainless)
diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm
index 0693ca9b279..3b908952de7 100644
--- a/code/game/gamemodes/heist/heist.dm
+++ b/code/game/gamemodes/heist/heist.dm
@@ -51,7 +51,7 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind'
raider_num--
for(var/datum/mind/raider in raiders)
- raider.assigned_role = "MODE"
+ raider.assigned_role = SPECIAL_ROLE_RAIDER
raider.special_role = SPECIAL_ROLE_RAIDER
..()
return 1
diff --git a/code/game/gamemodes/intercept_report.dm b/code/game/gamemodes/intercept_report.dm
index 6cb2956d3ee..50b749a62a2 100644
--- a/code/game/gamemodes/intercept_report.dm
+++ b/code/game/gamemodes/intercept_report.dm
@@ -91,7 +91,7 @@
var/list/dudes = list()
for(var/mob/living/carbon/human/man in player_list)
if(!man.mind) continue
- if(man.mind.assigned_role=="MODE") continue
+ if(man.mind.assigned_role == man.mind.special_role) continue
dudes += man
if(dudes.len==0)
return null
@@ -210,14 +210,14 @@
var/prob_right_job = rand(prob_correct_job_lower, prob_correct_job_higher)
if(prob(prob_right_job))
if(correct_person)
- if(correct_person:assigned_role=="MODE")
+ if(correct_person:assigned_role == correct_person:special_role)
changeling_job = pick(joblist)
else
changeling_job = correct_person:assigned_role
else
changeling_job = pick(joblist)
if(prob(prob_right_dude) && ticker.mode == "changeling")
- if(correct_person:assigned_role=="MODE")
+ if(correct_person:assigned_role == correct_person:special_role)
changeling_name = correct_person:current
else
changeling_name = src.pick_mob()
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index 57ce00c92af..8f4b5dab95e 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -159,9 +159,8 @@
for(var/obj/machinery/door/D in airlocks)
if(!is_station_level(D.z))
continue
- spawn(0)
- D.hostile_lockdown(src)
- addtimer(D, "disable_lockdown", 900)
+ INVOKE_ASYNC(D, /obj/machinery/door.proc/hostile_lockdown, src)
+ addtimer(CALLBACK(D, /obj/machinery/door.proc/disable_lockdown), 900)
post_status("alert", "lockdown")
diff --git a/code/game/gamemodes/miniantags/abduction/abduction.dm b/code/game/gamemodes/miniantags/abduction/abduction.dm
index b54b18335ef..1c6dc7d3022 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction.dm
@@ -74,11 +74,11 @@
agent = preset_agent
- scientist.assigned_role = "MODE"
+ scientist.assigned_role = SPECIAL_ROLE_ABDUCTOR_SCIENTIST
scientist.special_role = SPECIAL_ROLE_ABDUCTOR_SCIENTIST
log_game("[key_name(scientist)] has been selected as an abductor team [team_number] scientist.")
- agent.assigned_role = "MODE"
+ agent.assigned_role = SPECIAL_ROLE_ABDUCTOR_AGENT
agent.special_role = SPECIAL_ROLE_ABDUCTOR_AGENT
log_game("[key_name(agent)] has been selected as an abductor team [team_number] agent.")
diff --git a/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm b/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm
index 328981b2ab5..2d3bed1e0cf 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm
@@ -5,19 +5,19 @@
/datum/surgery/organ_extraction/can_start(mob/user, mob/living/carbon/target, target_zone, obj/item/tool,datum/surgery/surgery)
if(!ishuman(user))
- return 0
+ return FALSE
if(ishuman(target))
var/mob/living/carbon/human/H = target
var/obj/item/organ/external/affected = H.get_organ(target_zone)
if(!affected)
- return 0
+ return FALSE
if(affected.status & ORGAN_ROBOT)
- return 0
+ return FALSE
var/mob/living/carbon/human/H = user
// You must either: Be of the abductor species, or contain an abductor implant
if((H.get_species() == "Abductor" || (locate(/obj/item/implant/abductor) in H)))
- return 1
- return 0
+ return TRUE
+ return FALSE
/datum/surgery_step/internal/extract_organ
@@ -39,15 +39,19 @@
var/mob/living/carbon/human/AB = target
if(NO_INTORGANS in AB.species.species_traits)
user.visible_message("[user] prepares [target]'s [target_zone] for further dissection!", "You prepare [target]'s [target_zone] for further dissection.")
- return 1
+ return TRUE
if(IC)
user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "You pull [IC] out of [target]'s [target_zone].")
user.put_in_hands(IC)
IC.remove(target, special = 1)
- return 1
+ return TRUE
else
to_chat(user, "You don't find anything in [target]'s [target_zone]!")
- return 1
+ return TRUE
+
+/datum/surgery_step/internal/extract_organ/fail_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ user.visible_message("[user]'s hand slips, failing to extract anything!", "Your hand slips, failing to extract anything!")
+ return FALSE
/datum/surgery_step/internal/gland_insert
name = "insert gland"
@@ -63,7 +67,11 @@
user.drop_item()
var/obj/item/organ/internal/heart/gland/gland = tool
gland.insert(target, 2)
- return 1
+ return TRUE
+
+/datum/surgery_step/internal/gland_insert/fail_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ user.visible_message("[user]'s hand slips, failing to insert the gland!", "Your hand slips, failing to insert the gland!")
+ return FALSE
//IPC Gland Surgery//
@@ -91,4 +99,4 @@
/datum/surgery_step/internal/extract_organ/synth
name = "remove cell"
- organ_types = list(/obj/item/organ/internal/cell)
\ No newline at end of file
+ organ_types = list(/obj/item/organ/internal/cell)
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/console.dm b/code/game/gamemodes/miniantags/abduction/machinery/console.dm
index b0b879a30ab..10cd5473279 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/console.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/console.dm
@@ -27,7 +27,7 @@
var/obj/machinery/computer/camera_advanced/abductor/camera
var/list/datum/icon_snapshot/disguises = list()
-/obj/machinery/abductor/console/initialize()
+/obj/machinery/abductor/console/Initialize()
..()
Link_Abduction_Equipment()
diff --git a/code/game/gamemodes/miniantags/borer/borer.dm b/code/game/gamemodes/miniantags/borer/borer.dm
index e9a830e7ed6..00bf335c576 100644
--- a/code/game/gamemodes/miniantags/borer/borer.dm
+++ b/code/game/gamemodes/miniantags/borer/borer.dm
@@ -43,7 +43,8 @@
to_chat(B.host, "You feel the captive mind of [src] begin to resist your control.")
var/delay = (rand(350,450) + B.host.brainloss)
- addtimer(src, "return_control", delay, FALSE, B)
+ addtimer(CALLBACK(src, .proc/return_control, B), delay)
+
/mob/living/captive_brain/proc/return_control(mob/living/simple_animal/borer/B)
if(!B || !B.controlling)
@@ -243,7 +244,7 @@
to_chat(M, "Borer Communication from [B] ([ghost_follow_link(src, ghost=M)]): [input]")
to_chat(src, "[B.truename] says: [input]")
-/mob/living/simple_animal/borer/Life()
+/mob/living/simple_animal/borer/Life(seconds, times_fired)
..()
@@ -534,7 +535,7 @@
leaving = TRUE
- addtimer(src, "let_go", 200)
+ addtimer(CALLBACK(src, .proc/let_go), 200)
/mob/living/simple_animal/borer/proc/let_go()
@@ -611,7 +612,7 @@
bonding = TRUE
var/delay = 300+(host.getBrainLoss()*5)
- addtimer(src, "assume_control", delay)
+ addtimer(CALLBACK(src, .proc/assume_control), delay)
/mob/living/simple_animal/borer/proc/assume_control()
if(!host || !src || controlling)
diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm
index 822bfc9ce29..68e8c16c5da 100644
--- a/code/game/gamemodes/miniantags/guardian/guardian.dm
+++ b/code/game/gamemodes/miniantags/guardian/guardian.dm
@@ -57,7 +57,7 @@
else
holder.icon_state = "hudhealthy"
-/mob/living/simple_animal/hostile/guardian/Life() //Dies if the summoner dies
+/mob/living/simple_animal/hostile/guardian/Life(seconds, times_fired) //Dies if the summoner dies
..()
if(summoner)
if(summoner.stat == DEAD)
@@ -448,6 +448,14 @@
Support:Has two modes. Combat: Medium power attacks and damage resist. Healer: Attacks heal damage, but low damage resist and slow movemen. Can deploy a bluespace beacon and warp targets to it (including you) in either mode.
Explosive: High damage resist and medium power attack. Can turn any object into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered.
+
+ Assassin: Medium damage with no damage resistance, can enter stealth which massively increases the damage of the next attack causing it to ignore armour.
+
+ Charger: Medium damage and defense, very fast and has a special charge attack which damages a target and knocks items out of their hands.
+
+ Lightning: Applies lightning chains to any targets on attack with a link to your summoner, lightning chains will shock anyone nearby.
+
+ Protector: You will become leashed to your holoparasite instead of them to you. Has two modes, a medium attack/defense mode and a protection mode which greatly reduces incoming damage to the holoparasite.
"}
/obj/item/paper/guardian/update_icon()
diff --git a/code/game/gamemodes/miniantags/guardian/types/assassin.dm b/code/game/gamemodes/miniantags/guardian/types/assassin.dm
index 426824f2e8c..5eb8c1b1cec 100644
--- a/code/game/gamemodes/miniantags/guardian/types/assassin.dm
+++ b/code/game/gamemodes/miniantags/guardian/types/assassin.dm
@@ -13,7 +13,7 @@
var/obj/screen/alert/canstealthalert
var/obj/screen/alert/instealthalert
-/mob/living/simple_animal/hostile/guardian/assassin/Life()
+/mob/living/simple_animal/hostile/guardian/assassin/Life(seconds, times_fired)
. = ..()
updatestealthalert()
if(loc == summoner && toggle)
diff --git a/code/game/gamemodes/miniantags/guardian/types/charger.dm b/code/game/gamemodes/miniantags/guardian/types/charger.dm
index abdc349f175..17ed569f256 100644
--- a/code/game/gamemodes/miniantags/guardian/types/charger.dm
+++ b/code/game/gamemodes/miniantags/guardian/types/charger.dm
@@ -6,7 +6,7 @@
ranged_cooldown_time = 40
speed = -1
damage_transfer = 0.6
- playstyle_string = "As a Charger type you do medium damage, have medium damage resistance, move very fast, and can charge at a location, damaging any target hit and forcing them to drop any items they are holding."
+ playstyle_string = "As a Charger type you do medium damage, have medium damage resistance, move very fast, and can charge at a location, damaging any target hit and forcing them to drop any items they are holding. (Click a tile to use your charge ability)"
magic_fluff_string = "..And draw the Hunter, an alien master of rapid assault."
tech_fluff_string = "Boot sequence complete. Charge modules loaded. Holoparasite swarm online."
bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, ready to deal damage."
diff --git a/code/game/gamemodes/miniantags/guardian/types/fire.dm b/code/game/gamemodes/miniantags/guardian/types/fire.dm
index 2a9dc2d2c8e..61905f942d2 100644
--- a/code/game/gamemodes/miniantags/guardian/types/fire.dm
+++ b/code/game/gamemodes/miniantags/guardian/types/fire.dm
@@ -13,7 +13,7 @@
bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, ready to sow havoc at random."
var/toggle = FALSE
-/mob/living/simple_animal/hostile/guardian/fire/Life() //Dies if the summoner dies
+/mob/living/simple_animal/hostile/guardian/fire/Life(seconds, times_fired) //Dies if the summoner dies
..()
if(summoner)
summoner.ExtinguishMob()
diff --git a/code/game/gamemodes/miniantags/guardian/types/healer.dm b/code/game/gamemodes/miniantags/guardian/types/healer.dm
index d51e4cefd45..c679beac91a 100644
--- a/code/game/gamemodes/miniantags/guardian/types/healer.dm
+++ b/code/game/gamemodes/miniantags/guardian/types/healer.dm
@@ -32,7 +32,7 @@
/mob/living/simple_animal/hostile/guardian/healer/New()
..()
-/mob/living/simple_animal/hostile/guardian/healer/Life()
+/mob/living/simple_animal/hostile/guardian/healer/Life(seconds, times_fired)
..()
var/datum/atom_hud/medsensor = huds[DATA_HUD_MEDICAL_ADVANCED]
medsensor.add_hud_to(src)
diff --git a/code/game/gamemodes/miniantags/morph/morph_event.dm b/code/game/gamemodes/miniantags/morph/morph_event.dm
index d9e26597a2b..ab875832451 100644
--- a/code/game/gamemodes/miniantags/morph/morph_event.dm
+++ b/code/game/gamemodes/miniantags/morph/morph_event.dm
@@ -19,7 +19,7 @@
return kill()
var/mob/living/simple_animal/hostile/morph/S = new /mob/living/simple_animal/hostile/morph(pick(xeno_spawn))
player_mind.transfer_to(S)
- player_mind.assigned_role = "Morph"
+ player_mind.assigned_role = SPECIAL_ROLE_MORPH
player_mind.special_role = SPECIAL_ROLE_MORPH
ticker.mode.traitors |= player_mind
to_chat(S, S.playstyle_string)
diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm
index 49380c57863..953e6e91762 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant.dm
@@ -54,7 +54,7 @@
var/image/ghostimage = null //Visible to ghost with darkness off
-/mob/living/simple_animal/revenant/Life()
+/mob/living/simple_animal/revenant/Life(seconds, times_fired)
..()
if(revealed && essence <= 0)
death()
@@ -392,7 +392,7 @@
var/datum/mind/player_mind = new /datum/mind(key_of_revenant)
player_mind.active = 1
player_mind.transfer_to(R)
- player_mind.assigned_role = "revenant"
+ player_mind.assigned_role = SPECIAL_ROLE_REVENANT
player_mind.special_role = SPECIAL_ROLE_REVENANT
ticker.mode.traitors |= player_mind
message_admins("[key_of_revenant] has been [client_to_revive ? "re":""]made into a revenant by reforming ectoplasm.")
diff --git a/code/game/gamemodes/miniantags/revenant/revenant_spawn_event.dm b/code/game/gamemodes/miniantags/revenant/revenant_spawn_event.dm
index 859f863b03c..a70114d8f5e 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant_spawn_event.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant_spawn_event.dm
@@ -43,7 +43,7 @@
return kill()
var/mob/living/simple_animal/revenant/revvie = new /mob/living/simple_animal/revenant/(pick(spawn_locs))
player_mind.transfer_to(revvie)
- player_mind.assigned_role = "revenant"
+ player_mind.assigned_role = SPECIAL_ROLE_REVENANT
player_mind.special_role = SPECIAL_ROLE_REVENANT
ticker.mode.traitors |= player_mind
message_admins("[key_of_revenant] has been made into a revenant by an event.")
diff --git a/code/game/gamemodes/miniantags/slaughter/slaughter.dm b/code/game/gamemodes/miniantags/slaughter/slaughter.dm
index 42827d27f59..aeb26f58822 100644
--- a/code/game/gamemodes/miniantags/slaughter/slaughter.dm
+++ b/code/game/gamemodes/miniantags/slaughter/slaughter.dm
@@ -82,7 +82,7 @@
to_chat(src, "Objective #[2]: [fluffObjective.explanation_text]")
-/mob/living/simple_animal/slaughter/Life()
+/mob/living/simple_animal/slaughter/Life(seconds, times_fired)
..()
if(boost"
- if(scanned_user in existing_authors)
- temp += "
"
- temp_back_screen = NEWSCASTER_CREATE_FC
- else
- var/choice = alert("Please confirm feed channel creation", "Network Channel Handler", "Confirm", "Cancel")
- if(choice == "Confirm")
+ var/choice = alert("Please confirm feed channel creation", "Network Channel Handler", "Confirm", "Cancel")
+ if(choice == "Confirm")
+ if(channel_name == "" || channel_name == REDACTED || scanned_user == "Unknown" || check || (scanned_user in existing_authors))
+ temp = "ERROR: Could not submit feed channel to Network."
+ if(scanned_user in existing_authors)
+ temp += "
"
+ temp_back_screen = NEWSCASTER_CREATE_FC
+ else
var/datum/feed_channel/newChannel = new /datum/feed_channel
newChannel.channel_name = channel_name
newChannel.author = scanned_user
@@ -422,19 +422,19 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
else if(href_list["submit_wanted"])
var/input_param = text2num(href_list["submit_wanted"])
- if(msg == "" || channel_name == "" || scanned_user == "Unknown")
- temp = "ERROR: Wanted issue rejected by Network."
- if(channel_name == "" || channel_name == REDACTED)
- temp += "
"
- temp_back_screen = NEWSCASTER_MAIN
- else
- var/choice = alert("Please confirm wanted issue [input_param == 1 ? "creation." : "edit."]", "Network Security Handler", "Confirm", "Cancel")
- if(choice == "Confirm")
+ var/choice = alert("Please confirm wanted issue [input_param == 1 ? "creation." : "edit."]", "Network Security Handler", "Confirm", "Cancel")
+ if(choice == "Confirm")
+ if(msg == "" || channel_name == "" || scanned_user == "Unknown")
+ temp = "ERROR: Wanted issue rejected by Network."
+ if(channel_name == "" || channel_name == REDACTED)
+ temp += "
"
+ temp_back_screen = NEWSCASTER_MAIN
+ else
if(input_param == 1) //input_param == 1: new wanted issue, input_param == 2: editing an existing one
var/datum/feed_message/W = new /datum/feed_message
W.author = channel_name
diff --git a/code/game/machinery/programmable_unloader.dm b/code/game/machinery/programmable_unloader.dm
deleted file mode 100644
index 310d1798a09..00000000000
--- a/code/game/machinery/programmable_unloader.dm
+++ /dev/null
@@ -1,734 +0,0 @@
-
-// TODO: Check access
-// TODO: Renameable circuit boards
-// TODO: Disks? Disassembly?
-
-/obj/machinery/programmable
- name = "Programmable Unloader"
- icon = 'icons/obj/machines/mining_machines.dmi'
- icon_state = "unloader"
- density = 1
- anchored = 1.0
-
- var/debug = 0 // When set, this WILL spam people around the machine.
- // Identifies profile used and on which item.
-
- var/on = 1
- var/indir = 8
- var/outdir = 4
- var/turf/input = null
- var/turf/output = null
- var/typename = "Unloader"
- var/ident = "#1"
-
- var/const/workmax = 20
- var/datum/cargoprofile/default = new()
- var/list/profiles = list(new/datum/cargoprofile/cargo(),new/datum/cargoprofile/boxes(),new/datum/cargoprofile/supplies(),
- new/datum/cargoprofile/exotics(),new/datum/cargoprofile/tools(),new/datum/cargoprofile/weapons(),
- new/datum/cargoprofile/pressure(),new/datum/cargoprofile/chemical(),
- new/datum/cargoprofile/food(),new/datum/cargoprofile/clothing(),new/datum/cargoprofile/trash())
- var/list/overrides = list(new/datum/cargoprofile/cargo/unload(),new/datum/cargoprofile/in_stacker())
- var/list/emag_overrides = list(new/datum/cargoprofile/people(),new/datum/cargoprofile/unary/shredder(),new/datum/cargoprofile/unary/trainer())
- var/list/types = list()
-
- anchored = 1
- var/unwrenched = 0
- use_power = 1
- var/sleep = 0 // When set, the machine will skip the next however-many updates (to avoid spam)
- var/open = 0
- var/circuit_removed = 0
-
-
-
-/obj/machinery/programmable/New()
- ..()
- if(default)
- default.master = src
- if(!default.enabled)
- default.enabled = 1
- for(var/datum/cargoprofile/p in emag_overrides + overrides + profiles)
- p.master = src
- input = get_step(src.loc,indir)
- output = get_step(src.loc,outdir)
- var/count = 0
- for(var/obj/machinery/programmable/other in world)
- if(other.typename == typename)
- count++
- ident = "#[count]"
- name = "[typename] [ident]"
-
-/obj/machinery/programmable/RefreshParts()
- //This is called when the machine was constructed.
- //Unfortunately, it puts machine parts in our contents list, which we're using.
- //Fortunately, we aren't likely to ever need the components list, circuitboard excepted.
-
- for(var/obj/O in contents)
- if(istype(O,/obj/item/circuitboard/programmable))//retrieve settings here
-
- var/obj/item/circuitboard/programmable/C = O
-
- default = C.default
- emagged = C.emagged
- profiles = C.profiles
- overrides = C.overrides
- emag_overrides = C.emag_overrides
-
- //unary and binary methods (one vs two locales) don't mix
-
- if(istype(src,/obj/machinery/programmable/unary))
- for(var/datum/cargoprofile/P in profiles)
- if(!istype(P,/datum/cargoprofile/unary) && !P.universal)
- profiles -= P
- for(var/datum/cargoprofile/P in overrides)
- if(!istype(P,/datum/cargoprofile/unary) && !P.universal)
- overrides -= P
- for(var/datum/cargoprofile/P in emag_overrides)
- if(!istype(P,/datum/cargoprofile/unary) && !P.universal)
- emag_overrides -= P
- else
- for(var/datum/cargoprofile/P in profiles)
- if(istype(P,/datum/cargoprofile/unary) && !P.universal)
- profiles -= P
- for(var/datum/cargoprofile/P in overrides)
- if(istype(P,/datum/cargoprofile/unary) && !P.universal)
- overrides -= P
- for(var/datum/cargoprofile/P in emag_overrides)
- if(istype(P,/datum/cargoprofile/unary) && !P.universal)
- emag_overrides -= P
- if(default)
- default.master = src
- for(var/datum/cargoprofile/p in emag_overrides + overrides + profiles)
- p.master = src
-
- qdel(C)
- else
- qdel(O)
-
-/obj/machinery/programmable/attack_hand(mob/user as mob)
- if(stat) // moved, or something else
- return
- usr.set_machine(src)
- interact(user)
-
-/obj/machinery/programmable/proc/printlist(var/list/L)
- var/dat
- for(var/datum/cargoprofile/p in L)
- dat += "[p.name]: [p.enabled?"YES":"NO"]
"
- return dat
-
-/obj/machinery/programmable/proc/buildMenu()
- var/dat
- dat += "PROGRAMMABLE UNLOADER
"
- dat += "POWER: [on ? "ON" : "OFF"]
"
- dat += "INLET: [capitalize(dir2text(indir))] "
- dat += "OUTLET: [capitalize(dir2text(outdir))]"
- dat += " (SWAP)
"
- if(default)
- dat += "MAIN PROGRAM: "
- dat += "[default.name]: [default.enabled ? "YES" : "NO"]
"
- if(profiles.len)
- if(!default || !default.enabled)
- dat += printlist(profiles)
- dat += ""
- if(overrides.len)
- dat += "
OVERRIDES:
"
- dat += printlist(overrides)
- dat += ""
- return dat
-
-/obj/machinery/programmable/interact(mob/user as mob)
- var/dat = buildMenu()
- user << browse("
"
- dat += "POWER: [on ? "ON" : "OFF"]
"
- dat += "INLET: [capitalize(dir2text(indir))]
"
- if(default)
- dat += "MAIN PROGRAM: "
- dat += "[default.name]: [default.enabled ? "YES" : "NO"]
"
- if(profiles.len)
- if(!default || !default.enabled)
- dat += printlist(profiles)
- dat += ""
- if(overrides.len)
- dat += "
OVERRIDES:
"
- dat += printlist(overrides)
- dat += ""
- return dat
- Topic(href, href_list)
- switch(href_list["operation"])
- if("inlet")
- indir *= 2 // N S E W
- if(indir > 8)
- indir = 1 // W N
- outdir = indir
- input = get_step(src,indir) // todo: check for glasswalls / no path to target?
- output = input
- updateUsrDialog()
- return
- return ..()
-
-/obj/machinery/programmable/unary/stacker
- name = "Stacking Machine"
- default = new/datum/cargoprofile/unary/stacker()
- profiles = list()
- overrides = list()
- emag_overrides = list()
- typename = "Stacking Machine"
-
-/obj/machinery/programmable/unary/shredder
- name = "Paper Shredder"
- default = new/datum/cargoprofile/unary/shredder()
- profiles = list()
- overrides = list()
- emag_overrides = list(new/datum/cargoprofile/unary/gibber())
- typename = "Paper Shredder"
-
-/obj/machinery/programmable/unary/trainer
- name = "\improper Boxing Trainer"
- default = new/datum/cargoprofile/unary/trainer()
- profiles = list()
- overrides = list()
- emag_overrides = list()
- typename = "Boxing Trainer"
-
- attack_hand(mob/user as mob) //How did I type this with boxing gloves on?
- if(!istype(user,/mob/living/carbon/human))
- return ..()
-
- var/mob/living/carbon/human/H = user
- if(H.gloves && istype(H.gloves, /obj/item/clothing/gloves/boxing))
- var/newsleep = 0
- if(H.loc != input)
- to_chat(H, "The boxing machine refuses to acknowledge you unless you face it head on!")
- return
- var/damage = 0
- if(H.a_intent != INTENT_HARM)
- damage += rand(0,5)
- else
- damage += rand(0,10)
- if(!damage)
- playsound(H.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[H] tries to punch \the [src], but whiffs")
- return
-
- playsound(loc, "punch", 25, 1, -1)
- if(HULK in H.mutations) damage += 5
-
- if(damage < 5)
- visible_message("[H] gives \the [src] a weak punch.")
- if(prob(10))
- visible_message("\The [src] feints at [H], as though mocking \him.")
- else if(damage < 10)
- visible_message("[H] hits \the [src] with a solid [pick("punch","jab","smack")].")
- else if(damage < 15)
- visible_message("[pick("Whoa!","Nice!","Gasp!")] [H] hits [src] with a powerful [pick("punch","jab","uppercut","left hook", "right hook")].")
- else if(damage < 20)
- visible_message("[pick("WHOA!","ACK!","Jeez!")] [H] hits [src] so hard, the whole machine rocks band and forth for a moment.")
- else
- visible_message("Holy moly! [H] hits \the [src] so hard it stops working.")
- stat |= BROKEN
- return
- while(damage >= 5)
- if(prob(50))
- newsleep++
- damage -= 5
- if(newsleep)
- if(emagged)
- visible_message("\The [src]'s lights glow a bloodthirsty red. It refuses to stop!")
- sleep = 0
- else
- sleep += newsleep
- visible_message("\The [src]'s lights dim for a moment and it beeps, signifying a valid hit.")
- playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
- return
-
- else
- return ..()
-
-//----------------------------------------------------------------------------
-// For construction
-//----------------------------------------------------------------------------
-/obj/item/circuitboard/programmable
- name = "Circuit board (Programmable Unloader)"
- build_path = "/obj/machinery/programmable"
- board_type = "machine"
- origin_tech = "engineering=1;programming=2"
- frame_desc = "Requires 2 Manipulators, 1 Scanning Module, 1 Cable."
- req_components = list(
- /obj/item/stock_parts/scanning_module = 1,
- /obj/item/stock_parts/manipulator = 2,
- /obj/item/stack/cable_coil = 1)
-
- //Customization of the machine
- var/datum/cargoprofile/default = new/datum/cargoprofile()
- var/list/profiles = list()
- var/list/overrides = list()
- var/list/emag_overrides = list()
-
- var/emagged = 0
- var/hacking = 0
-
- proc/resetlists()
- profiles = list(new/datum/cargoprofile/cargo(),new/datum/cargoprofile/boxes(),new/datum/cargoprofile/supplies(),
- new/datum/cargoprofile/exotics(),new/datum/cargoprofile/tools(),new/datum/cargoprofile/weapons(),new/datum/cargoprofile/finished(),
- new/datum/cargoprofile/pressure(),new/datum/cargoprofile/pressure/full(),new/datum/cargoprofile/pressure/empty(),
- new/datum/cargoprofile/chemical(),new/datum/cargoprofile/organics(),new/datum/cargoprofile/food(),
- new/datum/cargoprofile/clothing(),new/datum/cargoprofile/trash())
- overrides = list(new/datum/cargoprofile/cargo/unload(),new/datum/cargoprofile/in_stacker(),
- new/datum/cargoprofile/unary/stacker(),new/datum/cargoprofile/unary/trainer())
- emag_overrides = list(new/datum/cargoprofile/people(),new/datum/cargoprofile/unary/shredder())
-
- New()
- ..()
- resetlists()
-
- attackby(obj/item/I as obj, mob/user as mob, params)
- if(istype(I,/obj/item/multitool))
- hacking = (hacking?0:1)
- if(hacking)
- to_chat(user, "You unlock the data port on the board. You can now use a PDA to alter its data.")
- else
- to_chat(user, "You relock the data port.")
- if(istype(I,/obj/item/pda))
- if(!hacking)
- to_chat(user, "It looks like you can't access the board's data port. You'll have to open it with a multitool.")
- else
- user.set_machine(src)
- interact(user)
- if(istype(I,/obj/item/card/emag) && !emagged)
- if(!hacking)
- to_chat(user, "There seems to be a data port on the card, but it's locked. A multitool could open it.")
- else
- emagged = 1
- overrides += emag_overrides
- to_chat(user, "You swipe the card in the card's data port. The lights flicker, then flash once.")
-
- proc/format(var/datum/cargoprofile/P,var/level)
- // PROFILE=0 OVERRIDE=1 MAIN=2
- if(P == null)
- return "NONE
"
- var/dat = "[P.name]"
- if(level == 0 || (level == 1 && !default))
- dat += " PROMOTE"
- if(level > 0)
- dat += " DEMOTE"
- dat += " REMOVE"
- dat += "
"
- return dat
-
- interact(mob/user as mob)
- var/dat
- dat = "MAIN FUNCTION
"
- dat += format(default,2)
- dat += "- CAUTION -
\[DELETE NON-MAIN ALGORITHMS\]
"
- dat += "\[MASTER RESET\]
"
-
- dat += "OVERRIDES:
"
- for(var/datum/cargoprofile/P in overrides)
- dat += format(P,1)
- dat += "
"
- dat += "- CAUTION -
\[DELETE ALL OVERRIDES\]
"
-
- dat += " TERTIARY PROFILES:
"
- for(var/datum/cargoprofile/P in profiles)
- dat += format(P,0)
- dat += "
"
- dat += "- CAUTION -
\[DELETE TERTIARY PROFILES\]"
-
- user << browse("
"
if(myyellowtoolbox)
dat += "[myyellowtoolbox.name]
"
- if(myengitape)
- dat += "[myengitape.name]
"
var/datum/browser/popup = new(user, "engicart", name, 240, 160)
popup.set_content(dat)
popup.open()
@@ -171,16 +160,12 @@
user.put_in_hands(myyellowtoolbox)
to_chat(user, "You take [myyellowtoolbox] from [src].")
myyellowtoolbox = null
- if(href_list["engitape"])
- if(myengitape)
- user.put_in_hands(myengitape)
- to_chat(user, "You take [myengitape] from [src].")
- myengitape = null
update_icon()
updateUsrDialog()
+
/obj/structure/engineeringcart/update_icon()
- overlays = null
+ overlays.Cut()
if(myglass)
overlays += "cart_glass"
if(mymetal)
@@ -194,6 +179,4 @@
if(myredtoolbox)
overlays += "cart_redtoolbox"
if(myyellowtoolbox)
- overlays += "cart_yellowtoolbox"
- if(myengitape)
- overlays += "cart_engitape"
+ overlays += "cart_yellowtoolbox"
\ No newline at end of file
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 284001de2bf..0c0c3c1aa0c 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -71,7 +71,7 @@
/obj/structure/grille/attack_hand(mob/living/user)
user.changeNext_move(CLICK_CD_MELEE)
- user.do_attack_animation(src)
+ user.do_attack_animation(src, ATTACK_EFFECT_KICK)
user.visible_message("[user] kicks [src].", \
"You kick [src].", \
"You hear twisting metal.")
@@ -146,6 +146,7 @@
return ..()
/obj/structure/grille/proc/build_window(obj/item/stack/sheet/S, mob/user)
+ var/dir_to_set = NORTH
if(!istype(S) || !user)
return
if(broken)
@@ -160,59 +161,40 @@
if(!getRelativeDirection(src, user) && (user.loc != loc)) //essentially a cardinal direction adjacent or sharing same loc check
to_chat(user, "You can't reach.")
return
- if(/obj/structure/window/full in loc) //check for a full window already present (blocks the whole tile)
- to_chat(user, "There is already a full window there.")
- return
- var/selection = alert(user, "What type of window would you like to place?", "Window Construction", "One Direction", "Full", "Cancel")
- if(selection == "Cancel")
- return
- if(selection == "Full")
- if(S.get_amount() < 2)
- to_chat(user, "You need at least two sheets of glass for that!")
+ if(loc == user.loc)
+ dir_to_set = user.dir
+ else
+ if(x == user.x)
+ if(y > user.y)
+ dir_to_set = SOUTH
+ else
+ dir_to_set = NORTH
+ else if(y == user.y)
+ if(x > user.x)
+ dir_to_set = WEST
+ else
+ dir_to_set = EAST
+ for(var/obj/structure/window/WINDOW in loc)
+ if(WINDOW.dir == dir_to_set)
+ to_chat(user, "There is already a window facing this way there.")
return
- if(do_after(user, 20, target = src)) //glass doesn't have a toolspeed, so no multiplier
- if(broken || !anchored || !src) //make sure the grille is still intact, anchored, and exists!
- return
- if(S.get_amount() < 2) //make sure we still have enough for this!
- return
- if(!getRelativeDirection(src, user) && (user.loc != loc)) //make sure we can still do this from our location
- return
- var/obj/structure/window/W = new S.full_window(get_turf(src))
- S.use(2)
- W.anchored = 0
- W.state = 0
- to_chat(user, "You place [W] on [src].")
- W.update_icon()
- return
- if(selection == "One Direction")
- var/dir_selection = input("Which direction will this window face?", "Direction") as null|anything in list("north", "east", "south", "west")
- if(!dir_selection)
+ to_chat(user, "You start placing the window...")
+ if(do_after(user, 20, target = src))
+ if(!loc || !anchored) //Grille destroyed or unanchored while waiting
return
- var/temp_dir = text2dir(dir_selection)
- for(var/obj/structure/window/W in loc)
- if(istype(W, /obj/structure/window/full)) //double checking in case a full window was created while selecting direction
- to_chat(user, "There is already a full window there.")
+ for(var/obj/structure/window/WINDOW in loc)
+ if(WINDOW.dir == dir_to_set)//checking this for a 2nd time to check if a window was made while we were waiting.
+ to_chat(user, "There is already a window facing this way there.")
return
- if(W.dir == temp_dir) //to avoid building a window on top of an existing window
- to_chat(user, "There is already a window facing this direction there.")
- return
- if(do_after(user, 20, target = src))
- if(broken || !anchored || !src) //make sure the grille is still intact, anchored, and exists!
- return
- if(S.get_amount() < 1) //make sure we still have enough fir this!
- to_chat(user, "You need at least one sheet of glass for that!")
- return
- if(!getRelativeDirection(src, user) && (user.loc != loc)) //make sure we can still do this from our location
- return
- var/obj/structure/window/W = new S.created_window(get_turf(src))
- S.use(1)
- W.setDir(temp_dir)
- W.ini_dir = temp_dir
- W.anchored = 0
- W.state = 0
- to_chat(user, "You place [W] on [src].")
- W.update_icon()
- return
+ var/obj/structure/window/W = new S.created_window(get_turf(src))
+ S.use(1)
+ W.setDir(dir_to_set)
+ W.ini_dir = dir_to_set
+ W.anchored = 0
+ W.state = 0
+ to_chat(user, "You place the [W] on [src].")
+ W.update_icon()
+ return
/obj/structure/grille/attacked_by(obj/item/I, mob/living/user)
user.changeNext_move(CLICK_CD_MELEE)
diff --git a/code/game/objects/structures/guillotine.dm b/code/game/objects/structures/guillotine.dm
new file mode 100644
index 00000000000..0de1a09a74c
--- /dev/null
+++ b/code/game/objects/structures/guillotine.dm
@@ -0,0 +1,235 @@
+#define GUILLOTINE_BLADE_MAX_SHARP 10 // This is maxiumum sharpness that will decapitate without failure
+#define GUILLOTINE_DECAP_MIN_SHARP 7 // Minimum amount of sharpness for decapitation. Any less and it will just deal brute damage
+#define GUILLOTINE_ANIMATION_LENGTH 9 // How many deciseconds the animation is
+#define GUILLOTINE_BLADE_RAISED 1
+#define GUILLOTINE_BLADE_MOVING 2
+#define GUILLOTINE_BLADE_DROPPED 3
+#define GUILLOTINE_BLADE_SHARPENING 4
+#define GUILLOTINE_HEAD_OFFSET 16 // How much we need to move the player to center their head
+#define GUILLOTINE_LAYER_DIFF 1.2 // How much to increase/decrease a head when it's buckled/unbuckled
+#define GUILLOTINE_ACTIVATE_DELAY 30 // Delay for executing someone
+#define GUILLOTINE_WRENCH_DELAY 10
+#define GUILLOTINE_ACTION_INUSE 5
+#define GUILLOTINE_ACTION_WRENCH 6
+
+/obj/structure/guillotine
+ name = "guillotine"
+ desc = "A large structure used to remove the heads of traitors and treasonists."
+ icon = 'icons/obj/guillotine.dmi'
+ icon_state = "guillotine_raised"
+ can_buckle = TRUE
+ anchored = TRUE
+ density = FALSE
+ buckle_lying = FALSE
+ layer = ABOVE_MOB_LAYER
+ var/blade_status = GUILLOTINE_BLADE_RAISED
+ var/blade_sharpness = GUILLOTINE_BLADE_MAX_SHARP // How sharp the blade is
+ var/kill_count = 0
+ var/force_clap = FALSE //You WILL clap if I want you to
+ var/current_action = 0 // What's currently happening to the guillotine
+
+/obj/structure/guillotine/examine(mob/user)
+ ..()
+
+ var/msg = ""
+
+ msg += "It is [anchored ? "wrenched to the floor." : "unsecured. A wrench should fix that."]
"
+
+ if(blade_status == GUILLOTINE_BLADE_RAISED)
+ msg += "The blade is raised, ready to fall, and"
+
+ if(blade_sharpness >= GUILLOTINE_DECAP_MIN_SHARP)
+ msg += " looks sharp enough to decapitate without any resistance."
+ else
+ msg += " doesn't look particularly sharp. Perhaps a whetstone can be used to sharpen it."
+ else
+ msg += "The blade is hidden inside the stocks."
+
+ if(has_buckled_mobs())
+ msg += "
"
+ msg += "Someone appears to be strapped in. You can help them out, or you can harm them by activating the guillotine."
+
+ to_chat(user, msg)
+
+ return msg
+
+/obj/structure/guillotine/attack_hand(mob/user)
+ add_fingerprint(user)
+
+ // Currently being used by something
+ if(current_action)
+ return
+
+ switch(blade_status)
+ if(GUILLOTINE_BLADE_MOVING)
+ return
+ if(GUILLOTINE_BLADE_DROPPED)
+ blade_status = GUILLOTINE_BLADE_MOVING
+ icon_state = "guillotine_raise"
+ addtimer(CALLBACK(src, .proc/raise_blade), GUILLOTINE_ANIMATION_LENGTH)
+ return
+ if(GUILLOTINE_BLADE_RAISED)
+ if(has_buckled_mobs())
+ if(user.a_intent == INTENT_HARM)
+ user.visible_message("[user] begins to pull the lever!",
+ "You begin to the pull the lever.")
+ current_action = GUILLOTINE_ACTION_INUSE
+
+ if(do_after(user, GUILLOTINE_ACTIVATE_DELAY, target = src) && blade_status == GUILLOTINE_BLADE_RAISED)
+ current_action = 0
+ blade_status = GUILLOTINE_BLADE_MOVING
+ icon_state = "guillotine_drop"
+ playsound(src, 'sound/items/unsheath.ogg', 100, 1)
+ addtimer(CALLBACK(src, .proc/drop_blade, user), GUILLOTINE_ANIMATION_LENGTH - 2) // Minus two so we play the sound and decap faster
+ else
+ current_action = 0
+ else
+ unbuckle_mob()
+ else
+ blade_status = GUILLOTINE_BLADE_MOVING
+ icon_state = "guillotine_drop"
+ playsound(src, 'sound/items/unsheath.ogg', 100, 1)
+ addtimer(CALLBACK(src, .proc/drop_blade), GUILLOTINE_ANIMATION_LENGTH)
+
+/obj/structure/guillotine/proc/raise_blade()
+ blade_status = GUILLOTINE_BLADE_RAISED
+ icon_state = "guillotine_raised"
+
+/obj/structure/guillotine/proc/drop_blade(mob/user)
+ if(has_buckled_mobs() && blade_sharpness)
+ var/mob/living/carbon/human/H = buckled_mob
+
+ if(!H)
+ blade_status = GUILLOTINE_BLADE_DROPPED
+ icon_state = "guillotine"
+ return
+
+ var/obj/item/organ/external/head/head = H.get_organ("head")
+
+ if(QDELETED(head))
+ blade_status = GUILLOTINE_BLADE_DROPPED
+ icon_state = "guillotine"
+ return
+
+ playsound(src, 'sound/weapons/bladeslice.ogg', 100, 1)
+ if(blade_sharpness >= GUILLOTINE_DECAP_MIN_SHARP || head.brute_dam >= 100)
+ head.droplimb()
+ add_attack_logs(user, H, "beheaded with [src]")
+ H.regenerate_icons()
+ unbuckle_mob()
+ kill_count += 1
+
+ var/blood_overlay = "bloody"
+
+ if(kill_count == 2)
+ blood_overlay = "bloodier"
+ else if(kill_count > 2)
+ blood_overlay = "bloodiest"
+
+ blood_overlay = "guillotine_" + blood_overlay + "_overlay"
+ overlays.Cut()
+ overlays += mutable_appearance(icon, blood_overlay)
+
+ if(force_clap)
+ // The crowd is pleased
+ // The delay is to make large crowds have a longer lasting applause
+ var/delay_offset = 0
+ for(var/mob/living/carbon/human/HM in viewers(src, 7))
+ addtimer(CALLBACK(HM, /mob/.proc/emote, "clap"), delay_offset * 0.3)
+ delay_offset++
+ else
+ H.apply_damage(15 * blade_sharpness, BRUTE, head)
+ add_attack_logs(user, H, "non-fatally dropped the blade on with [src]")
+ H.emote("scream")
+
+ if(blade_sharpness > 1)
+ blade_sharpness -= 1
+
+ blade_status = GUILLOTINE_BLADE_DROPPED
+ icon_state = "guillotine"
+
+/obj/structure/guillotine/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/whetstone))
+ add_fingerprint(user)
+ if(blade_status == GUILLOTINE_BLADE_SHARPENING)
+ return
+
+ if(blade_status == GUILLOTINE_BLADE_RAISED)
+ if(blade_sharpness < GUILLOTINE_BLADE_MAX_SHARP)
+ blade_status = GUILLOTINE_BLADE_SHARPENING
+ if(do_after(user, 7, target = src))
+ blade_status = GUILLOTINE_BLADE_RAISED
+ user.visible_message("[user] sharpens the large blade of the guillotine.",
+ "You sharpen the large blade of the guillotine.")
+ blade_sharpness += 1
+ playsound(src, 'sound/items/Screwdriver.ogg', 100, 1)
+ return
+ else
+ blade_status = GUILLOTINE_BLADE_RAISED
+ return
+ else
+ to_chat(user, "The blade is sharp enough!")
+ return
+ else
+ to_chat(user, "You need to raise the blade in order to sharpen it!")
+ return
+ if(iswrench(W))
+ if(current_action)
+ return
+
+ current_action = GUILLOTINE_ACTION_WRENCH
+
+ if(do_after(user, GUILLOTINE_WRENCH_DELAY, target = src))
+ current_action = 0
+ if(has_buckled_mobs())
+ to_chat(user, "Can't unfasten, someone's strapped in!")
+ return
+
+ if(current_action)
+ return
+ to_chat(user, "You [anchored ? "un" : ""]secure [src].")
+ anchored = !anchored
+ playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
+ dir = SOUTH
+ return TRUE
+ else
+ current_action = 0
+ else
+ return ..()
+
+/obj/structure/guillotine/buckle_mob(mob/living/M, force = 0)
+ if(!anchored)
+ to_chat(usr, "The [src] needs to be wrenched to the floor!")
+ return FALSE
+
+ if(!ishuman(M))
+ to_chat(usr, "It doesn't look like they can fit into this properly!")
+ return FALSE // Can't decapitate non-humans
+
+ if(blade_status != GUILLOTINE_BLADE_RAISED)
+ to_chat(usr, "You need to raise the blade before buckling someone in!")
+ return FALSE
+
+ if(..())
+ M.pixel_y -= GUILLOTINE_HEAD_OFFSET // Offset their body so it looks like they're in the guillotine
+ M.layer += GUILLOTINE_LAYER_DIFF
+
+/obj/structure/guillotine/unbuckle_mob(force = 0)
+ if(buckled_mob)
+ buckled_mob.pixel_y += GUILLOTINE_HEAD_OFFSET // Move their body back
+ buckled_mob.layer -= GUILLOTINE_LAYER_DIFF
+ . = ..()
+
+#undef GUILLOTINE_BLADE_MAX_SHARP
+#undef GUILLOTINE_DECAP_MIN_SHARP
+#undef GUILLOTINE_ANIMATION_LENGTH
+#undef GUILLOTINE_BLADE_RAISED
+#undef GUILLOTINE_BLADE_MOVING
+#undef GUILLOTINE_BLADE_DROPPED
+#undef GUILLOTINE_BLADE_SHARPENING
+#undef GUILLOTINE_HEAD_OFFSET
+#undef GUILLOTINE_LAYER_DIFF
+#undef GUILLOTINE_ACTIVATE_DELAY
+#undef GUILLOTINE_WRENCH_DELAY
+#undef GUILLOTINE_ACTION_INUSE
+#undef GUILLOTINE_ACTION_WRENCH
\ No newline at end of file
diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm
new file mode 100644
index 00000000000..0b730a539b9
--- /dev/null
+++ b/code/game/objects/structures/holosign.dm
@@ -0,0 +1,135 @@
+
+//holographic signs and barriers
+
+/obj/structure/holosign
+ name = "holo sign"
+ icon = 'icons/effects/effects.dmi'
+ anchored = TRUE
+ max_integrity = 1
+ armor = list("melee" = 0, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 0, "bio" = 0, "rad" = 0)
+ var/obj/item/holosign_creator/projector
+
+/obj/structure/holosign/New(loc, source_projector)
+ if(source_projector)
+ projector = source_projector
+ projector.signs += src
+ ..()
+
+/obj/structure/holosign/Destroy()
+ if(projector)
+ projector.signs -= src
+ projector = null
+ return ..()
+
+/obj/structure/holosign/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
+ user.do_attack_animation(src)
+ user.changeNext_move(CLICK_CD_MELEE)
+ take_damage(5 , BRUTE, "melee", 1)
+
+/obj/structure/holosign/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
+ switch(damage_type)
+ if(BRUTE)
+ playsound(loc, 'sound/weapons/egloves.ogg', 80, 1)
+ if(BURN)
+ playsound(loc, 'sound/weapons/egloves.ogg', 80, 1)
+
+/obj/structure/holosign/wetsign
+ name = "wet floor sign"
+ desc = "The words flicker as if they mean nothing."
+ icon_state = "holosign"
+
+/obj/structure/holosign/barrier
+ name = "holo barrier"
+ desc = "A short holographic barrier which can only be passed by walking."
+ icon_state = "holosign_sec"
+ pass_flags = LETPASSTHROW
+ density = TRUE
+ max_integrity = 20
+ var/allow_walk = TRUE //can we pass through it on walk intent
+
+/obj/structure/holosign/barrier/CanPass(atom/movable/mover, turf/target)
+ if(!density)
+ return TRUE
+ if(mover.pass_flags & (PASSGLASS|PASSTABLE|PASSGRILLE))
+ return TRUE
+ if(iscarbon(mover))
+ var/mob/living/carbon/C = mover
+ if(allow_walk && C.m_intent == MOVE_INTENT_WALK)
+ return TRUE
+
+/obj/structure/holosign/barrier/engineering
+ icon_state = "holosign_engi"
+
+/obj/structure/holosign/barrier/atmos
+ name = "holo firelock"
+ desc = "A holographic barrier resembling a firelock. Though it does not prevent solid objects from passing through, gas is kept out."
+ icon_state = "holo_firelock"
+ density = FALSE
+ layer = ABOVE_MOB_LAYER
+ anchored = TRUE
+ layer = ABOVE_MOB_LAYER
+ alpha = 150
+
+/obj/structure/holosign/barrier/atmos/New()
+ ..()
+ air_update_turf(TRUE)
+
+/obj/structure/holosign/barrier/atmos/CanAtmosPass(turf/T)
+ return FALSE
+
+/obj/structure/holosign/barrier/atmos/Destroy()
+ var/turf/T = get_turf(src)
+ T.air_update_turf(TRUE)
+ return ..()
+
+/obj/structure/holosign/barrier/cyborg
+ name = "Energy Field"
+ desc = "A fragile energy field that blocks movement. Excels at blocking lethal projectiles."
+ density = TRUE
+ max_integrity = 10
+ allow_walk = FALSE
+
+/obj/structure/holosign/barrier/cyborg/bullet_act(obj/item/projectile/P)
+ take_damage((P.damage / 5) , BRUTE, "melee", 1) //Doesn't really matter what damage flag it is.
+ if(istype(P, /obj/item/projectile/energy/electrode))
+ take_damage(10, BRUTE, "melee", 1) //Tasers aren't harmful.
+ if(istype(P, /obj/item/projectile/beam/disabler))
+ take_damage(5, BRUTE, "melee", 1) //Disablers aren't harmful.
+
+/obj/structure/holosign/barrier/cyborg/hacked
+ name = "Charged Energy Field"
+ desc = "A powerful energy field that blocks movement. Energy arcs off it."
+ max_integrity = 20
+ var/shockcd = 0
+
+/obj/structure/holosign/barrier/cyborg/hacked/bullet_act(obj/item/projectile/P)
+ take_damage(P.damage, BRUTE, "melee", 1) //Yeah no this doesn't get projectile resistance.
+
+/obj/structure/holosign/barrier/cyborg/hacked/proc/cooldown()
+ shockcd = FALSE
+
+/obj/structure/holosign/barrier/cyborg/hacked/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
+ if(!shockcd)
+ if(ismob(user))
+ var/mob/living/M = user
+ M.electrocute_act(15,"Energy Barrier", safety=1)
+ shockcd = TRUE
+ addtimer(CALLBACK(src, .proc/cooldown), 5)
+
+/obj/structure/holosign/barrier/cyborg/hacked/Bumped(atom/movable/AM)
+ if(shockcd)
+ return
+
+ if(!isliving(AM))
+ return
+
+ var/mob/living/M = AM
+ M.electrocute_act(15, "Energy Barrier", safety = 1)
+ shockcd = TRUE
+ addtimer(CALLBACK(src, .proc/cooldown), 5)
diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm
index 6d03ca4fdef..4ea0fc34e2d 100644
--- a/code/game/objects/structures/inflatable.dm
+++ b/code/game/objects/structures/inflatable.dm
@@ -25,7 +25,7 @@
var/health = 50.0
-/obj/structure/inflatable/initialize(location)
+/obj/structure/inflatable/Initialize(location)
..()
air_update_turf(1)
diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm
index f4a2990918b..e0e9ba1b6a7 100644
--- a/code/game/objects/structures/mineral_doors.dm
+++ b/code/game/objects/structures/mineral_doors.dm
@@ -24,7 +24,7 @@
..()
initial_state = icon_state
-/obj/structure/mineral_door/initialize()
+/obj/structure/mineral_door/Initialize()
..()
air_update_turf(1)
diff --git a/code/game/objects/structures/misc.dm b/code/game/objects/structures/misc.dm
index 131a355feb2..6be7bf072d8 100644
--- a/code/game/objects/structures/misc.dm
+++ b/code/game/objects/structures/misc.dm
@@ -87,7 +87,7 @@
var/atom/attack_atom
-/obj/structure/ghost_beacon/initialize()
+/obj/structure/ghost_beacon/Initialize()
. = ..()
last_ghost_alert = world.time
attack_atom = src
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index 3e5d3386e0a..60ca03ad0f7 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -29,7 +29,7 @@
anchored = 1.0
var/open_sound = 'sound/items/Deconstruct.ogg'
-/obj/structure/morgue/initialize()
+/obj/structure/morgue/Initialize()
. = ..()
update()
diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm
index da4c1181f01..b8c28046bd3 100644
--- a/code/game/objects/structures/musician.dm
+++ b/code/game/objects/structures/musician.dm
@@ -295,7 +295,7 @@
QDEL_NULL(song)
return ..()
-/obj/structure/piano/initialize()
+/obj/structure/piano/Initialize()
song.tempo = song.sanitize_tempo(song.tempo) // tick_lag isn't set when the map is loaded
..()
diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm
index caa1bf48b4b..8ea6a3c0cce 100644
--- a/code/game/objects/structures/noticeboard.dm
+++ b/code/game/objects/structures/noticeboard.dm
@@ -7,7 +7,8 @@
anchored = 1
var/notices = 0
-/obj/structure/noticeboard/initialize()
+/obj/structure/noticeboard/Initialize()
+ ..()
for(var/obj/item/I in loc)
if(notices > 4) break
if(istype(I, /obj/item/paper))
diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm
index f0a2c28af85..8d22732e5dd 100644
--- a/code/game/objects/structures/plasticflaps.dm
+++ b/code/game/objects/structures/plasticflaps.dm
@@ -124,7 +124,7 @@
name = "airtight plastic flaps"
desc = "Heavy duty, airtight, plastic flaps."
-/obj/structure/plasticflaps/mining/initialize()
+/obj/structure/plasticflaps/mining/Initialize()
air_update_turf(1)
..()
diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm
index 315728ddc16..44c9da74b20 100644
--- a/code/game/objects/structures/safe.dm
+++ b/code/game/objects/structures/safe.dm
@@ -30,7 +30,8 @@ FLOOR SAFES
tumbler_2_open = rand(0, 71)
-/obj/structure/safe/initialize()
+/obj/structure/safe/Initialize()
+ ..()
for(var/obj/item/I in loc)
if(space >= maxspace)
return
@@ -178,7 +179,7 @@ obj/structure/safe/ex_act(severity)
layer = 2.5
-/obj/structure/safe/floor/initialize()
+/obj/structure/safe/floor/Initialize()
..()
var/turf/T = loc
hide(T.intact)
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 002bbb566d6..4fedc99f0c5 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -376,7 +376,7 @@
return
// Don't break if they're just flying past
if(AM.throwing)
- addtimer(src, "throw_check", 5, FALSE, AM)
+ addtimer(CALLBACK(src, .proc/throw_check, AM), 5)
else
check_break(AM)
@@ -616,7 +616,7 @@
if(user.weakened || user.resting || user.lying)
return
user.changeNext_move(CLICK_CD_MELEE)
- user.do_attack_animation(src)
+ user.do_attack_animation(src, ATTACK_EFFECT_KICK)
user.visible_message("[user] kicks [src].", \
"You kick [src].")
take_damage(rand(4,8), BRUTE, "melee", 1)
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 7cc9c97dfdd..3ea23108662 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -249,9 +249,11 @@
var/ismist = 0 //needs a var so we can make it linger~
var/watertemp = "normal" //freezing, normal, or boiling
var/mobpresent = 0 //true if there is a mob on the shower's loc, this is to ease process()
+ var/datum/looping_sound/showering/soundloop
/obj/machinery/shower/New(turf/T, newdir = SOUTH, building = FALSE)
..()
+ soundloop = new(list(src), FALSE)
if(building)
dir = newdir
pixel_x = 0
@@ -264,8 +266,8 @@
layer = FLY_LAYER
/obj/machinery/shower/Destroy()
- if(mymist)
- QDEL_NULL(mymist)
+ QDEL_NULL(mymist)
+ QDEL_NULL(soundloop)
return ..()
//add heat controls? when emagged, you can freeze to death in it?
@@ -282,6 +284,7 @@
on = !on
update_icon()
if(on)
+ soundloop.start()
if(M.loc == loc)
wash(M)
check_heat(M)
@@ -289,6 +292,8 @@
for(var/atom/movable/G in src.loc)
G.clean_blood()
G.water_act(100, convertHeat(), src)
+ else
+ soundloop.stop()
/obj/machinery/shower/attackby(obj/item/I as obj, mob/user as mob, params)
if(I.type == /obj/item/analyzer)
@@ -338,9 +343,9 @@
mist_time = 70 //7 seconds on freezing temperature to disperse existing mist
if(watertemp == "boiling")
mist_time = 20 //2 seconds on boiling temperature to build up mist
- addtimer(src, "update_mist", mist_time)
+ addtimer(CALLBACK(src, .proc/update_mist), mist_time)
else
- addtimer(src, "update_mist", 250) //25 seconds for mist to disperse after being turned off
+ addtimer(CALLBACK(src, .proc/update_mist), 250) //25 seconds for mist to disperse after being turned off
/obj/machinery/shower/proc/update_mist()
if(on)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index c93a0e5f1b8..aebd111ad26 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -386,7 +386,7 @@ var/global/wcCommon = pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e", "#8f
update_nearby_icons()
return
-/obj/structure/window/initialize()
+/obj/structure/window/Initialize()
air_update_turf(1)
return ..()
@@ -454,7 +454,7 @@ var/global/wcCommon = pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e", "#8f
update_nearby_icons()
return
-/obj/structure/window/plasmabasic/initialize()
+/obj/structure/window/plasmabasic/Initialize()
..()
air_update_turf(1)
@@ -483,7 +483,7 @@ var/global/wcCommon = pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e", "#8f
update_nearby_icons()
return
-/obj/structure/window/plasmareinforced/initialize()
+/obj/structure/window/plasmareinforced/Initialize()
..()
air_update_turf(1)
diff --git a/code/game/response_team.dm b/code/game/response_team.dm
index 9fdf3121b59..a865e4a5ad9 100644
--- a/code/game/response_team.dm
+++ b/code/game/response_team.dm
@@ -104,8 +104,12 @@ var/ert_request_answered = 0
if(index > emergencyresponseteamspawn.len)
index = 1
+ if(!M || !M.client)
+ continue
var/client/C = M.client
var/mob/living/new_commando = C.create_response_team(emergencyresponseteamspawn[index])
+ if(!M || !new_commando)
+ continue
new_commando.mind.key = M.key
new_commando.key = M.key
new_commando.update_icons()
@@ -157,17 +161,17 @@ var/ert_request_answered = 0
head_organ.h_style = random_hair_style(M.gender, head_organ.species.name)
head_organ.f_style = random_facial_hair_style(M.gender, head_organ.species.name)
- M.real_name = "[pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant First Class", "Master Sergeant", "Sergeant Major")] [pick(last_names)]"
- M.name = M.real_name
+ M.rename_character(null, "[pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant First Class", "Master Sergeant", "Sergeant Major")] [pick(last_names)]")
M.age = rand(23,35)
M.regenerate_icons()
M.update_body()
+ M.update_dna()
//Creates mind stuff.
M.mind = new
M.mind.current = M
M.mind.original = M
- M.mind.assigned_role = "MODE"
+ M.mind.assigned_role = SPECIAL_ROLE_ERT
M.mind.special_role = SPECIAL_ROLE_ERT
if(!(M.mind in ticker.minds))
ticker.minds += M.mind //Adds them to regular mind list.
@@ -199,13 +203,13 @@ var/ert_request_answered = 0
var/cyborg_unlock = 0
/datum/response_team/proc/setSlots(com, sec, med, eng, jan, par, cyb)
- command_slots = com
- security_slots = sec
- medical_slots = med
- engineer_slots = eng
- janitor_slots = jan
- paranormal_slots = par
- cyborg_slots = cyb
+ command_slots = com || command_slots
+ security_slots = sec || security_slots
+ medical_slots = med || medical_slots
+ engineer_slots = eng || engineer_slots
+ janitor_slots = jan || janitor_slots
+ paranormal_slots = par || paranormal_slots
+ cyborg_slots = cyb || cyborg_slots
/datum/response_team/proc/reduceCyborgSlots()
cyborg_slots--
@@ -280,8 +284,7 @@ var/ert_request_answered = 0
command_slots = 0
// Override name and age for the commander
- M.real_name = "[pick("Lieutenant", "Captain", "Major")] [pick(last_names)]"
- M.name = M.real_name
+ M.rename_character(null, "[pick("Lieutenant", "Captain", "Major")] [pick(last_names)]")
M.age = rand(35,45)
M.equipOutfit(command_outfit)
diff --git a/code/game/skincmd.dm b/code/game/skincmd.dm
deleted file mode 100644
index 7d27a1ce6df..00000000000
--- a/code/game/skincmd.dm
+++ /dev/null
@@ -1,13 +0,0 @@
-/mob/var/skincmds = list()
-/obj/proc/SkinCmd(mob/user as mob, var/data as text)
-
-/proc/SkinCmdRegister(var/mob/user, var/name as text, var/O as obj)
- user.skincmds[name] = O
-
-/mob/verb/skincmd(data as text)
- set hidden = 1
-
- var/ref = copytext(data, 1, findtext(data, ";"))
- if(src.skincmds[ref] != null)
- var/obj/a = src.skincmds[ref]
- a.SkinCmd(src, copytext(data, findtext(data, ";") + 1))
\ No newline at end of file
diff --git a/code/game/smoothwall.dm b/code/game/smoothwall.dm
deleted file mode 100644
index 20dea8de7b0..00000000000
--- a/code/game/smoothwall.dm
+++ /dev/null
@@ -1,108 +0,0 @@
-// OKAY I DON'T KNOW WHO THE FUCK ORIGINALLY CODED THIS BUT THEY ARE OFFICIALLY FIRED FOR BEING DRUNK AND STUPID
-// FUCK YOU MYSTERY CODERS
-// FOR THIS SHIT I'M GOING TO MAKE ALL MY COMMENTS IN CAPS
-
-/atom
- var/list/canSmoothWith=list() // TYPE PATHS I CAN SMOOTH WITH~~~~~
-
-// MOVED INTO UTILITY FUNCTION FOR LESS DUPLICATED CODE.
-/atom/proc/findSmoothingNeighbors()
- // THIS IS A BITMAP BECAUSE NORTH/SOUTH/ETC ARE ALL BITFLAGS BECAUSE BYOND IS DUMB AND
- // DOESN'T FUCKING MAKE SENSE, BUT IT WORKS TO OUR ADVANTAGE
- var/junction = 0
- for(var/cdir in cardinal)
- var/turf/T = get_step(src,cdir)
- if(isSmoothableNeighbor(T))
- junction |= cdir
- continue // NO NEED FOR FURTHER SEARCHING IN THIS TILE
- for(var/atom/A in T)
- if(isSmoothableNeighbor(A))
- junction |= cdir
- break // NO NEED FOR FURTHER SEARCHING IN THIS TILE
-
- return junction
-
-/atom/proc/isSmoothableNeighbor(var/atom/A)
- return is_type_in_list(A,canSmoothWith)
-
-/turf/simulated/wall/isSmoothableNeighbor(var/atom/A)
- if(is_type_in_list(A,canSmoothWith))
- // COLON OPERATORS ARE TERRIBLE BUT I HAVE NO CHOICE
- if(src.mineral == A:mineral) //mineral not walltype so reinf still smooths with normal and vice versa
- return 1
- return 0
-
-/**
- * WALL SMOOTHING SHIT
- *
- * IN /ATOM BECAUSE /TURFS ARE /ATOMS AND SO ARE /OBJ/STRUCTURE/FALSEWALLS
- * THIS IS STUPID BUT IS FAIRLY ELEGANT FOR BYOND
- *
- * HOWEVER, INSTEAD OF MAKING ONE BIG GODDAMN MONOLITHIC PROC LIKE A FUCKING
- * SHITTY FUNCTIONAL PROGRAMMER, WE WILL BE COOL AND MODERN AND USE INHERITANCE.
- */
-/atom/proc/relativewall()
- return // DOES JACK SHIT BY DEFAULT. OLD BEHAVIOR WAS TO SPAM LOOPS ANYWAY.
-
-/*
- * SEE? NOW WE ONLY HAVE TO PROGRAM THIS SHIT INTO WHAT WE WANT TO SMOOTH
- * INSTEAD OF BEING DUMB AND HAVING A BIG FUCKING IFTREE WITH TYPECHECKS
- * MY GOD, WE COULD EVEN MOVE THE CODE TO BE WITH THE REST OF THE WALL'S CODE!
- * HOW FUCKING INNOVATIVE. ISN'T INHERITANCE NICE?
- *
- * WE COULD STANDARDIZE THIS BUT EVERYONE'S A FUCKING SNOWFLAKE
- */
-/turf/simulated/wall/relativewall()
- var/junction=findSmoothingNeighbors()
- icon_state = "[walltype][junction]" // WHY ISN'T THIS IN UPDATE_ICON OR SIMILAR
-
-/atom/proc/relativewall_neighbours(var/sko=0) //SKO: Skip Optimizations
- // OPTIMIZE BY NOT CHECKING FOR NEIGHBORS IF WE DON'T FUCKING SMOOTH
- if(canSmoothWith.len>0 || sko)
- relativewall()
- for(var/cdir in cardinal)
- var/turf/T = get_step(src,cdir)
- if(isSmoothableNeighbor(T) || sko)
- T.relativewall()
- for(var/atom/A in T)
- if(isSmoothableNeighbor(A) || sko)
- A.relativewall()
-
-/turf/simulated/wall/New()
- ..()
- relativewall_neighbours()
-
-/turf/simulated/wall/Destroy()
- for(var/obj/effect/E in src)
- if(E.name == "Wallrot")
- qdel(E)
-
- if(!del_suppress_resmoothing)
- spawn(10)
- relativewall_neighbours(sko=1)
-
- // JESUS WHY
- for(var/direction in cardinal)
- for(var/obj/structure/glowshroom/shroom in get_step(src,direction))
- if(!shroom.floor) //shrooms drop to the floor
- shroom.floor = 1
- shroom.icon_state = "glowshroomf"
- shroom.pixel_x = 0
- shroom.pixel_y = 0
-/* for(var/obj/effect/supermatter_crystal/crystal in get_step(src,direction))
- if(!crystal.floor) //crystals drop to the floor
- crystal.floor = 1
- crystal.icon_state = "supermatter_crystalf"
- crystal.pixel_x = 0
- crystal.pixel_y = 0 */
- return ..()
-
-// DE-HACK
-/turf/simulated/wall/vault/relativewall()
- return
-
-
-/obj/structure/alien/resin/relativewall()
- var/junction = findSmoothingNeighbors()
- icon_state = "[resintype][junction]"
- return
\ No newline at end of file
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 39bf16bc697..66746ece0ae 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -1,4 +1,4 @@
-/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE)
+/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE)
if(isarea(source))
error("[source] is an area and is trying to make the sound: [soundin]")
return
@@ -11,7 +11,10 @@
// Looping through the player list has the added bonus of working for mobs inside containers
var/sound/S = sound(get_sfx(soundin))
var/maxdistance = (world.view + extrarange) * 3
- for(var/P in player_list)
+ var/list/listeners = player_list
+ if(!ignore_walls) //these sounds don't carry through walls
+ listeners = listeners & hearers(maxdistance, turf_source)
+ for(var/P in listeners)
var/mob/M = P
if(!M || !M.client)
continue
@@ -78,13 +81,15 @@
S.y = 1
S.falloff = (falloff ? falloff : FALLOFF_SOUNDS)
- src << S
+ SEND_SOUND(src, S)
-/client/proc/playtitlemusic()
- if(!ticker || !ticker.login_music || config.disable_lobby_music)
- return
- if(prefs.sound & SOUND_LOBBY)
- src << sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = CHANNEL_LOBBYMUSIC) // MAD JAMS
+/proc/sound_to_playing_players(soundin, volume = 100, vary = FALSE, frequency = 0, falloff = FALSE, channel = 0, pressure_affected = FALSE, sound/S)
+ if(!S)
+ S = sound(get_sfx(soundin))
+ for(var/m in player_list)
+ if(ismob(m) && !isnewplayer(m))
+ var/mob/M = m
+ M.playsound_local(M, null, volume, vary, frequency, falloff, channel, pressure_affected, S)
/proc/open_sound_channel()
var/static/next_channel = 1 //loop through the available 1024 - (the ones we reserve) channels and pray that its not still being used
@@ -93,7 +98,13 @@
next_channel = 1
/mob/proc/stop_sound_channel(chan)
- src << sound(null, repeat = 0, wait = 0, channel = chan)
+ SEND_SOUND(src, sound(null, repeat = 0, wait = 0, channel = chan))
+
+/client/proc/playtitlemusic()
+ if(!ticker || !ticker.login_music || config.disable_lobby_music)
+ return
+ if(prefs.sound & SOUND_LOBBY)
+ SEND_SOUND(src, sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = CHANNEL_LOBBYMUSIC)) // MAD JAMS
/proc/get_rand_frequency()
return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs.
diff --git a/code/game/turfs/simulated/floor/plasteel_floor.dm b/code/game/turfs/simulated/floor/plasteel_floor.dm
index cbb5647f283..cba841ce823 100644
--- a/code/game/turfs/simulated/floor/plasteel_floor.dm
+++ b/code/game/turfs/simulated/floor/plasteel_floor.dm
@@ -18,8 +18,13 @@
/turf/simulated/floor/plasteel/airless/New()
..()
- name = "floor"
-
+ name = "floor"
+
+/turf/simulated/floor/plasteel/airless/indestructible // For bomb testing range
+
+/turf/simulated/floor/plasteel/airless/indestructible/ex_act(severity)
+ return
+
/turf/simulated/floor/plasteel/goonplaque
icon_state = "plaque"
name = "Commemorative Plaque"
diff --git a/code/game/world.dm b/code/game/world.dm
index 4ebeadedc6f..7d592864501 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -16,10 +16,12 @@ var/global/list/map_transition_config = MAP_TRANSITION_CONFIG
GLOB.timezoneOffset = text2num(time2text(0, "hh")) * 36000
+ makeDatumRefLists()
callHook("startup")
src.update_status()
+
. = ..()
// Create robolimbs for chargen.
@@ -324,6 +326,10 @@ var/world_topic_spam_protect_time = world.timeofday
processScheduler.stop()
shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss.
+ for(var/client/C in clients)
+ if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
+ C << link("byond://[config.server]")
+
if(config && config.shutdown_on_reboot)
sleep(0)
if(shutdown_shell_command)
@@ -331,9 +337,6 @@ var/world_topic_spam_protect_time = world.timeofday
del(world)
return
else
- for(var/client/C in clients)
- if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
- C << link("byond://[config.server]")
..(0)
diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm
index b97993d5327..4c905a0b517 100644
--- a/code/modules/admin/IsBanned.dm
+++ b/code/modules/admin/IsBanned.dm
@@ -93,7 +93,7 @@ world/IsBanned(key,address,computer_id)
var/appealmessage = ""
if(config.banappeals)
appealmessage = " You may appeal it at [config.banappeals]."
- expires = " The is a permanent ban.[appealmessage]"
+ expires = " This is a permanent ban.[appealmessage]"
var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime].[expires]"
diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm
index 21731cc8b7a..5039146b1c3 100644
--- a/code/modules/admin/secrets.dm
+++ b/code/modules/admin/secrets.dm
@@ -25,8 +25,6 @@
Show current traitors and objectives
Set Night Shift Mode
Bombs
- Bombing List
- Remove all bombs currently in existence
[check_rights(R_SERVER, 0) ? " Toggle bomb cap
" : "
"]
Lists
Show last [length(lastsignalers)] signalers
@@ -130,5 +128,3 @@
var/datum/browser/popup = new(usr, "secrets", "