diff --git a/.travis.yml b/.travis.yml index 979e35f6aed..2c2b9dec61d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,74 +1,41 @@ -#pretending we're C because otherwise ruby will initialize, even with "language: dm". language: generic -sudo: false +dist: xenial +os: linux git: depth: 1 -cache: - directories: - - $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR} - -addons: - apt: - packages: - - libc6-i386 - - libgcc1:i386 - - libstdc++6:i386 - -env: - global: - - BYOND_MAJOR="513" - - BYOND_MINOR="1505" - - BYOND_MACRO_COUNT=4 - matrix: - - DM_MAPFILE="cyberiad" - - DM_MAPFILE="metastation" - - DM_MAPFILE="delta" - - DM_MAPFILE="test_all_maps" - -stages: - - File Checks - - test - -before_script: - - chmod +x ./install-byond.sh - - ./install-byond.sh -script: - - source $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin/byondsetup - - bash dm.sh -M${DM_MAPFILE} paradise.dme - jobs: include: - # Basic styling/functionality checks - - stage: File Checks - env: + - name: "Run Linters" addons: + apt: + packages: + - python3 + - python3-pip + - python3-setuptools install: - - pip install --user PyYaml -q - - pip install --user beautifulsoup4 -q + - tools/travis/install_build_deps.sh - tools/travis/install_dreamchecker.sh - before_script: skip script: - shopt -s globstar + - find . -name "*.php" -print0 | xargs -0 -n1 php -l + - find . -name "*.json" -not -path "./nano/node_modules/*" -print0 | xargs -0 python3 ./tools/travis/json_verifier.py + - tools/travis/build_nanoui.sh + - tools/travis/check_grep.sh - python3 tools/travis/check_line_endings.py - - (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 - ~/dreamchecker - # Compile NanoUI to make sure it works - - stage: NanoUI - language: node_js - node_js: - - "9" - env: + - name: "Compile All Maps" addons: - before_install: - - npm install -g gulp-cli - - cd ./nano/ + apt: + packages: + - libstdc++6:i386 + cache: + directories: + - $HOME/BYOND install: - - npm install --loglevel=error - before_script: + - tools/travis/install_byond.sh + - source $HOME/BYOND/byond/bin/byondsetup script: - - node node_modules/gulp/bin/gulp.js --require less-loader + - tools/travis/dm.sh -Mtravis_map_testing paradise.dme diff --git a/README.md b/README.md index eafdb5ffe91..943397b0fa8 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,16 @@ Make sure to set the port to the one you specified in the config.txt, and set the Security box to 'Trusted'. Then press GO and the server should start up and be ready to join. +### Installation (Linux) + +The code is able to run on Linux server side, however the libraries for MySQL and logging do require extra packages. + +For MySQL, run the following: `apt-get install libmysqlclient-dev:i386` + +For RustG, run the following: `apt-get install libssl-dev:i386 pkg-config:i386 zlib1g-dev:i386` + +After installing these packages, these libraries should function as intended. + --- ### UPDATING diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 837f8f440d6..a447c7993ba 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -594,4 +594,18 @@ CREATE TABLE `connection_log` ( `ip` varchar(32) NOT NULL, `computerid` varchar(32) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- +-- Table structure for table `changelog` +-- +DROP TABLE IF EXISTS `changelog`; +CREATE TABLE `changelog` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `pr_number` INT(11) NOT NULL, + `date_merged` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `author` VARCHAR(32) NOT NULL, + `cl_type` ENUM('FIX','WIP','TWEAK','SOUNDADD','SOUNDDEL','CODEADD','CODEDEL','IMAGEADD','IMAGEDEL','SPELLCHECK','EXPERIMENT') NOT NULL, + `cl_entry` TEXT NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index b43141f6784..6096f0547e6 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -591,4 +591,18 @@ CREATE TABLE `SS13_connection_log` ( `ip` varchar(32) NOT NULL, `computerid` varchar(32) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- +-- Table structure for table `SS13_changelog` +-- +DROP TABLE IF EXISTS `SS13_changelog`; +CREATE TABLE `SS13_changelog` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `pr_number` INT(11) NOT NULL, + `date_merged` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `author` VARCHAR(32) NOT NULL, + `cl_type` ENUM('FIX','WIP','TWEAK','SOUNDADD','SOUNDDEL','CODEADD','CODEDEL','IMAGEADD','IMAGEDEL','SPELLCHECK','EXPERIMENT') NOT NULL, + `cl_entry` TEXT NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/SQL/updates/10-11.sql b/SQL/updates/10-11.sql index 9564d3efaad..b2718db85e6 100644 --- a/SQL/updates/10-11.sql +++ b/SQL/updates/10-11.sql @@ -38,4 +38,4 @@ ALTER TABLE feedback.population CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4 ALTER TABLE feedback.privacy CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTER TABLE feedback.vpn_whitelist CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTER TABLE feedback.watch CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -ALTER TABLE feedback.whitelist CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; \ No newline at end of file +ALTER TABLE feedback.whitelist CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/SQL/updates/11-12.sql b/SQL/updates/11-12.sql new file mode 100644 index 00000000000..f6e9ac01baa --- /dev/null +++ b/SQL/updates/11-12.sql @@ -0,0 +1,13 @@ +#Updating the SQL from version 11 to version 12. -AffectedArc07 +#Creating a table for the new changelog system + +DROP TABLE IF EXISTS `changelog`; +CREATE TABLE IF NOT EXISTS `changelog` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `pr_number` INT(11) NOT NULL, + `date_merged` TIMESTAMP NOT NULL DEFAULT current_timestamp(), + `author` VARCHAR(32) NOT NULL, + `cl_type` ENUM('FIX','WIP','TWEAK','SOUNDADD','SOUNDDEL','CODEADD','CODEDEL','IMAGEADD','IMAGEDEL','SPELLCHECK','EXPERIMENT') NOT NULL, + `cl_entry` TEXT NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/_build_dependencies.sh b/_build_dependencies.sh index f9bddd66134..24a33ed3644 100644 --- a/_build_dependencies.sh +++ b/_build_dependencies.sh @@ -1,2 +1,11 @@ # This file has all the information on what versions of libraries are thrown into the code +# For dreamchecker export SPACEMANDMM_TAG=suite-1.2 +# For NanoUI +export NODE_VERSION=9 +# For the scripts in tools +export PHP_VERSION=5.6 +# Byond Major +export BYOND_MAJOR=513 +# Byond Minor +export BYOND_MINOR=1505 diff --git a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm index 864981494ac..5a880549b8a 100644 --- a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm +++ b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm @@ -2017,7 +2017,7 @@ /obj/machinery/vending/sustenance{ desc = "A vending machine normally reserved for work camps."; name = "\improper sustenance vendor"; - product_slogans = "Enjoy your meal.;Enough calories to support any worker." + slogan_list = list("Enjoy your meal.","Enough calories to support any worker.") }, /turf/simulated/floor/plasteel{ icon_state = "floorgrime" diff --git a/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm b/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm index 62a22425926..43aa3cd98c7 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm @@ -832,6 +832,10 @@ /obj/item/shard, /turf/space, /area/space/nearstation) +"Hv" = ( +/obj/item/gps/ruin, +/turf/simulated/wall/r_wall, +/area/ruin/unpowered) (1,1,1) = {" aa @@ -973,7 +977,7 @@ aa at at aF -at +Hv aU ay ay diff --git a/_maps/map_files/RandomRuins/SpaceRuins/listeningpost.dmm b/_maps/map_files/RandomRuins/SpaceRuins/listeningpost.dmm index 22d4c0798aa..17d49d666bc 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/listeningpost.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/listeningpost.dmm @@ -269,6 +269,10 @@ icon_state = "freezerfloor" }, /area/ruin/powered) +"Y" = ( +/obj/item/gps/ruin, +/turf/simulated/wall/r_wall, +/area/ruin/powered) (1,1,1) = {" a @@ -960,7 +964,7 @@ b f f p -f +Y f f j diff --git a/_maps/map_files/RandomRuins/SpaceRuins/mechtransport.dmm b/_maps/map_files/RandomRuins/SpaceRuins/mechtransport.dmm index 2a5c0eae533..b4e36942d6a 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/mechtransport.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/mechtransport.dmm @@ -240,6 +240,13 @@ /obj/structure/shuttle/engine/propulsion, /turf/simulated/shuttle/plating, /area/ruin/powered) +"U" = ( +/obj/item/gps/ruin, +/turf/simulated/shuttle/wall{ + tag = "icon-swall12"; + icon_state = "swall12" + }, +/area/ruin/powered) (1,1,1) = {" a @@ -313,7 +320,7 @@ a c g l -q +U r u t diff --git a/_maps/map_files/RandomRuins/SpaceRuins/wizardcrash.dmm b/_maps/map_files/RandomRuins/SpaceRuins/wizardcrash.dmm index fef87df8950..ebfaf3b94b4 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/wizardcrash.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/wizardcrash.dmm @@ -209,7 +209,6 @@ "aI" = ( /obj/structure/table/wood, /obj/item/toy/character/wizard, -/obj/item/paper/spells, /turf/simulated/floor/carpet, /area/ruin/unpowered) "aJ" = ( diff --git a/_maps/map_files/cyberiad/z2.dmm b/_maps/map_files/cyberiad/z2.dmm index 684365ada39..a4baee09320 100644 --- a/_maps/map_files/cyberiad/z2.dmm +++ b/_maps/map_files/cyberiad/z2.dmm @@ -2060,7 +2060,16 @@ icon_opened = "cabinet_open"; icon_state = "cabinet_closed" }, +/obj/item/clothing/under/color/lightpurple, +/obj/item/clothing/under/color/purple, /obj/item/storage/backpack/satchel, +/obj/item/storage/backpack/satchel, +/obj/item/clothing/head/wizard/red, +/obj/item/clothing/suit/wizrobe/red, +/obj/item/clothing/head/wizard, +/obj/item/clothing/suit/wizrobe, +/obj/item/clothing/shoes/sandal, +/obj/item/clothing/shoes/sandal, /turf/unsimulated/floor{ dir = 9; icon_state = "carpetside" @@ -2148,8 +2157,6 @@ /area/wizard_station) "fC" = ( /obj/structure/table/wood, -/obj/item/trash/tray, -/obj/item/paper/spells, /turf/unsimulated/floor{ dir = 10; icon_state = "carpetside" @@ -3248,10 +3255,10 @@ /area/shuttle/assault_pod) "iw" = ( /obj/structure/rack, +/obj/item/clothing/under/plasmaman/wizard, +/obj/item/clothing/head/helmet/space/plasmaman/wizard, /obj/item/clothing/mask/breath, -/obj/item/clothing/mask/breath/vox, -/obj/item/tank/plasma/plasmaman, -/obj/item/tank/emergency_oxygen/vox, +/obj/item/tank/plasma/plasmaman/belt/full, /turf/unsimulated/floor{ icon_state = "grimy" }, @@ -3895,10 +3902,8 @@ /area/centcom/gamma) "ke" = ( /obj/structure/rack, -/obj/item/clothing/suit/wizrobe/red, -/obj/item/clothing/shoes/sandal, -/obj/item/clothing/head/wizard/red, -/obj/item/twohanded/staff, +/obj/item/tank/emergency_oxygen/vox, +/obj/item/clothing/mask/breath/vox, /turf/unsimulated/floor{ icon_state = "grimy" }, @@ -5006,6 +5011,20 @@ name = "grass" }, /area/centcom/control) +"nc" = ( +/obj/machinery/door/airlock/centcom{ + name = "Gamma Armory"; + opacity = 1; + req_access_txt = "114" + }, +/obj/machinery/door/poddoor/impassable{ + id_tag = "CCGAMMA"; + name = "Gamma Security" + }, +/turf/simulated/floor/plasteel{ + icon_state = "dark" + }, +/area/centcom/gamma) "nd" = ( /obj/structure/flora/ausbushes/lavendergrass, /turf/unsimulated/floor{ @@ -5381,7 +5400,7 @@ }, /area/syndicate_mothership) "nQ" = ( -/obj/machinery/door/poddoor{ +/obj/machinery/door/poddoor/impassable{ id_tag = "GRAVPULTS"; name = "Gravity Catapults" }, @@ -5391,7 +5410,7 @@ }, /area/centcom/specops) "nR" = ( -/obj/machinery/door/poddoor{ +/obj/machinery/door/poddoor/impassable{ id_tag = "GRAVPULTS"; name = "Gravity Catapults" }, @@ -5408,7 +5427,7 @@ }, /area/syndicate_mothership) "nT" = ( -/obj/machinery/door/poddoor{ +/obj/machinery/door/poddoor/impassable{ id_tag = "ASSAULT"; name = "Assault Armor" }, @@ -5854,7 +5873,7 @@ }, /area/centcom/gamma) "oR" = ( -/obj/machinery/door/poddoor{ +/obj/machinery/door/poddoor/impassable{ id_tag = "SPECOPS"; name = "Ready Room" }, @@ -5979,7 +5998,7 @@ opacity = 1; req_access_txt = "114" }, -/obj/machinery/door/poddoor{ +/obj/machinery/door/poddoor/impassable{ id_tag = "specopsoffice"; name = "Super Privacy Shutters" }, @@ -6118,7 +6137,7 @@ /turf/simulated/floor/mech_bay_recharge_floor, /area/shuttle/gamma/space) "pv" = ( -/obj/machinery/door/poddoor{ +/obj/machinery/door/poddoor/impassable{ id_tag = "CCTELE"; name = "Specops Teleporter" }, @@ -6365,7 +6384,7 @@ /area/centcom/specops) "pX" = ( /obj/machinery/door_control{ - desc = "A remote control switch to block view of the singularity."; + desc = "A remote control switch to connect the ready room to the rest of Centcom."; icon_state = "doorctrl0"; id = "SPECOPS"; name = "Ready Room"; @@ -29642,7 +29661,7 @@ fm fm md md -oO +nc fm pv sX diff --git a/_maps/map_files/cyberiad/z6.dmm b/_maps/map_files/cyberiad/z6.dmm index 09453cfe542..6cbb87b6f80 100644 --- a/_maps/map_files/cyberiad/z6.dmm +++ b/_maps/map_files/cyberiad/z6.dmm @@ -761,7 +761,7 @@ /area/derelict/bridge) "bK" = ( /obj/machinery/vending/cigarette/free{ - product_slogans = "Just remember! No capitalist.;Best enjoyed with Vodka!.;Smoke!;Nine out of ten USSP scientists agree, smoking reduces stress!;There's no cigarette like a Russian cigarette!;Cigarettes! Now with 100% less capitalism." + slogan_list = list("Just remember! No capitalist.","Best enjoyed with Vodka!.","Smoke!","Nine out of ten USSP scientists agree, smoking reduces stress!","There's no cigarette like a Russian cigarette!","Cigarettes! Now with 100% less capitalism.") }, /turf/simulated/floor/plasteel{ dir = 9; @@ -1441,7 +1441,7 @@ pixel_y = 32 }, /obj/machinery/vending/cigarette/free{ - product_slogans = "Just remember! No capitalist.;Best enjoyed with Vodka!.;Smoke!;Nine out of ten USSP scientists agree, smoking reduces stress!;There's no cigarette like a Russian cigarette!;Cigarettes! Now with 100% less capitalism." + slogan_list = list("Just remember! No capitalist.","Best enjoyed with Vodka!.","Smoke!","Nine out of ten USSP scientists agree, smoking reduces stress!","There's no cigarette like a Russian cigarette!","Cigarettes! Now with 100% less capitalism.") }, /obj/effect/decal/cleanable/dirt, /turf/simulated/floor/plasteel{ @@ -4163,7 +4163,7 @@ name = "suspicious button" }, /obj/machinery/vending/cigarette/free{ - product_slogans = "Just remember! No capitalist.;Best enjoyed with Vodka!.;Smoke!;Nine out of ten USSP scientists agree, smoking reduces stress!;There's no cigarette like a Russian cigarette!;Cigarettes! Now with 100% less capitalism." + slogan_list = list("Just remember! No capitalist.","Best enjoyed with Vodka!.","Smoke!","Nine out of ten USSP scientists agree, smoking reduces stress!","There's no cigarette like a Russian cigarette!","Cigarettes! Now with 100% less capitalism.") }, /turf/simulated/floor/wood{ broken = 1; @@ -5186,7 +5186,7 @@ "kW" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/vending/cigarette/free{ - product_slogans = "Just remember! No capitalist.;Best enjoyed with Vodka!.;Smoke!;Nine out of ten USSP scientists agree, smoking reduces stress!;There's no cigarette like a Russian cigarette!;Cigarettes! Now with 100% less capitalism." + slogan_list = list("Just remember! No capitalist.","Best enjoyed with Vodka!.","Smoke!","Nine out of ten USSP scientists agree, smoking reduces stress!","There's no cigarette like a Russian cigarette!","Cigarettes! Now with 100% less capitalism.") }, /turf/simulated/floor/plasteel{ dir = 5; @@ -6363,7 +6363,7 @@ icon_state = "sink"; pixel_x = 12 }, -/turf/simulated/floor/mineral/plasma, +/turf/simulated/floor/mineral/silver, /area/syndicate_depot/core) "of" = ( /obj/structure/closet/secure_closet/syndicate/depot, @@ -6448,26 +6448,9 @@ icon_state = "wood" }, /area/derelict/crew_quarters) -"oo" = ( -/obj/effect/spawner/random_spawners/syndicate/layout/door/secret, -/turf/simulated/floor/plasteel{ - icon_state = "dark" - }, -/area/syndicate_depot/core) "op" = ( /turf/simulated/floor/mineral/silver, /area/syndicate_depot/core) -"oq" = ( -/obj/machinery/door/airlock/plasma{ - welded = 1 - }, -/turf/simulated/floor/plasteel{ - icon_state = "dark" - }, -/area/syndicate_depot/core) -"or" = ( -/turf/simulated/floor/mineral/plasma, -/area/syndicate_depot/core) "os" = ( /obj/structure/table, /obj/effect/spawner/random_spawners/syndicate/loot/stetchkin, @@ -6543,7 +6526,7 @@ /area/syndicate_depot/core) "oB" = ( /obj/effect/spawner/random_spawners/syndicate/mob, -/turf/simulated/floor/mineral/plasma, +/turf/simulated/floor/mineral/silver, /area/syndicate_depot/core) "oC" = ( /obj/effect/landmark{ @@ -6706,27 +6689,14 @@ icon_state = "dark" }, /area/syndicate_depot/core) -"oZ" = ( -/obj/structure/mirror{ - pixel_x = -32 - }, -/turf/simulated/floor/mineral/plasma, -/area/syndicate_depot/core) "pa" = ( /obj/structure/toilet{ dir = 8 }, /turf/simulated/floor/mineral/silver, /area/syndicate_depot/core) -"pb" = ( -/obj/machinery/portable_atmospherics/canister/toxins, -/turf/simulated/floor/plasteel{ - icon_state = "dark" - }, -/area/syndicate_depot/core) "pc" = ( /obj/machinery/light, -/obj/effect/spawner/random_spawners/syndicate/loot/level3, /turf/simulated/floor/plasteel{ icon_state = "dark" }, @@ -9114,7 +9084,7 @@ }) "tY" = ( /obj/machinery/vending/cigarette/free{ - product_slogans = "Just remember! No capitalist.;Best enjoyed with Vodka!.;Smoke!;Nine out of ten USSP scientists agree, smoking reduces stress!;There's no cigarette like a Russian cigarette!;Cigarettes! Now with 100% less capitalism." + slogan_list = list("Just remember! No capitalist.","Best enjoyed with Vodka!.","Smoke!","Nine out of ten USSP scientists agree, smoking reduces stress!","There's no cigarette like a Russian cigarette!","Cigarettes! Now with 100% less capitalism.") }, /turf/simulated/floor/plasteel{ icon_state = "bar" @@ -10678,7 +10648,7 @@ /area/derelict/arrival) "xe" = ( /obj/machinery/vending/cigarette/free{ - product_slogans = "Just remember! No capitalist.;Best enjoyed with Vodka!.;Smoke!;Nine out of ten USSP scientists agree, smoking reduces stress!;There's no cigarette like a Russian cigarette!;Cigarettes! Now with 100% less capitalism." + slogan_list = list("Just remember! No capitalist.","Best enjoyed with Vodka!.","Smoke!","Nine out of ten USSP scientists agree, smoking reduces stress!","There's no cigarette like a Russian cigarette!","Cigarettes! Now with 100% less capitalism.") }, /turf/simulated/floor/plasteel{ dir = 2; @@ -11582,10 +11552,10 @@ }, /area/space/nearstation) "zR" = ( -/obj/machinery/portable_atmospherics/canister/toxins, /obj/machinery/light/small{ dir = 1 }, +/obj/effect/decal/cleanable/blood, /turf/simulated/floor/plasteel{ icon_state = "dark" }, @@ -57707,7 +57677,7 @@ of ot mA mA -pb +nX pi mA py @@ -59251,7 +59221,7 @@ oE oR oE oz -pb +mA mA mA mm @@ -61558,7 +61528,7 @@ mm mB mm mm -oo +mm mm lV mA @@ -61816,7 +61786,7 @@ mA zP mm zR -oo +mm oL ns mA @@ -62072,7 +62042,7 @@ mA mA mt mm -oq +mm mm mm mm @@ -62332,7 +62302,7 @@ mm op oB oM -oZ +oM ob mA pu @@ -62586,7 +62556,7 @@ zP mA mA ob -or +op nJ oe pa diff --git a/_maps/test_all_maps.dm b/_maps/test_all_maps.dm deleted file mode 100644 index 94bd9bac437..00000000000 --- a/_maps/test_all_maps.dm +++ /dev/null @@ -1,145 +0,0 @@ -// 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\academy.dmm" - #include "map_files\RandomZLevels\beach.dmm" - #include "map_files\RandomZLevels\blackmarketpackers.dmm" - #include "map_files\RandomZLevels\centcomAway.dmm" - #include "map_files\RandomZLevels\evil_santa.dmm" - #include "map_files\RandomZLevels\example.dmm" - #include "map_files\RandomZLevels\moonoutpost19.dmm" - #include "map_files\RandomZLevels\spacebattle.dmm" - #include "map_files\RandomZLevels\spacehotel.dmm" - #include "map_files\RandomZLevels\stationCollision.dmm" - #include "map_files\RandomZLevels\terrorspiders.dmm" - #include "map_files\RandomZLevels\undergroundoutpost45.dmm" - #include "map_files\RandomZLevels\wildwest.dmm" - - - // Lavaland Ruins - #include "map_files\RandomRuins\LavaRuins\lavaland_biodome_beach.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_biodome_clown_planet.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_biodome_winter.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_animal_hospital.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_ash_walker1.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_blooddrunk1.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_blooddrunk2.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_blooddrunk3.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_cube.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_cultaltar.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_dead_ratvar.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_envy.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_fountain_hall.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_gluttony.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_greed.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_hermit.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_hierophant.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_pizzaparty.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_pride.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_puzzle.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_random_ripley.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_seed_vault.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_sloth.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_survivalpod.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_swarmer_crash.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_syndicate_base1.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_ufo_crash.dmm" - #include "map_files\RandomRuins\LavaRuins\lavaland_surface_xeno_nest.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\oldstation.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" - - // 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/travis_map_testing.dm b/_maps/travis_map_testing.dm new file mode 100644 index 00000000000..89fc4ec49ce --- /dev/null +++ b/_maps/travis_map_testing.dm @@ -0,0 +1,157 @@ +// This is for Travis testing. DO NOT SET THIS AS THE GAME'S MAP NORMALLY! + +#if !defined(USING_MAP_DATUM) + // Cyberiad + #include "map_files/Cyberiad/cyberiad.dmm" + #include "map_files/Cyberiad/z2.dmm" + #include "map_files/Cyberiad/z3.dmm" + #include "map_files/Cyberiad/z4.dmm" + #include "map_files/Cyberiad/z6.dmm" + + // Debug Maps + #include "map_files/Debug/singletile.dmm" + #include "map_files/Debug/smoothing.dmm" + + // Delta + #include "map_files/Delta/delta.dmm" + + // Generic Z Levels + #include "map_files/Generic/Lavaland.dmm" + #include "map_files/Generic/z6.dmm" + #include "map_files/Generic/z7.dmm" + + // MetaStation + #include "map_files/MetaStation/MetaStation.v41A.II.dmm" + #include "map_files/MetaStation/z2.dmm" + #include "map_files/MetaStation/z3.dmm" + #include "map_files/MetaStation/z4.dmm" + + // Lavaland Ruins + #include "map_files/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_biodome_winter.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_animal_hospital.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_blooddrunk1.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_blooddrunk2.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_blooddrunk3.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_cube.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_cultaltar.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_dead_ratvar.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_envy.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_fountain_hall.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_gluttony.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_greed.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_pride.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_puzzle.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_random_ripley.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_sloth.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_swarmer_crash.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm" + #include "map_files/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.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/oldstation.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" + #include "map_files/RandomRuins/SpaceRuins/wizardcrash.dmm" + + // Gateway Missions + #include "map_files/RandomZLevels/academy.dmm" + #include "map_files/RandomZLevels/beach.dmm" + #include "map_files/RandomZLevels/blackmarketpackers.dmm" + #include "map_files/RandomZLevels/centcomAway.dmm" + #include "map_files/RandomZLevels/evil_santa.dmm" + #include "map_files/RandomZLevels/example.dmm" + #include "map_files/RandomZLevels/moonoutpost19.dmm" + #include "map_files/RandomZLevels/spacebattle.dmm" + #include "map_files/RandomZLevels/spacehotel.dmm" + #include "map_files/RandomZLevels/stationCollision.dmm" + #include "map_files/RandomZLevels/terrorspiders.dmm" + #include "map_files/RandomZLevels/undergroundoutpost45.dmm" + #include "map_files/RandomZLevels/wildwest.dmm" + + // Shuttles + #include "map_files/shuttles/admin_admin.dmm" + #include "map_files/shuttles/admin_hospital.dmm" + #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" + + // Templates + #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" + + // Spacehotel Rooms + #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" + +#elif !defined(MAP_OVERRIDE) + #warn a map has already been included. +#endif diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 956930aae70..2f98b6ee7b5 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -35,7 +35,6 @@ #define CANPUSH 8 #define PASSEMOTES 16 //Mob has a cortical borer or holders inside of it that need to see emotes. #define GOTTAGOFAST 32 -#define GOTTAGOFAST_METH 64 #define IGNORESLOWDOWN 128 #define GODMODE 4096 #define FAKEDEATH 8192 //Replaces stuff like changeling.changeling_fakedeath diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm index 01dbc2f1c2b..34528090e86 100644 --- a/code/__DEFINES/lighting.dm +++ b/code/__DEFINES/lighting.dm @@ -90,3 +90,27 @@ #define FLASH_LIGHT_DURATION 2 #define FLASH_LIGHT_POWER 3 #define FLASH_LIGHT_RANGE 3.8 + +/// Returns the red part of a #RRGGBB hex sequence as number +#define GETREDPART(hexa) hex2num(copytext(hexa, 2, 4)) + +/// Returns the green part of a #RRGGBB hex sequence as number +#define GETGREENPART(hexa) hex2num(copytext(hexa, 4, 6)) + +/// Returns the blue part of a #RRGGBB hex sequence as number +#define GETBLUEPART(hexa) hex2num(copytext(hexa, 6, 8)) + +/// Parse the hexadecimal color into lumcounts of each perspective. +#define PARSE_LIGHT_COLOR(source) \ +do { \ + if (source.light_color) { \ + var/__light_color = source.light_color; \ + source.lum_r = GETREDPART(__light_color) / 255; \ + source.lum_g = GETGREENPART(__light_color) / 255; \ + source.lum_b = GETBLUEPART(__light_color) / 255; \ + } else { \ + source.lum_r = 1; \ + source.lum_g = 1; \ + source.lum_b = 1; \ + }; \ +} while (FALSE) diff --git a/code/__DEFINES/logs.dm b/code/__DEFINES/logs.dm index a8a4a457c7c..25d1fac7323 100644 --- a/code/__DEFINES/logs.dm +++ b/code/__DEFINES/logs.dm @@ -3,4 +3,4 @@ #define CONVERSION_LOG "Conversion" #define SAY_LOG "Say" #define EMOTE_LOG "Emote" -#define MISC_LOG "Misc" \ No newline at end of file +#define MISC_LOG "Misc" diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 7eaaa86747e..cf27ec09143 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -319,7 +319,7 @@ #define INVESTIGATE_BOMB "bombs" // The SQL version required by this version of the code -#define SQL_VERSION 11 +#define SQL_VERSION 12 // Vending machine stuff #define CAT_NORMAL 1 @@ -345,7 +345,7 @@ #define MOUSE_OPACITY_OPAQUE 2 // Defib stats -#define DEFIB_TIME_LIMIT 120 +#define DEFIB_TIME_LIMIT 300 #define DEFIB_TIME_LOSS 60 //different types of atom colorations diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 2b9e2c56b4d..8021fa4452d 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -48,7 +48,7 @@ //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 //(in game days played) to play that role -var/global/list/special_roles = list( +GLOBAL_LIST_INIT(special_roles, list( ROLE_ABDUCTOR = /datum/game_mode/abduction, // Abductor ROLE_BLOB = /datum/game_mode/blob, // Blob ROLE_CHANGELING = /datum/game_mode/changeling, // Changeling @@ -72,10 +72,10 @@ var/global/list/special_roles = list( ROLE_VAMPIRE = /datum/game_mode/vampire, // Vampire ROLE_RAIDER = /datum/game_mode/heist, // Vox raider ROLE_ALIEN, // Xenomorph - ROLE_WIZARD = /datum/game_mode/wizard, // Wizard + ROLE_WIZARD = /datum/game_mode/wizard // Wizard // UNUSED/BROKEN ANTAGS // ROLE_HOG_GOD = /datum/game_mode/hand_of_god, // ROLE_HOG_CULTIST = /datum/game_mode/hand_of_god, // ROLE_MONKEY = /datum/game_mode/monkey, Sooner or later these are going to get ported -// ROLE_GANG = /datum/game_mode/gang, -) +// ROLE_GANG = /datum/game_mode/gang +)) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 8de2f30ad2f..2217271a2e7 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -417,16 +417,6 @@ return 0 return 1 - -/proc/GetRedPart(const/hexa) - return hex2num(copytext(hexa, 2, 4)) - -/proc/GetGreenPart(const/hexa) - return hex2num(copytext(hexa, 4, 6)) - -/proc/GetBluePart(const/hexa) - return hex2num(copytext(hexa, 6, 8)) - /proc/lavaland_equipment_pressure_check(turf/T) . = FALSE if(!istype(T)) @@ -438,13 +428,6 @@ if(pressure <= LAVALAND_EQUIPMENT_EFFECT_PRESSURE) . = TRUE -/proc/GetHexColors(const/hexa) - return list( - GetRedPart(hexa), - GetGreenPart(hexa), - GetBluePart(hexa), - ) - /proc/MinutesToTicks(var/minutes as num) return minutes * 60 * 10 diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index d70712c0010..4e11dbf4140 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -580,7 +580,7 @@ world var/B = RGB[2] var/Y = (0.2126 * R) + (0.7152 * G) + (0.0722 * B) - return clamp((Y * 0.01), 0, 1) //Returns the brightness of a color in decimal percentage format. Can multiply light_power by this to receive 100% brightness or a lower brightness. Not a higher brightness. + return Clamp((Y * 0.01), 0, 1) //Returns the brightness of a color in decimal percentage format. Can multiply light_power by this to receive 100% brightness or a lower brightness. Not a higher brightness. /proc/HueToAngle(hue) // normalize hsv in case anything is screwy diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index d702c073b86..29e0f9b52b9 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -19,10 +19,10 @@ GLOBAL_VAR(command_name) /proc/command_name() return GLOB.using_map.dock_name -var/religion_name = null +GLOBAL_VAR(religion_name) /proc/religion_name() - if(religion_name) - return religion_name + if(GLOB.religion_name) + return GLOB.religion_name var/name = "" diff --git a/code/_globalvars/configuration.dm b/code/_globalvars/configuration.dm index 5cf36541eeb..ea2cf1290fd 100644 --- a/code/_globalvars/configuration.dm +++ b/code/_globalvars/configuration.dm @@ -4,7 +4,6 @@ GLOBAL_VAR(host) GLOBAL_VAR(join_motd) GLOBAL_VAR(join_tos) GLOBAL_VAR_INIT(game_version, "ParaCode") -GLOBAL_VAR_INIT(changelog_hash, md5('html/changelog.html')) //used to check if the CL changed GLOBAL_VAR_INIT(game_year, (text2num(time2text(world.realtime, "YYYY")) + 544)) GLOBAL_VAR_INIT(aliens_allowed, 1) diff --git a/code/_globalvars/lists/reagents.dm b/code/_globalvars/lists/reagents.dm index 20620d60800..abd878ff936 100644 --- a/code/_globalvars/lists/reagents.dm +++ b/code/_globalvars/lists/reagents.dm @@ -64,3 +64,5 @@ GLOBAL_LIST_INIT(safe_chem_list, list("antihol", "charcoal", "epinephrine", "ins "omnizine", "stimulants", "synaptizine", "potass_iodide", "oculine", "mannitol", "styptic_powder", "spaceacillin", "salglu_solution", "sal_acid", "cryoxadone", "blood", "synthflesh", "hydrocodone", "mitocholide", "rezadone")) + +GLOBAL_LIST_INIT(safe_chem_applicator_list, list("silver_sulfadiazine", "styptic_powder", "synthflesh")) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 6bfd72413de..20e50bb3054 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -261,12 +261,12 @@ if(incapacitated()) return var/face_dir = get_cardinal_dir(src, A) - if(forced_look == face_dir) + if(!face_dir || forced_look == face_dir || A == src) forced_look = null - to_chat(src, "You are no longer facing any direction.") + to_chat(src, "Cancelled direction lock.") return forced_look = face_dir - to_chat(src, "You are now facing [dir2text(forced_look)].") + to_chat(src, "You are now facing [dir2text(forced_look)]. To cancel this, shift-middleclick yourself.") /* Middle shift-control-click @@ -274,12 +274,12 @@ */ /mob/proc/MiddleShiftControlClickOn(atom/A) var/face_uid = A.UID() - if(forced_look == face_uid) + if(forced_look == face_uid || A == src) forced_look = null - to_chat(src, "You are no longer facing [A].") + to_chat(src, "Cancelled direction lock.") return forced_look = face_uid - to_chat(src, "You are now facing [A].") + to_chat(src, "You are now facing [A]. To cancel this, shift-middleclick yourself.") // In case of use break glass /* diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index cc0269cdc95..29edee05120 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -58,7 +58,7 @@ else return 1 var/obj/item/organ/external/O = M.get_organ(user.zone_selected) - if((is_sharp(src) || (isscrewdriver(src) && O.is_robotic())) && user.a_intent == INTENT_HELP) + if((is_sharp(src) || (isscrewdriver(src) && O?.is_robotic())) && user.a_intent == INTENT_HELP) if(!attempt_initiate_surgery(src, M, user)) return FALSE else diff --git a/code/controllers/master.dm b/code/controllers/master.dm index f64e566e097..a6026823ec9 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -146,7 +146,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new msg = "The [BadBoy.name] subsystem was the last to fire for 2 controller restarts. It will be recovered now and disabled if it happens again." FireHim = TRUE if(3) - msg = "The [BadBoy.name] subsystem seems to be destabilizing the MC and will be offlined." + msg = "The [BadBoy.name] subsystem seems to be destabilizing the MC and will be offlined. The following implications are now in effect: [BadBoy.offline_implications]" BadBoy.flags |= SS_NO_FIRE if(msg) to_chat(GLOB.admins, "[msg]") diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index f257f2b4895..4a125003389 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -35,6 +35,8 @@ var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out! + var/offline_implications = "None" // What are the implications of this SS being offlined? + //Do not override ///datum/controller/subsystem/New() diff --git a/code/controllers/subsystem/acid.dm b/code/controllers/subsystem/acid.dm index 40063b00a87..119d82113d7 100644 --- a/code/controllers/subsystem/acid.dm +++ b/code/controllers/subsystem/acid.dm @@ -3,6 +3,7 @@ SUBSYSTEM_DEF(acid) priority = FIRE_PRIORITY_ACID flags = SS_NO_INIT|SS_BACKGROUND runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + offline_implications = "Objects will no longer react to acid. No immediate action is needed." var/list/currentrun = list() var/list/processing = list() diff --git a/code/controllers/subsystem/afk.dm b/code/controllers/subsystem/afk.dm index 6ab1d67a816..9122e6a16c6 100644 --- a/code/controllers/subsystem/afk.dm +++ b/code/controllers/subsystem/afk.dm @@ -5,6 +5,7 @@ SUBSYSTEM_DEF(afk) name = "AFK Watcher" wait = 300 flags = SS_BACKGROUND + offline_implications = "Players will no longer be marked as AFK. No immediate action is needed." var/list/afk_players = list() // Associative list. ckey as key and AFK state as value @@ -17,27 +18,27 @@ SUBSYSTEM_DEF(afk) for(var/mob/living/carbon/human/H in GLOB.living_mob_list) if(!H.ckey) // Useless non ckey creatures continue - - var/turf/T + + var/turf/T // Only players and players with the AFK watch enabled // No dead, unconcious, restrained, people without jobs, people on other Z levels than the station or antags if(!H.client || !H.client.prefs.afk_watch || !H.mind || \ H.stat || H.restrained() || !H.job || H.mind.special_role || \ !is_station_level((T = get_turf(H)).z)) // Assign the turf as last. Small optimization - if(afk_players[H.ckey]) + if(afk_players[H.ckey]) toRemove += H.ckey continue - + var/mins_afk = round(H.client.inactivity / 600) if(mins_afk < config.warn_afk_minimum) if(afk_players[H.ckey]) toRemove += H.ckey continue - + if(!afk_players[H.ckey]) afk_players[H.ckey] = AFK_WARNED warn(H, "You are AFK for [mins_afk] minutes. You will be cryod after [config.auto_cryo_afk] total minutes and fully despawned after [config.auto_despawn_afk] total minutes. Please move or click in game if you want to avoid being despawned.") - else + else var/area/A = T.loc // Turfs loc is the area if(afk_players[H.ckey] == AFK_WARNED) if(mins_afk >= config.auto_cryo_afk && A.can_get_auto_cryod) @@ -50,14 +51,14 @@ SUBSYSTEM_DEF(afk) afk_players[H.ckey] = AFK_CRYOD msg_admins(H, mins_afk, T, "put into cryostorage") warn(H, "You are AFK for [mins_afk] minutes and have been moved to cryostorage. After being AFK for [config.auto_despawn_afk] total minutes you will be fully despawned. Please eject yourself (right click, eject) out of the cryostorage if you want to avoid being despawned.") - + else if(mins_afk >= config.auto_despawn_afk) var/obj/machinery/cryopod/P = H.loc msg_admins(H, mins_afk, T, "forcefully despawned") warn(H, "You are have been despawned after being AFK for [mins_afk] minutes.") toRemove += H.ckey P.despawn_occupant() - + removeFromWatchList(toRemove) /datum/controller/subsystem/afk/proc/warn(mob/living/carbon/human/H, text) diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 6f2a451ef76..80ce66d13ec 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -14,6 +14,7 @@ SUBSYSTEM_DEF(air) wait = 5 flags = SS_BACKGROUND runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + offline_implications = "Turfs will no longer process atmos, and all atmospheric machines (including cryotubes) will no longer function. Shuttle call recommended." var/cost_turfs = 0 var/cost_groups = 0 var/cost_highpressure = 0 diff --git a/code/controllers/subsystem/alarm.dm b/code/controllers/subsystem/alarm.dm index bac32a449de..289adf6de40 100644 --- a/code/controllers/subsystem/alarm.dm +++ b/code/controllers/subsystem/alarm.dm @@ -1,6 +1,7 @@ SUBSYSTEM_DEF(alarms) name = "Alarms" init_order = INIT_ORDER_ALARMS // 2 + offline_implications = "Alarms (Power, camera, fire, etc) will no longer be checked. No immediate action is needed." var/datum/alarm_handler/atmosphere/atmosphere_alarm = new() var/datum/alarm_handler/burglar/burglar_alarm = new() var/datum/alarm_handler/camera/camera_alarm = new() diff --git a/code/controllers/subsystem/changelog.dm b/code/controllers/subsystem/changelog.dm new file mode 100644 index 00000000000..98188599abd --- /dev/null +++ b/code/controllers/subsystem/changelog.dm @@ -0,0 +1,263 @@ +/* + Subsystem core for ParadiseSS13 changelogs + Author: AffectedArc07 + + Basically this SS extracts changelogs from the past 30 days from the database, and cleanly formats them into HTML that the players can see + It only runs the extraction on initialize to ensure that the changelog doesnt change mid round, and to reduce the amount of DB calls that need to be done + The changelog entries are generated from the PHP scripts in tools/githubChangelogProcessor.php + + This SS also handles the checking of player CL dates and informing them if it has changed + +*/ + +SUBSYSTEM_DEF(changelog) + name = "Changelog" + flags = SS_NO_FIRE + var/current_cl_timestamp = "0" // Timestamp is seconds since UNIX epoch (1st January 1970). ITs also a string because BYOND doesnt like big numbers. + var/ss_ready = FALSE // Is the SS ready? We dont want to run procs if we have not generated yet + var/list/startup_clients_button = list() // Clients who connected before initialization who need their button color updating + var/list/startup_clients_open = list() // Clients who connected before initialization who need the CL opening + var/changelogHTML = "" // HTML that the changelog will use to display + +/datum/controller/subsystem/changelog/Initialize() + // This entire subsystem relies on SQL being here. + if(!GLOB.dbcon.IsConnected()) + return ..() + + var/DBQuery/latest_cl_date = GLOB.dbcon.NewQuery("SELECT UNIX_TIMESTAMP(date_merged) AS ut FROM [format_table_name("changelog")] ORDER BY date_merged DESC LIMIT 1") + if(!latest_cl_date.Execute()) + var/err = latest_cl_date.ErrorMsg() + log_game("SQL ERROR during SSchangelog initialization L24. Error: \[[err]\]\n") + message_admins("SQL ERROR during SSchangelog initialization L24. Error: \[[err]\]\n") + // Abort if we cant do this + return ..() + + while(latest_cl_date.NextRow()) + current_cl_timestamp = latest_cl_date.item[1] + + if(!GenerateChangelogHTML()) // if this failed to generate + to_chat(world, "WARNING: Changelog failed to generate. Please inform a coder/server dev") + return ..() + + ss_ready = TRUE + // Now we can alert anyone who wanted to check the changelog + for(var/x in startup_clients_button) + var/client/C = x + UpdatePlayerChangelogButton(C) + + // Now we can alert anyone who wanted to check the changelog + for(var/client/C in startup_clients_open) + OpenChangelog(C) + + return ..() + + +/datum/controller/subsystem/changelog/proc/UpdatePlayerChangelogDate(client/C) + if(!ss_ready) + return // Only return here, we dont have to worry about a queue list because this will be called from ShowChangelog() + // Technically this is only for the date but we can also do the UI button at the same time + var/datum/preferences/P = GLOB.preferences_datums[C.ckey] + if(P.toggles & UI_DARKMODE) + winset(C, "rpane.changelog", "background-color=#40628a;font-color=#ffffff;font-style=none") + else + winset(C, "rpane.changelog", "background-color=none;font-style=none") + C.prefs.lastchangelog = current_cl_timestamp + var/DBQuery/updatePlayerCLTime = GLOB.dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastchangelog='[sanitizeSQL(current_cl_timestamp)]' WHERE ckey='[C.ckey]'") + if(!updatePlayerCLTime.Execute()) + var/err = updatePlayerCLTime.ErrorMsg() + log_game("SQL ERROR during lastchangelog updating. Error: \[[err]\]\n") + message_admins("SQL ERROR during lastchangelog updating. Error: \[[err]\]\n") + to_chat(C, "Couldn't update your last seen changelog, please try again later.") + return FALSE + return TRUE + +/datum/controller/subsystem/changelog/proc/UpdatePlayerChangelogButton(client/C) + // If SQL aint even enabled, just set the button to default style + if(!GLOB.dbcon.IsConnected()) + if(C.prefs.toggles & UI_DARKMODE) + winset(C, "rpane.changelog", "background-color=#40628a;text-color=#FFFFFF") + else + winset(C, "rpane.changelog", "background-color=none;text-color=#000000") + return + + // If SQL is enabled but we aint ready, queue them up, and use the default style + if(!ss_ready) + startup_clients_button |= C + if(C.prefs.toggles & UI_DARKMODE) + winset(C, "rpane.changelog", "background-color=#40628a;text-color=#FFFFFF") + else + winset(C, "rpane.changelog", "background-color=none;text-color=#000000") + return + + // Sanity check to ensure clients still exist (If a client DCs mid startup this would runtime) + if(C && C.prefs) + // If we are ready, process the button style + if(C.prefs.lastchangelog != current_cl_timestamp) + winset(C, "rpane.changelog", "background-color=#bb7700;text-color=#FFFFFF;font-style=bold") + to_chat(C, "Changelog has changed since your last visit.") + else + if(C.prefs.toggles & UI_DARKMODE) + winset(C, "rpane.changelog", "background-color=#40628a;text-color=#FFFFFF") + else + winset(C, "rpane.changelog", "background-color=none;text-color=#000000") + + +/datum/controller/subsystem/changelog/proc/OpenChangelog(client/C) + // If SQL isnt enabled, dont even queue them, just tell them it wont work + if(!GLOB.dbcon.IsConnected()) + to_chat(C, "This server is not running with an SQL backend. Changelog is unavailable.") + return + + // If SQL is enabled but we aint ready, queue them up + if(!ss_ready) + startup_clients_open |= C + to_chat(C, "The changelog system is still initializing. The changelog will open for you once it has initialized.") + return + + UpdatePlayerChangelogDate(C) + UpdatePlayerChangelogButton(C) + + var/datum/browser/cl_popup = new(C.mob, "changelog", "Changelog", 700, 800) + cl_popup.set_content(changelogHTML) + cl_popup.open() + +/client/verb/changes() + set name = "Changelog" + set desc = "View the changelog." + set category = "OOC" + // Just invoke the actual CL thing + SSchangelog.OpenChangelog(src) + +// Helper to turn CL types into a fontawesome icon instead of an image +// The colors are #28a745 for green, #fd7e14 for orange, and #dc3545 for red. +// These colours are from bootstrap and look good with black and white +/datum/controller/subsystem/changelog/proc/Text2Icon(text) + switch(text) + if("FIX") + return "" // Fixes are white because while they are good, they have no negative coutnerpart + if("WIP") + return "" // WIP stuff is orange because new code is good but its not done yet + if("TWEAK") + return "" // Tweaks are white because they could be good or bad, and theres no specific add or remove + if("SOUNDADD") + return "" // Sound additions are green because its something new + if("SOUNDDEL") + return "" // Sound removals are red because something has been removed + if("CODEADD") + return "" // Code additions are green because its something new + if("CODEDEL") + return "" // Code removals are red becuase someting has been removed + if("IMAGEADD") + return "" // Image additions are green because something has been added + if("IMAGEDEL") + return "" // Image removals are red because something has been removed + if("SPELLCHECK") + return "" // Spellcheck is white because theres no dedicated negative to it, so theres no red for it to collate with + if("EXPERIMENT") + return "" // Experimental stuff is orange because while its a new feature, its unstable + else // Just incase the DB somehow breaks + return "" // Same here + +// This proc is the star of the show +/datum/controller/subsystem/changelog/proc/GenerateChangelogHTML() + // Modify the code below to modify the header of the changelog + var/changelog_header = {" + + ParadiseSS13 Changelog + +
+

Paradise Station Changelog

+

Forum - Wiki - GitHub

+
+ "} + + var/list/prs_to_process = list() + // Grab all from last 30 days + var/DBQuery/pr_list_query = GLOB.dbcon.NewQuery("SELECT DISTINCT pr_number FROM changelog WHERE date_merged BETWEEN NOW() - INTERVAL 30 DAY AND NOW() ORDER BY date_merged DESC") + if(!pr_list_query.Execute()) + var/err = pr_list_query.ErrorMsg() + log_game("SQL ERROR during CL generation L143. Error: \[[err]\]\n") + message_admins("SQL ERROR during CL generation L143. Error: \[[err]\]\n") + return FALSE + + while(pr_list_query.NextRow()) + prs_to_process += text2num(pr_list_query.item[1]) + + // Load in the header + changelogHTML += changelog_header + + // Make blocks for all the PRs + for(var/pr_number in prs_to_process) + // Initial declarations + var/pr_block = "" // HTML for the changelog section + var/author = "" // Author of the PR + var/merge_date = "" // Timestamp of when the PR was merged + + // Now we gather the data from the DB + // Also we probably dont need to sanitize the PR number but you never know + var/DBQuery/pr_meta = GLOB.dbcon.NewQuery("SELECT author,DATE(date_merged) AS date FROM changelog WHERE pr_number = [sanitizeSQL(pr_number)] LIMIT 1") + if(!pr_meta.Execute()) + var/err = pr_meta.ErrorMsg() + log_game("SQL ERROR during CL generation L190. Error: \[[err]\]\n") + message_admins("SQL ERROR during CL generation L190. Error: \[[err]\]\n") + return FALSE + + while(pr_meta.NextRow()) + author = pr_meta.item[1] + merge_date = pr_meta.item[2] + + // Now for each actual entry + var/DBQuery/db_entries = GLOB.dbcon.NewQuery("SELECT cl_type, cl_entry FROM changelog WHERE pr_number = [sanitizeSQL(pr_number)]") + if(!db_entries.Execute()) + var/err = db_entries.ErrorMsg() + log_game("SQL ERROR during CL generation L204. Error: \[[err]\]\n") + message_admins("SQL ERROR during CL generation L204. Error: \[[err]\]\n") + return FALSE + + + // Now we make a changelog block + pr_block += "
" + // If the github URL in the config has a trailing slash, it doesnt matter here, thankfully github accepts having a double slash: https://github.com/org/repo//pull/1 + pr_block += "

#[pr_number] by [author] (Merged on [merge_date])" + + while(db_entries.NextRow()) + pr_block += "

[Text2Icon(db_entries.item[1])] [db_entries.item[2]]

" + + pr_block += "

" + + changelogHTML += pr_block + + // Make sure we return TRUE so we know it worked + return TRUE + + +// Topic handler so that PRs and forums and stuff open in another window +/datum/controller/subsystem/changelog/Topic(href, href_list) + // Handler to open pages in your browser instead of inside the CL window + // Yes usr.client is gross here but src is the subsystem + // Takes the page to open as an argument + if(href_list["openPage"]) + switch(href_list["openPage"]) + if("forum") + usr.client.forum() + if("wiki") + // Wiki needs snowflake because it has no cancel button + if(config.wikiurl) + if(alert("This will open the wiki in your browser. Are you sure?",,"Yes","No")=="No") + return + usr.client.wiki("") // Blank arg is important here + else + to_chat(usr, "The Wiki URL is not set in the server configuration. Please inform the server host.") + + if("github") + usr.client.github() + // Takes a PR number as argument + if(href_list["openPR"]) + if(config.githuburl) + if(alert("This will open PR #[href_list["openPR"]] in your browser. Are you sure?",,"Yes","No")=="No") + return + var/url = "[config.githuburl]/pull/[href_list["openPR"]]" + usr << link(url) + else + to_chat(usr, "The GitHub URL is not set in the server configuration. PRs cannot be opened from changelog view. Please inform the server host.") + diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm index dbe38634e6a..4eb468a0952 100644 --- a/code/controllers/subsystem/chat.dm +++ b/code/controllers/subsystem/chat.dm @@ -4,6 +4,7 @@ SUBSYSTEM_DEF(chat) wait = 1 priority = FIRE_PRIORITY_CHAT init_order = INIT_ORDER_CHAT + offline_implications = "Chat messages will no longer be cleanly queued. No immediate action is needed." var/list/payload = list() diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm index 3612faa4a7e..ad77904bac7 100644 --- a/code/controllers/subsystem/events.dm +++ b/code/controllers/subsystem/events.dm @@ -2,6 +2,7 @@ SUBSYSTEM_DEF(events) name = "Events" init_order = INIT_ORDER_EVENTS runlevels = RUNLEVEL_GAME + offline_implications = "Random events will no longer happen. No immediate action is needed." // Report events at the end of the rouund var/report_at_round_end = 0 diff --git a/code/controllers/subsystem/fires.dm b/code/controllers/subsystem/fires.dm index aafc5ed48d5..dc419fffeb5 100644 --- a/code/controllers/subsystem/fires.dm +++ b/code/controllers/subsystem/fires.dm @@ -3,6 +3,7 @@ SUBSYSTEM_DEF(fires) priority = FIRE_PRIOTITY_BURNING flags = SS_NO_INIT|SS_BACKGROUND runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + offline_implications = "Objects will no longer react to fires. No immediate action is needed." var/list/currentrun = list() var/list/processing = list() diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 4bc3965e6cf..cbf17d05fbf 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -5,6 +5,7 @@ SUBSYSTEM_DEF(garbage) flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY init_order = INIT_ORDER_GARBAGE + offline_implications = "Garbage collection is no longer functional, and objects will not be qdel'd. Immediate server restart recommended." var/list/collection_timeout = list(0, 2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level diff --git a/code/controllers/subsystem/icon_smooth.dm b/code/controllers/subsystem/icon_smooth.dm index 531b6af2e78..289505a153c 100644 --- a/code/controllers/subsystem/icon_smooth.dm +++ b/code/controllers/subsystem/icon_smooth.dm @@ -4,6 +4,7 @@ SUBSYSTEM_DEF(icon_smooth) wait = 1 priority = FIRE_PRIOTITY_SMOOTHING flags = SS_TICKER + offline_implications = "Objects will no longer smooth together properly. No immediate action is needed." var/list/smooth_queue = list() diff --git a/code/controllers/subsystem/idlenpcpool.dm b/code/controllers/subsystem/idlenpcpool.dm index 42df941e10f..d61b90f1239 100644 --- a/code/controllers/subsystem/idlenpcpool.dm +++ b/code/controllers/subsystem/idlenpcpool.dm @@ -4,6 +4,7 @@ SUBSYSTEM_DEF(idlenpcpool) priority = FIRE_PRIORITY_IDLE_NPC wait = 60 runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + offline_implications = "Idle simple animals will no longer process. Shuttle call recommended." var/list/currentrun = list() var/static/list/idle_mobs_by_zlevel[][] @@ -39,4 +40,4 @@ SUBSYSTEM_DEF(idlenpcpool) if(SA.stat != DEAD) SA.consider_wakeup() if(MC_TICK_CHECK) - return + return diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm index f379deec72b..9dd6fce1554 100644 --- a/code/controllers/subsystem/input.dm +++ b/code/controllers/subsystem/input.dm @@ -5,6 +5,7 @@ SUBSYSTEM_DEF(input) flags = SS_TICKER priority = FIRE_PRIORITY_INPUT runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY + offline_implications = "Player input will no longer be recognised. Immediate server restart recommended." var/list/macro_sets var/list/movement_keys @@ -24,7 +25,7 @@ SUBSYSTEM_DEF(input) // This is for when macro sets are eventualy datumized /datum/controller/subsystem/input/proc/setup_default_macro_sets() var/list/static/default_macro_sets - + if(default_macro_sets) macro_sets = default_macro_sets return diff --git a/code/controllers/subsystem/jobs.dm b/code/controllers/subsystem/jobs.dm index 6f7894ca428..1d6fd410f9b 100644 --- a/code/controllers/subsystem/jobs.dm +++ b/code/controllers/subsystem/jobs.dm @@ -3,6 +3,7 @@ SUBSYSTEM_DEF(jobs) init_order = INIT_ORDER_JOBS // 12 wait = 3000 // 5 minutes (Deciseconds) runlevels = RUNLEVEL_GAME + offline_implications = "Job playtime hours will no longer be logged. No immediate action is needed." //List of all jobs var/list/occupations = list() diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm index 7441d855f22..3fc92a3346a 100644 --- a/code/controllers/subsystem/lighting.dm +++ b/code/controllers/subsystem/lighting.dm @@ -7,6 +7,7 @@ SUBSYSTEM_DEF(lighting) wait = 2 init_order = INIT_ORDER_LIGHTING flags = SS_TICKER + offline_implications = "Lighting will no longer update. Shuttle call recommended." /datum/controller/subsystem/lighting/stat_entry() ..("L:[GLOB.lighting_update_lights.len]|C:[GLOB.lighting_update_corners.len]|O:[GLOB.lighting_update_objects.len]") diff --git a/code/controllers/subsystem/machinery.dm b/code/controllers/subsystem/machinery.dm index 9a73c1dbabb..7e78e2b9df1 100644 --- a/code/controllers/subsystem/machinery.dm +++ b/code/controllers/subsystem/machinery.dm @@ -6,6 +6,7 @@ SUBSYSTEM_DEF(machines) name = "Machines" init_order = INIT_ORDER_MACHINES flags = SS_KEEP_TIMING + offline_implications = "Machinery will no longer process. Shuttle call recommended." var/list/processing = list() var/list/currentrun = list() diff --git a/code/controllers/subsystem/mobs.dm b/code/controllers/subsystem/mobs.dm index c21b8f0760a..8345822ca80 100644 --- a/code/controllers/subsystem/mobs.dm +++ b/code/controllers/subsystem/mobs.dm @@ -3,6 +3,7 @@ SUBSYSTEM_DEF(mobs) priority = FIRE_PRIORITY_MOBS flags = SS_KEEP_TIMING runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + offline_implications = "Mobs will no longer process. Immediate server restart recommended." var/list/currentrun = list() var/static/list/clients_by_zlevel[][] diff --git a/code/controllers/subsystem/nano_mob_hunter.dm b/code/controllers/subsystem/nano_mob_hunter.dm index a634f091013..9094bf9fe2b 100644 --- a/code/controllers/subsystem/nano_mob_hunter.dm +++ b/code/controllers/subsystem/nano_mob_hunter.dm @@ -2,6 +2,7 @@ SUBSYSTEM_DEF(mob_hunt) name = "Nano-Mob Hunter GO Server" init_order = INIT_ORDER_NANOMOB priority = FIRE_PRIORITY_NANOMOB // Low priority, no need for MC_TICK_CHECK due to extremely low performance impact. + offline_implications = "Nano-Mob Hunter will no longer spawn mobs. No immediate action is needed." var/max_normal_spawns = 15 //change this to adjust the number of normal spawns that can exist at one time. trapped spawns (from traitors) don't count towards this var/list/normal_spawns = list() var/max_trap_spawns = 15 //change this to adjust the number of trap spawns that can exist at one time. traps spawned beyond this point clear the oldest traps diff --git a/code/controllers/subsystem/nanoui.dm b/code/controllers/subsystem/nanoui.dm index c8cbbc62013..ef1b6ee03fe 100644 --- a/code/controllers/subsystem/nanoui.dm +++ b/code/controllers/subsystem/nanoui.dm @@ -4,6 +4,7 @@ SUBSYSTEM_DEF(nanoui) flags = SS_NO_INIT priority = FIRE_PRIORITY_NANOUI runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT + offline_implications = "All NanoUIs will no longer process. Shuttle call recommended." var/list/currentrun = list() var/list/open_uis = list() // A list of open UIs, grouped by src_object and ui_key. diff --git a/code/controllers/subsystem/nightshift.dm b/code/controllers/subsystem/nightshift.dm index e13f49fd1c2..deffcb6bddf 100644 --- a/code/controllers/subsystem/nightshift.dm +++ b/code/controllers/subsystem/nightshift.dm @@ -4,6 +4,7 @@ SUBSYSTEM_DEF(nightshift) priority = FIRE_PRIORITY_NIGHTSHIFT wait = 600 flags = SS_NO_TICK_CHECK + offline_implications = "The game will no longer shift between day and night lighting. No immediate action is needed." var/nightshift_active = FALSE var/nightshift_start_time = 702000 //7:30 PM, station time diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm index 5eaca5d19c4..79541c199a4 100644 --- a/code/controllers/subsystem/npcpool.dm +++ b/code/controllers/subsystem/npcpool.dm @@ -3,6 +3,7 @@ SUBSYSTEM_DEF(npcpool) flags = SS_POST_FIRE_TIMING|SS_NO_INIT|SS_BACKGROUND priority = FIRE_PRIORITY_NPC runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + offline_implications = "Simple animals will no longer process. Shuttle call recommended." var/list/currentrun = list() diff --git a/code/controllers/subsystem/overlays.dm b/code/controllers/subsystem/overlays.dm index c35f1adee65..95b9e925b5d 100644 --- a/code/controllers/subsystem/overlays.dm +++ b/code/controllers/subsystem/overlays.dm @@ -4,6 +4,7 @@ SUBSYSTEM_DEF(overlays) wait = 1 priority = FIRE_PRIORITY_OVERLAYS init_order = INIT_ORDER_OVERLAY + offline_implications = "Overlays may look strange. No immediate action is needed." var/list/queue var/list/stats diff --git a/code/controllers/subsystem/parallax.dm b/code/controllers/subsystem/parallax.dm index 039b6d2b008..9135f62b03f 100644 --- a/code/controllers/subsystem/parallax.dm +++ b/code/controllers/subsystem/parallax.dm @@ -4,6 +4,7 @@ SUBSYSTEM_DEF(parallax) flags = SS_POST_FIRE_TIMING | SS_BACKGROUND priority = FIRE_PRIORITY_PARALLAX runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT + offline_implications = "Space parallax will no longer move around. No immediate action is needed." var/list/currentrun var/planet_x_offset = 128 var/planet_y_offset = 128 diff --git a/code/controllers/subsystem/shuttles.dm b/code/controllers/subsystem/shuttles.dm index 14a9b507977..247d71d05b8 100644 --- a/code/controllers/subsystem/shuttles.dm +++ b/code/controllers/subsystem/shuttles.dm @@ -6,6 +6,7 @@ SUBSYSTEM_DEF(shuttle) init_order = INIT_ORDER_SHUTTLE flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK runlevels = RUNLEVEL_SETUP | RUNLEVEL_GAME + offline_implications = "Shuttles will no longer function and cargo will not generate points. Immediate server restart recommended." var/list/mobile = list() var/list/stationary = list() var/list/transit = list() diff --git a/code/controllers/subsystem/spacedrift.dm b/code/controllers/subsystem/spacedrift.dm index fcc62a2fa50..d9c46f9c9d7 100644 --- a/code/controllers/subsystem/spacedrift.dm +++ b/code/controllers/subsystem/spacedrift.dm @@ -4,6 +4,7 @@ SUBSYSTEM_DEF(spacedrift) wait = 5 flags = SS_NO_INIT|SS_KEEP_TIMING runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + offline_implications = "Mobs will no longer respect a lack of gravity. No immediate action is needed." var/list/currentrun = list() var/list/processing = list() diff --git a/code/controllers/subsystem/sun.dm b/code/controllers/subsystem/sun.dm index b9843c57b68..3f8e15df05a 100644 --- a/code/controllers/subsystem/sun.dm +++ b/code/controllers/subsystem/sun.dm @@ -3,6 +3,7 @@ SUBSYSTEM_DEF(sun) wait = 600 flags = SS_NO_TICK_CHECK init_order = INIT_ORDER_SUN + offline_implications = "Solar panels will no longer rotate. No immediate action is needed." var/angle var/dx var/dy diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index 74dbf4c4d93..04ddf40f442 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -7,6 +7,7 @@ SUBSYSTEM_DEF(throwing) wait = 1 flags = SS_NO_INIT|SS_KEEP_TIMING|SS_TICKER runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + offline_implications = "Thrown objects may not react properly. Shuttle call recommended." var/list/currentrun var/list/processing = list() diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index bbc73cfed14..825eab93a31 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -5,6 +5,7 @@ SUBSYSTEM_DEF(ticker) priority = FIRE_PRIORITY_TICKER flags = SS_KEEP_TIMING runlevels = RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME + offline_implications = "The game is no longer aware of when the round ends. Immediate server restart recommended." var/round_start_time = 0 var/const/restart_timeout = 600 @@ -97,7 +98,7 @@ SUBSYSTEM_DEF(ticker) mode.check_finished() // some modes contain var-changing code in here, so call even if we don't uses result else game_finished |= mode.check_finished() - if(game_finished) + if(game_finished || force_ending) current_state = GAME_STATE_FINISHED if(GAME_STATE_FINISHED) current_state = GAME_STATE_FINISHED @@ -309,15 +310,12 @@ SUBSYSTEM_DEF(ticker) cinematic.mouse_opacity = MOUSE_OPACITY_TRANSPARENT cinematic.screen_loc = "1,0" - var/obj/structure/bed/temp_buckle = new(src) if(station_missed) for(var/mob/M in GLOB.mob_list) - M.buckled = temp_buckle //buckles the mob so it can't do anything if(M.client) M.client.screen += cinematic //show every client the cinematic else //nuke kills everyone on z-level 1 to prevent "hurr-durr I survived" for(var/mob/M in GLOB.mob_list) - M.buckled = temp_buckle if(M.stat != DEAD) var/turf/T = get_turf(M) if(T && is_station_level(T.z) && !istype(M.loc, /obj/structure/closet/secure_closet/freezer)) @@ -387,8 +385,6 @@ SUBSYSTEM_DEF(ticker) //Otherwise if its a verb it will continue on afterwards. spawn(300) QDEL_NULL(cinematic) //end the cinematic - if(temp_buckle) - qdel(temp_buckle) //release everybody @@ -518,6 +514,11 @@ SUBSYSTEM_DEF(ticker) //Ask the event manager to print round end information SSevents.RoundEnd() + //make big obvious note in game logs that round ended + log_game("///////////////////////////////////////////////////////") + log_game("///////////////////// ROUND ENDED /////////////////////") + log_game("///////////////////////////////////////////////////////") + // Add AntagHUD to everyone, see who was really evil the whole time! for(var/datum/atom_hud/antag/H in GLOB.huds) for(var/m in GLOB.player_list) diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index 1caa3d7819a..7bb6a496274 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -9,6 +9,7 @@ SUBSYSTEM_DEF(timer) init_order = INIT_ORDER_TIMER flags = SS_TICKER|SS_NO_INIT + offline_implications = "The game will no longer process timers. Immediate server restart recommended." var/list/second_queue = list() //awe, yes, you've had first queue, but what about second queue? var/list/hashes = list() diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 28456c9b5c5..b0110258da7 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -3,6 +3,7 @@ SUBSYSTEM_DEF(vote) wait = 10 flags = SS_KEEP_TIMING|SS_NO_INIT runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT + offline_implications = "Votes (Endround shuttle) will no longer function. Shuttle call recommended." var/initiator = null var/started_time = null diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm index ac2f0c59313..7b08bd3ca48 100644 --- a/code/controllers/subsystem/weather.dm +++ b/code/controllers/subsystem/weather.dm @@ -9,6 +9,7 @@ SUBSYSTEM_DEF(weather) flags = SS_BACKGROUND wait = 10 runlevels = RUNLEVEL_GAME + offline_implications = "Ash storms will no longer trigger. No immediate action is needed." var/list/processing = list() var/list/eligible_zlevels = list() var/list/next_hit_by_zlevel = list() //Used by barometers to know when the next storm is coming diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm index 0a14b0e9476..8e1a9d8bcce 100644 --- a/code/datums/ai_laws.dm +++ b/code/datums/ai_laws.dm @@ -62,15 +62,15 @@ if(sorted_laws.len) return - for(var/ion_law in ion_laws) - sorted_laws += ion_law - - for(var/evil_law in devil_laws) - sorted_laws += evil_law - if(zeroth_law) sorted_laws += zeroth_law + for(var/ion_law in ion_laws) + sorted_laws += ion_law + + for(var/evil_law in devil_laws) + sorted_laws += evil_law + var/index = 1 for(var/datum/ai_law/inherent_law in inherent_laws) inherent_law.index = index++ @@ -133,12 +133,12 @@ for(var/datum/ai_law/AL in devil_laws) if(AL.law == law) return - + var/new_law = new/datum/ai_law/sixsixsix(law) devil_laws += new_law if(state_devil.len < devil_laws.len) state_devil += 1 - + sorted_laws.Cut() /datum/ai_laws/proc/add_ion_law(var/law) @@ -209,9 +209,9 @@ /datum/ai_law/ion/delete_law(var/datum/ai_laws/laws) laws.internal_delete_law(laws.ion_laws, laws.state_ion, src) - + /datum/ai_law/sixsixsix/delete_law(var/datum/ai_laws/laws) - laws.internal_delete_law(laws.devil_laws, laws.state_devil, src) + laws.internal_delete_law(laws.devil_laws, laws.state_devil, src) /datum/ai_law/inherent/delete_law(var/datum/ai_laws/laws) laws.internal_delete_law(laws.inherent_laws, laws.state_inherent, src) diff --git a/code/datums/diseases/advance/symptoms/sensory.dm b/code/datums/diseases/advance/symptoms/sensory.dm index cf39d91a866..5759ab32de6 100644 --- a/code/datums/diseases/advance/symptoms/sensory.dm +++ b/code/datums/diseases/advance/symptoms/sensory.dm @@ -62,4 +62,4 @@ Bonus M.reagents.add_reagent("oculine", 20) else if(prob(SYMPTOM_ACTIVATION_PROB * 5)) - to_chat(M, "[pick("Your eyes feel great.","You feel like your eyes can focus more clearly.", "You don't feel the need to blink.","Your ears feel great.","Your healing feels more acute.")]") + to_chat(M, "[pick("Your eyes feel great.","You feel like your eyes can focus more clearly.", "You don't feel the need to blink.","Your ears feel great.","Your hearing feels more acute.")]") diff --git a/code/datums/diseases/critical.dm b/code/datums/diseases/critical.dm index 8dc910e3baf..3afb48ce534 100644 --- a/code/datums/diseases/critical.dm +++ b/code/datums/diseases/critical.dm @@ -199,4 +199,4 @@ affected_mob.emote("collapse") if(prob(12)) to_chat(affected_mob, "You feel [pick("tired", "exhausted", "sluggish")].") - affected_mob.Slowed(rand(4, 16)) \ No newline at end of file + affected_mob.Slowed(rand(4, 16)) diff --git a/code/datums/gas_mixture.dm b/code/datums/gas_mixture.dm index 35cc970aa67..63b70b512ee 100644 --- a/code/datums/gas_mixture.dm +++ b/code/datums/gas_mixture.dm @@ -645,7 +645,7 @@ What are the archived variables for? ((nitrogen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen) || (nitrogen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen))) return 0 if((abs(carbon_dioxide-sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \ - ((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide))) + ((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (carbon_dioxide > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide))) return 0 if((abs(toxins-sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \ ((toxins < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins) || (toxins > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins))) diff --git a/code/datums/log_viewer.dm b/code/datums/log_viewer.dm index 460cd47100f..72872e93a3c 100644 --- a/code/datums/log_viewer.dm +++ b/code/datums/log_viewer.dm @@ -120,6 +120,9 @@ dat += "Mobs being used:" for(var/i in selected_mobs) var/mob/M = i + if(QDELETED(M)) + selected_mobs -= i + continue dat += "[get_display_name(M)]" dat += "Add Mob" dat += "Add Mob (by ckey)" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index add68cd51a7..2a3a32d8119 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -63,8 +63,6 @@ var/datum/mind/soulOwner //who owns the soul. Under normal circumstances, this will point to src var/hasSoul = TRUE - var/rev_cooldown = 0 - var/isholy = FALSE // is this person a chaplain or admin role allowed to use bibles var/isblessed = FALSE // is this person blessed by a chaplain? var/num_blessed = 0 // for prayers diff --git a/code/datums/outfits/plasmamen.dm b/code/datums/outfits/plasmamen.dm index 376bf2af90c..94206c0ae3a 100644 --- a/code/datums/outfits/plasmamen.dm +++ b/code/datums/outfits/plasmamen.dm @@ -176,3 +176,9 @@ head = /obj/item/clothing/head/helmet/space/plasmaman/blueshield uniform = /obj/item/clothing/under/plasmaman/blueshield + +/datum/outfit/plasmaman/wizard + name = "Wizard Plasmaman" + + head = /obj/item/clothing/head/helmet/space/plasmaman/wizard + uniform = /obj/item/clothing/under/plasmaman/wizard diff --git a/code/datums/spells/area_teleport.dm b/code/datums/spells/area_teleport.dm index 8a3585febc0..0d24a984014 100644 --- a/code/datums/spells/area_teleport.dm +++ b/code/datums/spells/area_teleport.dm @@ -79,6 +79,8 @@ target.forceMove(pick(L)) playsound(get_turf(user), sound2, 50,1) + user.update_action_buttons_icon() //Update action buttons as some spells might now be castable + return /obj/effect/proc_holder/spell/targeted/area_teleport/invocation(area/chosenarea = null) diff --git a/code/datums/spells/lichdom.dm b/code/datums/spells/lichdom.dm index 94ad0960e17..9175fd677fb 100644 --- a/code/datums/spells/lichdom.dm +++ b/code/datums/spells/lichdom.dm @@ -28,7 +28,7 @@ config.continuous_rounds = 0 return ..() -/obj/effect/proc_holder/spell/targeted/lichdom/cast(list/targets,mob/user = usr) +/obj/effect/proc_holder/spell/targeted/lichdom/cast(list/targets, mob/user = usr) if(!config.continuous_rounds) existence_stops_round_end = 1 config.continuous_rounds = 1 @@ -36,7 +36,7 @@ for(var/mob/M in targets) var/list/hand_items = list() if(iscarbon(M)) - hand_items = list(M.get_active_hand(),M.get_inactive_hand()) + hand_items = list(M.get_active_hand(), M.get_inactive_hand()) if(marked_item && !stat_allowed) //sanity, shouldn't happen without badminry marked_item = null @@ -74,12 +74,9 @@ var/mob/old_body = current_body var/turf/body_turf = get_turf(old_body) current_body = lich - lich.Weaken(10+10*resurrections) + lich.Weaken(10 + 10 * resurrections) ++resurrections - lich.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(lich), slot_shoes) - lich.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(lich), slot_w_uniform) - lich.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/black(lich), slot_wear_suit) - lich.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/black(lich), slot_head) + equip_lich(lich) if(old_body && old_body.loc) if(iscarbon(old_body)) @@ -127,7 +124,10 @@ H.unEquip(H.head) H.unEquip(H.shoes) H.unEquip(H.head) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/black(H), slot_wear_suit) - H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/black(H), slot_head) - H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H), slot_shoes) - H.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(H), slot_w_uniform) + equip_lich(H) + +/obj/effect/proc_holder/spell/targeted/lichdom/proc/equip_lich(mob/living/carbon/human/H) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/black(H), slot_wear_suit) + H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/black(H), slot_head) + H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H), slot_shoes) + H.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(H), slot_w_uniform) diff --git a/code/datums/spells/mime.dm b/code/datums/spells/mime.dm index d0c052649d9..11b0a75b275 100644 --- a/code/datums/spells/mime.dm +++ b/code/datums/spells/mime.dm @@ -165,4 +165,4 @@ /obj/item/spellbook/oneuse/mime/greaterwall spell = /obj/effect/proc_holder/spell/targeted/forcewall/mime spellname = "Invisible Greater Wall" - desc = "It contains illustrations of the great walls of human history." \ No newline at end of file + desc = "It contains illustrations of the great walls of human history." diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm index 896f4f999a9..74abf104465 100644 --- a/code/datums/status_effects/status_effect.dm +++ b/code/datums/status_effects/status_effect.dm @@ -41,6 +41,9 @@ LAZYREMOVE(owner.status_effects, src) on_remove() owner = null + if(linked_alert) + linked_alert.attached_effect = null + linked_alert = null return ..() /datum/status_effect/process() @@ -85,6 +88,13 @@ desc = "You don't feel any different..." var/datum/status_effect/attached_effect +/obj/screen/alert/status_effect/Destroy() + if(attached_effect) + attached_effect.linked_alert = null + attached_effect = null + return ..() + + ////////////////// // HELPER PROCS // ////////////////// diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index 91e68da427b..15c6f3fb2c0 100644 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -1204,7 +1204,7 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY containername = "hydroponics crate" announce_beacons = list("Hydroponics" = list("Hydroponics")) -/datum/supply_packs/misc/hydroponics/hydrotank +/datum/supply_packs/organic/hydroponics/hydrotank name = "Hydroponics Watertank Crate" contains = list(/obj/item/watertank) cost = 10 diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm index 2ca607921ff..8f65ac634f4 100644 --- a/code/game/area/ai_monitored.dm +++ b/code/game/area/ai_monitored.dm @@ -3,16 +3,14 @@ var/obj/machinery/camera/motioncamera = null -/area/ai_monitored/New() - ..() +/area/ai_monitored/LateInitialize() + . = ..() // locate and store the motioncamera - spawn (20) // spawn on a delay to let turfs/objs load - for(var/obj/machinery/camera/M in src) - if(M.isMotion()) - motioncamera = M - M.area_motion = src - return - return + for(var/obj/machinery/camera/M in src) + if(M.isMotion()) + motioncamera = M + M.area_motion = src + break /area/ai_monitored/Entered(atom/movable/O) ..() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 6b49962bbac..ac77d3d4553 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1,6 +1,7 @@ /atom/movable layer = 3 appearance_flags = TILE_BOUND + glide_size = 8 // Default, adjusted when mobs move based on their movement delays var/last_move = null var/anchored = 0 var/move_resist = MOVE_RESIST_DEFAULT @@ -131,13 +132,14 @@ /atom/movable/proc/setLoc(var/T, var/teleported=0) loc = T -/atom/movable/Move(atom/newloc, direct = 0) +/atom/movable/Move(atom/newloc, direct = 0, movetime) if(!loc || !newloc) return 0 var/atom/oldloc = loc if(loc != newloc) + glide_for(movetime) if(!(direct & (direct - 1))) //Cardinal move - . = ..() + . = ..(newloc, direct) // don't pass up movetime else //Diagonal move, split it into cardinal moves moving_diagonally = FIRST_DIAG_STEP var/first_step_dir @@ -203,7 +205,7 @@ src.move_speed = world.time - src.l_move_time src.l_move_time = world.time - if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc, direct)) //movement failed due to buckled mob + if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc, direct, movetime)) //movement failed due to buckled mob . = 0 // Called after a successful Move(). By this point, we've already moved @@ -216,6 +218,15 @@ update_parallax_contents() return TRUE +// Change glide size for the duration of one movement +/atom/movable/proc/glide_for(movetime) + if(movetime) + glide_size = world.icon_size/max(DS2TICKS(movetime), 1) + spawn(movetime) + glide_size = initial(glide_size) + else + glide_size = initial(glide_size) + // Previously known as HasEntered() // This is automatically called when something enters your square /atom/movable/Crossed(atom/movable/AM, oldloc) @@ -428,10 +439,10 @@ /atom/movable/proc/water_act(volume, temperature, source, method = REAGENT_TOUCH) //amount of water acting : temperature of water in kelvin : object that called it (for shennagins) return TRUE -/atom/movable/proc/handle_buckled_mob_movement(newloc,direct) +/atom/movable/proc/handle_buckled_mob_movement(newloc,direct,movetime) for(var/m in buckled_mobs) var/mob/living/buckled_mob = m - if(!buckled_mob.Move(newloc, direct)) + if(!buckled_mob.Move(newloc, direct, movetime)) forceMove(buckled_mob.loc) last_move = buckled_mob.last_move inertia_dir = last_move diff --git a/code/game/gamemodes/changeling/powers/hivemind.dm b/code/game/gamemodes/changeling/powers/hivemind.dm index af375cad368..98336608da4 100644 --- a/code/game/gamemodes/changeling/powers/hivemind.dm +++ b/code/game/gamemodes/changeling/powers/hivemind.dm @@ -23,7 +23,7 @@ return // HIVE MIND UPLOAD/DOWNLOAD DNA -var/list/datum/dna/hivemind_bank = list() +GLOBAL_LIST_EMPTY(hivemind_bank) /datum/action/changeling/hivemind_upload name = "Hive Channel DNA" @@ -36,7 +36,7 @@ var/list/datum/dna/hivemind_bank = list() var/datum/changeling/changeling = user.mind.changeling var/list/names = list() for(var/datum/dna/DNA in (changeling.absorbed_dna+changeling.protected_dna)) - if(!(DNA in hivemind_bank)) + if(!(DNA in GLOB.hivemind_bank)) names += DNA.real_name if(names.len <= 0) @@ -51,7 +51,7 @@ var/list/datum/dna/hivemind_bank = list() if(!chosen_dna) return - hivemind_bank += chosen_dna + GLOB.hivemind_bank += chosen_dna to_chat(user, "We channel the DNA of [chosen_name] to the air.") feedback_add_details("changeling_powers","HU") return 1 @@ -75,7 +75,7 @@ var/list/datum/dna/hivemind_bank = list() /datum/action/changeling/hivemind_download/sting_action(var/mob/user) var/datum/changeling/changeling = user.mind.changeling var/list/names = list() - for(var/datum/dna/DNA in hivemind_bank) + for(var/datum/dna/DNA in GLOB.hivemind_bank) if(!(DNA in changeling.absorbed_dna)) names[DNA.real_name] = DNA diff --git a/code/game/gamemodes/cult/cult_objectives.dm b/code/game/gamemodes/cult/cult_objectives.dm index 80b889a5bfb..f1a188022a0 100644 --- a/code/game/gamemodes/cult/cult_objectives.dm +++ b/code/game/gamemodes/cult/cult_objectives.dm @@ -155,12 +155,12 @@ /datum/game_mode/cult/proc/get_possible_sac_targets() var/list/possible_sac_targets = list() for(var/mob/living/carbon/human/player in GLOB.player_list) - if(player.mind && !is_convertable_to_cult(player.mind) && (player.stat != DEAD)) + if(player.mind && !is_convertable_to_cult(player.mind) && (player.stat != DEAD) && (!player.mind.offstation_role) ) possible_sac_targets += player.mind if(!possible_sac_targets.len) //There are no living Unconvertables on the station. Looking for a Sacrifice Target among the ordinary crewmembers for(var/mob/living/carbon/human/player in GLOB.player_list) - if(is_secure_level(player.z)) //We can't sacrifice people that are on the centcom z-level + if(is_secure_level(player.z) || player.mind.offstation_role) //We can't sacrifice people that are on the centcom z-level or offstation roles continue if(player.mind && !(player.mind in cult) && (player.stat != DEAD))//make DAMN sure they are not dead possible_sac_targets += player.mind diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 70b18377559..8c83c88f3d0 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -332,10 +332,12 @@ GLOBAL_LIST_EMPTY(teleport_runes) user.forceMove(get_turf(actual_selected_rune)) var/mob/living/carbon/human/H = user if(user.z != T.z) - H.bleed(5) + if(istype(H)) + H.bleed(5) user.apply_damage(5, BRUTE) else - H.bleed(rand(5,10)) + if(istype(H)) + H.bleed(rand(5,10)) else fail_invoke() @@ -832,7 +834,8 @@ GLOBAL_LIST_EMPTY(teleport_runes) fail_invoke() log_game("Summon Cultist rune failed - target in away mission") return - if((cultist_to_summon.reagents.has_reagent("holywater") || cultist_to_summon.restrained()) && invokers.len < 3) + var/hard_summon = (cultist_to_summon.reagents && cultist_to_summon.reagents.has_reagent("holywater")) || cultist_to_summon.restrained() + if(hard_summon && invokers.len < 3) to_chat(user, "The summoning of [cultist_to_summon] is being blocked somehow! You need 3 chanters to counter it!") fail_invoke() new /obj/effect/temp_visual/cult/sparks(get_turf(cultist_to_summon)) //observer warning @@ -840,7 +843,7 @@ GLOBAL_LIST_EMPTY(teleport_runes) return ..() - if(cultist_to_summon.reagents.has_reagent("holywater") || cultist_to_summon.restrained()) + if(hard_summon) summontime = 20 if(do_after(user, summontime, target = loc)) diff --git a/code/game/gamemodes/devil/devil.dm b/code/game/gamemodes/devil/devil.dm index ab5f5796d2e..06933891ba6 100644 --- a/code/game/gamemodes/devil/devil.dm +++ b/code/game/gamemodes/devil/devil.dm @@ -1,4 +1,4 @@ -var/global/list/whiteness = list ( +GLOBAL_LIST_INIT(whiteness, list( /obj/item/clothing/under/color/white = 2, /obj/item/clothing/under/rank/bartender = 1, /obj/item/clothing/under/rank/chef = 1, @@ -21,7 +21,7 @@ var/global/list/whiteness = list ( /obj/item/clothing/under/noble_clothes = 1, /obj/item/clothing/under/sl_suit = 1, /obj/item/clothing/under/burial = 1 -) +)) @@ -32,9 +32,9 @@ var/global/list/whiteness = list ( var/mob/living/carbon/human/H = attacker if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under)) var/obj/item/clothing/under/U = H.w_uniform - if(whiteness[U.type]) + if(GLOB.whiteness[U.type]) src.visible_message("[src] seems to have been harmed by the purity of [attacker]'s clothes.", "Unsullied white clothing is disrupting your form.") - return whiteness[U.type] + 1 + return GLOB.whiteness[U.type] + 1 if(BANE_TOOLBOX) if(istype(weapon,/obj/item/storage/toolbox)) src.visible_message("The [weapon] seems unusually robust this time.", "The [weapon] is your unmaking!") diff --git a/code/game/gamemodes/miniantags/abduction/abduction.dm b/code/game/gamemodes/miniantags/abduction/abduction.dm index 1888d0e4a1d..60de5ba4238 100644 --- a/code/game/gamemodes/miniantags/abduction/abduction.dm +++ b/code/game/gamemodes/miniantags/abduction/abduction.dm @@ -282,4 +282,4 @@ /datum/game_mode/proc/update_abductor_icons_removed(datum/mind/alien_mind) var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_ABDUCTOR] hud.leave_hud(alien_mind.current) - set_antag_hud(alien_mind.current, null) \ No newline at end of file + set_antag_hud(alien_mind.current, null) diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm index 65424bf9008..f425a34654d 100644 --- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm +++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm @@ -421,13 +421,13 @@ return FALSE /obj/structure/lattice/catwalk/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) - . = ..() var/turf/here = get_turf(src) for(var/A in here.contents) var/obj/structure/cable/C = A if(istype(C)) to_chat(S, "Disrupting the power grid would bring no benefit to us. Aborting.") return FALSE + return ..() /obj/item/deactivated_swarmer/IntegrateAmount() return 50 diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer_event.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer_event.dm index d0be68819ae..fbceda6bd94 100644 --- a/code/game/gamemodes/miniantags/bot_swarm/swarmer_event.dm +++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer_event.dm @@ -13,9 +13,9 @@ /datum/event/spawn_swarmer/start() if(find_swarmer()) return 0 - if(!the_gateway) + if(!GLOB.the_gateway) return 0 - new /obj/effect/mob_spawn/swarmer(get_turf(the_gateway)) + new /obj/effect/mob_spawn/swarmer(get_turf(GLOB.the_gateway)) /datum/event/spawn_swarmer/proc/find_swarmer() diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm index 387cd03aceb..126587a0c97 100644 --- a/code/game/gamemodes/miniantags/guardian/guardian.dm +++ b/code/game/gamemodes/miniantags/guardian/guardian.dm @@ -296,11 +296,12 @@ if(used == TRUE) to_chat(user, "[used_message]") return + used = TRUE // Set this BEFORE the popup to prevent people using the injector more than once, polling ghosts multiple times, and receiving multiple guardians. var/choice = alert(user, "[confirmation_message]",, "Yes", "No") if(choice == "No") to_chat(user, "You decide against using the [name].") + used = FALSE return - used = TRUE to_chat(user, "[use_message]") var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the [mob_name] of [user.real_name]?", ROLE_GUARDIAN, 0, 100) var/mob/dead/observer/theghost = null diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 9974ee8305a..de15f62d09d 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -231,7 +231,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective) return 0 /datum/objective/block - explanation_text = "Do not allow any lifeforms, be it organic or synthetic to escape on the shuttle alive. AIs, Cyborgs, and pAIs are not considered alive." + explanation_text = "Do not allow any lifeforms, be it organic or synthetic to escape on the shuttle alive. AIs, Cyborgs, Maintenance drones, and pAIs are not considered alive." martyr_compatible = 1 /datum/objective/block/check_completion() @@ -243,15 +243,14 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective) return 0 var/area/A = SSshuttle.emergency.areaInstance - var/list/protected_mobs = list(/mob/living/silicon/ai, /mob/living/silicon/pai, /mob/living/silicon/robot) for(var/mob/living/player in GLOB.player_list) - if(player.type in protected_mobs) - continue + if(issilicon(player)) + continue // If they're silicon, they're not considered alive, skip them. if(player.mind && player.stat != DEAD) if(get_area(player) == A) - return 0 + return 0 // If there are any other organic mobs on the shuttle, you failed the objective. return 1 diff --git a/code/game/gamemodes/steal_items.dm b/code/game/gamemodes/steal_items.dm index de9f8fc0eb7..78a05f904a8 100644 --- a/code/game/gamemodes/steal_items.dm +++ b/code/game/gamemodes/steal_items.dm @@ -76,12 +76,12 @@ datum/theft_objective/ai/check_special_completion(var/obj/item/aicard/C) /datum/theft_objective/blueprints name = "the station blueprints" - typepath = /obj/item/areaeditor/blueprints + typepath = /obj/item/areaeditor/blueprints/ce protected_jobs = list("Chief Engineer") altitems = list(/obj/item/photo) /datum/objective_item/steal/blueprints/check_special_completion(obj/item/I) - if(istype(I, /obj/item/areaeditor/blueprints)) + if(istype(I, /obj/item/areaeditor/blueprints/ce)) return 1 if(istype(I, /obj/item/photo)) var/obj/item/photo/P = I diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm index 3dbd9211399..82f6d833d16 100644 --- a/code/game/gamemodes/wizard/rightandwrong.dm +++ b/code/game/gamemodes/wizard/rightandwrong.dm @@ -168,4 +168,4 @@ GLOBAL_VAR_INIT(summon_magic_triggered, FALSE) if(summon_type == SUMMON_MAGIC) give_magic(H) else - give_guns(H) \ No newline at end of file + give_guns(H) diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index 863ce6405cc..a7eb5d135e9 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -6,34 +6,36 @@ var/category = "Offensive" var/log_name = "XX" //What it shows up as in logs var/cost = 2 - var/refundable = 1 + var/refundable = TRUE var/surplus = -1 // -1 for infinite, not used by anything atm var/obj/effect/proc_holder/spell/S = null //Since spellbooks can be used by only one person anyway we can track the actual spell var/buy_word = "Learn" var/limit //used to prevent a spellbook_entry from being bought more than X times with one wizard spellbook /datum/spellbook_entry/proc/IsSpellAvailable() // For config prefs / gamemode restrictions - these are round applied - return 1 + return TRUE /datum/spellbook_entry/proc/CanBuy(mob/living/carbon/human/user, obj/item/spellbook/book) // Specific circumstances - if(book.uses= aspell.level_max) to_chat(user, "This spell cannot be improved further.") - return 0 + return FALSE else aspell.name = initial(aspell.name) aspell.spell_level++ - aspell.charge_max = round(initial(aspell.charge_max) - aspell.spell_level * (initial(aspell.charge_max) - aspell.cooldown_min)/ aspell.level_max) + aspell.charge_max = round(initial(aspell.charge_max) - aspell.spell_level * (initial(aspell.charge_max) - aspell.cooldown_min) / aspell.level_max) if(aspell.charge_max < aspell.charge_counter) aspell.charge_counter = aspell.charge_max switch(aspell.spell_level) @@ -51,37 +53,39 @@ aspell.name = "Instant [aspell.name]" if(aspell.spell_level >= aspell.level_max) to_chat(user, "This spell cannot be strengthened any further.") - return 1 + return TRUE //No same spell found - just learn it - feedback_add_details("wizard_spell_learned",log_name) - user.mind.AddSpell(S) - to_chat(user, "You have learned [S.name].") - return 1 + feedback_add_details("wizard_spell_learned", log_name) + user.mind.AddSpell(newspell) + to_chat(user, "You have learned [newspell.name].") + return TRUE /datum/spellbook_entry/proc/CanRefund(mob/living/carbon/human/user, obj/item/spellbook/book) if(!refundable) - return 0 + return FALSE if(!S) S = new spell_type() for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list) if(initial(S.name) == initial(aspell.name)) - return 1 - return 0 + return TRUE + return FALSE /datum/spellbook_entry/proc/Refund(mob/living/carbon/human/user, obj/item/spellbook/book) //return point value or -1 for failure var/area/wizard_station/A = locate() if(!(user in A.contents)) - to_chat(user, "You can only refund spells at the wizard lair") + to_chat(user, "You can only refund spells at the wizard lair.") return -1 - if(!S) + if(!S) //This happens when the spell's source is from another spellbook, from loadouts, or adminery, this create a new template temporary spell S = new spell_type() var/spell_levels = 0 for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list) if(initial(S.name) == initial(aspell.name)) spell_levels = aspell.spell_level user.mind.spell_list.Remove(aspell) - QDEL_NULL(S) - return cost * (spell_levels+1) + qdel(aspell) + if(S) //If we created a temporary spell above, delete it now. + qdel(S) + return cost * (spell_levels + 1) return -1 /datum/spellbook_entry/proc/GetInfo() @@ -571,6 +575,48 @@ category = "Summons" limit = 1 +//Spell loadouts datum, list of loadouts is in wizloadouts.dm +/datum/spellbook_entry/loadout + name = "Standard Loadout" + cost = 10 + category = "Standard" + refundable = FALSE + buy_word = "Summon" + var/list/items_path = list() + var/list/spells_path = list() + var/destroy_spellbook = FALSE //Destroy the spellbook when bought, for loadouts containing non-standard items/spells, otherwise wiz can refund spells + +/datum/spellbook_entry/loadout/GetInfo() + var/dat = "" + dat += "[name]" + if(cost > 0) + dat += " Cost:[cost]
" + else + dat += " No Cost
" + dat += "[desc]
" + return dat + +/datum/spellbook_entry/loadout/Buy(mob/living/carbon/human/user, obj/item/spellbook/book) + if(destroy_spellbook) + var/response = alert(user, "The [src] loadout cannot be refunded once bought. Are you sure this is what you want?", "No refunds!", "No", "Yes") + if(response == "No") + return FALSE + to_chat(user, "[book] crumbles to ashes as you acquire its knowledge.") + qdel(book) + else if(items_path.len) + var/response = alert(user, "The [src] loadout contains items that will not be refundable if bought. Are you sure this is what you want?", "No refunds!", "No", "Yes") + if(response == "No") + return FALSE + if(items_path.len) + var/obj/item/storage/box/wizard/B = new(src) + for(var/path in items_path) + new path(B) + user.put_in_hands(B) + for(var/path in spells_path) + var/obj/effect/proc_holder/spell/S = new path() + LearnSpell(user, book, S) + return TRUE + /obj/item/spellbook name = "spell book" desc = "The legendary book of spells of the wizard." @@ -587,12 +633,13 @@ var/mob/living/carbon/human/owner var/list/datum/spellbook_entry/entries = list() var/list/categories = list() - var/list/main_categories = list("Spells", "Magical Items") + var/list/main_categories = list("Spells", "Magical Items", "Loadouts") var/list/spell_categories = list("Offensive", "Defensive", "Mobility", "Assistance", "Rituals") var/list/item_categories = list("Artefacts", "Weapons and Armors", "Staves", "Summons") + var/list/loadout_categories = list("Standard", "Unique") /obj/item/spellbook/proc/initialize() - var/entry_types = subtypesof(/datum/spellbook_entry) - /datum/spellbook_entry/item - /datum/spellbook_entry/summon + var/entry_types = subtypesof(/datum/spellbook_entry) - /datum/spellbook_entry/item - /datum/spellbook_entry/summon - /datum/spellbook_entry/loadout for(var/T in entry_types) var/datum/spellbook_entry/E = new T if(E.IsSpellAvailable()) @@ -676,6 +723,12 @@ if("Summons") dat += "Magical items geared towards bringing in outside forces to aid you.

" dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased.
" + if("Standard") + dat += "These battle-tested spell sets are easy to use and provide good balance between offense and defense.

" + dat += "They all cost, and are worth, 10 spell points. You are able to refund any of the spells included as long as you stay in the wizard den.
" + if("Unique") + dat += "These esoteric loadouts usually contain spells or items that cannot be bought elsewhere in this spellbook.

" + dat += "Recommended for experienced wizards looking for something new. No refunds once purchased!
" return dat /obj/item/spellbook/proc/wrap(content) @@ -720,23 +773,24 @@ cat_dat[main_category] = "
" dat += "
  • [main_category]
  • " dat += "" + dat += "