From 7641ff5100382c6e3a565981595a68f3474e59ec Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Fri, 16 Oct 2015 11:03:04 +0200 Subject: [PATCH 01/14] Secures the AI and Cyborg upload console circuits in the ERT staging area. --- maps/exodus-2.dmm | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/maps/exodus-2.dmm b/maps/exodus-2.dmm index 0ad7c5cb128..a1729c1e029 100644 --- a/maps/exodus-2.dmm +++ b/maps/exodus-2.dmm @@ -1086,7 +1086,7 @@ "uT" = (/obj/machinery/door/window/northleft,/turf/unsimulated/floor{icon_state = "carpet"; dir = 2},/area/centcom/control) "uU" = (/obj/effect/landmark{name = "Marauder Exit"},/turf/unsimulated/floor{name = "plating"},/area/centcom/specops) "uV" = (/turf/unsimulated/floor{name = "plating"},/area/centcom/specops) -"uW" = (/obj/machinery/door/blast/regular{icon_state = "pdoor1"; id = "CREED"; name = "Ready Room"; p_open = 0},/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) +"uW" = (/obj/machinery/door/blast/regular{id = "ert_synth_equipment"; name = "Synthetics Modification Equipment"},/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) "uX" = (/turf/unsimulated/floor{icon_state = "warnplate"; dir = 8},/area/centcom/specops) "uY" = (/turf/unsimulated/floor{icon_state = "warnplate"; dir = 4},/area/centcom/specops) "uZ" = (/obj/machinery/mass_driver{dir = 8; id = "ASSAULT3"; name = "gravpult"},/turf/unsimulated/floor{icon_state = "bot"},/area/centcom/specops) @@ -1128,7 +1128,7 @@ "vJ" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/unsimulated/floor{name = "plating"},/area/centcom/control) "vK" = (/obj/machinery/vending/tool,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom/specops) "vL" = (/obj/structure/sign/poster{poster_type = "/datum/poster/bay_50"; pixel_x = -32},/turf/simulated/shuttle/floor{icon_state = "floor6"},/area/syndicate_station/start) -"vM" = (/obj/structure/table/woodentable{dir = 10},/obj/machinery/button/remote/blast_door{id = "CREED"; name = "Spec Ops Ready Room"; pixel_y = 4; req_access = list(108)},/obj/machinery/button/remote/blast_door{icon_state = "doorctrl0"; id = "ASSAULT"; name = "Mech Storage"; pixel_y = -4; req_access = list(108)},/turf/unsimulated/floor{icon_state = "grimy"},/area/centcom/creed) +"vM" = (/obj/item/weapon/aiModule/nanotrasen,/obj/item/weapon/aiModule/reset,/obj/item/weapon/aiModule/freeformcore,/obj/item/weapon/aiModule/protectStation,/obj/item/weapon/aiModule/quarantine,/obj/item/weapon/aiModule/paladin,/obj/item/weapon/aiModule/robocop,/obj/item/weapon/aiModule/safeguard,/obj/structure/table/rack,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom/specops) "vN" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{id = "skipjackshutters"; name = "Skipjack Blast Shielding"},/turf/simulated/shuttle/plating,/area/skipjack_station/start) "vO" = (/obj/machinery/door/airlock/centcom{name = "Maintenance Access"; opacity = 1; req_access = list(106)},/turf/unsimulated/floor{icon_state = "dark"},/area/centcom/control) "vP" = (/obj/mecha/combat/gygax/dark,/obj/machinery/camera/network/ert{c_tag = "Assault Armor North"},/turf/unsimulated/floor{icon_state = "delivery"; dir = 6},/area/centcom/specops) @@ -1166,7 +1166,7 @@ "wv" = (/obj/structure/window/reinforced{dir = 4},/turf/unsimulated/floor{icon_state = "floor"},/area/centcom/control) "ww" = (/obj/structure/bed/chair{dir = 1},/turf/unsimulated/floor{icon_state = "carpet"; dir = 2},/area/centcom/control) "wx" = (/obj/mecha/working/ripley/firefighter,/turf/unsimulated/floor{icon_state = "delivery"; dir = 6},/area/centcom/specops) -"wy" = (/obj/item/weapon/circuitboard/aiupload,/obj/item/weapon/circuitboard/borgupload,/obj/item/weapon/circuitboard/smes,/obj/item/weapon/aiModule/nanotrasen,/obj/item/weapon/aiModule/reset,/obj/item/weapon/aiModule/freeformcore,/obj/item/weapon/aiModule/protectStation,/obj/item/weapon/aiModule/quarantine,/obj/item/weapon/aiModule/paladin,/obj/item/weapon/aiModule/robocop,/obj/item/weapon/aiModule/safeguard,/obj/structure/table/steel_reinforced,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom/specops) +"wy" = (/obj/machinery/portable_atmospherics/canister/air,/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) "wz" = (/obj/machinery/door/airlock/centcom{name = "Maintenance Access"; opacity = 1; req_access = list(106)},/turf/unsimulated/floor{icon_state = "delivery"},/area/centcom/control) "wA" = (/obj/structure/sign/securearea,/turf/unsimulated/wall,/area/centcom/control) "wB" = (/obj/machinery/door/airlock/centcom{name = "Teleporter Bay"; opacity = 1; req_access = list(107)},/turf/unsimulated/floor{icon_state = "delivery"},/area/centcom/control) @@ -1940,9 +1940,13 @@ "Lp" = (/obj/item/pizzabox/meat,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/skipjack_station/start) "Lq" = (/obj/structure/bed,/obj/item/weapon/bedsheet/rd,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/skipjack_station/start) "Lr" = (/obj/structure/bed,/obj/item/weapon/bedsheet/clown,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/skipjack_station/start) +"Ls" = (/obj/structure/table/rack,/obj/item/weapon/circuitboard/borgupload,/obj/item/weapon/circuitboard/aiupload{pixel_x = -3; pixel_y = -3},/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) +"Lt" = (/obj/structure/table/woodentable{dir = 10},/obj/machinery/button/remote/blast_door{id = "CREED"; name = "Spec Ops Ready Room"; pixel_x = -5; pixel_y = 4; req_access = list(108)},/obj/machinery/button/remote/blast_door{icon_state = "doorctrl0"; id = "ASSAULT"; name = "Mech Storage"; pixel_x = -5; pixel_y = -4; req_access = list(108)},/obj/machinery/button/remote/blast_door{id = "ert_synth_equipment"; name = "Synth Modification Equipment"; pixel_x = 5; pixel_y = -4; req_access = list(108)},/turf/unsimulated/floor{icon_state = "grimy"},/area/centcom/creed) "Lu" = (/turf/unsimulated/floor{tag = "icon-ironsand7"; icon_state = "ironsand7"},/turf/unsimulated/floor{tag = "icon-asteroid7"; name = "plating"; icon_state = "asteroid7"},/area/wizard_station) "Lv" = (/turf/unsimulated/floor{tag = "icon-ironsand12"; icon_state = "ironsand12"},/turf/unsimulated/floor{tag = "icon-asteroid2"; name = "plating"; icon_state = "asteroid2"},/area/wizard_station) +"Lw" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/circuitboard/smes,/obj/item/weapon/circuitboard/smes,/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) "Lx" = (/obj/structure/sign/nosmoking_2{pixel_x = 32},/turf/simulated/shuttle/floor{icon_state = "floor6"},/area/syndicate_station/start) +"Ly" = (/obj/machinery/door/airlock/centcom{name = "Special Operations"; opacity = 1; req_access = list(103)},/obj/machinery/door/blast/regular{icon_state = "pdoor1"; id = "CREED"; name = "Ready Room"; p_open = 0},/turf/unsimulated/floor{icon_state = "delivery"},/area/centcom/specops) "Lz" = (/turf/simulated/floor/holofloor{icon_state = "carpet7-3"; dir = 4},/area/holodeck/source_theatre) "LA" = (/turf/simulated/floor/holofloor/grass,/turf/simulated/floor/holofloor{icon_state = "wood_siding1"; dir = 2},/obj/structure/flora/ausbushes/ywflowers,/turf/simulated/floor/holofloor{icon_state = "wood_siding5"; dir = 2},/area/holodeck/source_picnicarea) "LB" = (/turf/simulated/floor/holofloor{icon_state = "carpet11-12"; dir = 4},/area/holodeck/source_theatre) @@ -2186,16 +2190,16 @@ aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMjHoUoVoVoVqRpepepepepepepepepepeqHoVoVoVoVpFpFtctdpFpFpFtctetdpFqvqvqvpFtftgtgtgtgtgthpFpZqztitjqYqYqYtktlqAjIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMmumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumumumu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMjHoUoVoVoVoVoVoVoVoVoVoVoVoVoVoVoVoVoVoVoVpFtptptptptptptptptppFpFumpFpFtptptptptptptppFpZqztrtstttttttstuqAjIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumumumu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvyhyhyhyhyhyhyhtptptptxtxtxtxtxtxpFtytztypFtxtxtxtxtxtxtxtxpZqzqztAtBtBtBtCqzqAjIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvuntvupuxuuuzuyuAtvveuhvfvfvkvgvpvpvyvyyhzdyIyIyIyIvzvAvHvAvJtOtPtQtRtSpFtytztypFtTtUtVtWtWtxaMaMpZqzqzqzqzqzqzqzqzqAjIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvtvtvtvtvtvtvAgtvuhuhuhuhuhuhtvvKuhuhuhuhuhuhuhuhuhyhyByIvMyIyIvEurururvOueufufufufpFtytztypFtWtWtWtWtWtxaMaMugugugugugugugugugugugtxtxtxtxtxtxtxtxtxtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutvPvbuvuwvQuhuhuhuhuhuhuhvRtvvSuhuhuhuhuhuhuhuhuhyhyHvTzqyIyIvzvAvHvAvJueufufufufpFvUumwhpFtWtWtWtWtWtxuguguguguguguowjuqtxurururtxururururururururtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVAIuXuVuVuVuYAIuZvavbvbvctvwluhuhuhuhuhuhuhtvwmuhuhuhuhvpwownwpwpyhzrzpzEyIyIyhwqwqwqtvuDuEuFuGuHtxuIuIuItxtWtWtWtWtWtxuJuKuJuLuMuguNuNuNuOurururuOuruPuQuPuruRuSuTtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvvQtvtvtvuhuhuhuhuhuhuhuhtvuhuhuhuhwytvtvtvtvtvyhyhyhyhyhyhyhxQxQxQtvwzwAvlvmvntxufJyuftxvlvmvowAwBtxvqvrvqvrvqugtxtxtxtxurururtxvsvtuPvuvsvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutvIvbvbwEtvvxwPukxowVwXuhuhtvuhuhuhuhwYtvxawZwZxaxcxbxexdxQxQxQxQxQxgtvufufvBvCvCvCvCvCvCvCvCvCvDufufxhvqvqvqvqvqugvFuNuotxurururtxvGvGxkvGvGvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVwWuXuVuVuVuYwWwivavbvbxltvwFwGwGwGwItvuhuhtvuhuhuhuhxmtvuhxQxQxQxnxQxQxQxQxQxQxQxQxptvufJyvVvWvXvXvXvXvXvXvXvYueJyufugvZwawbwcwdugweuNwjtxurururtxwfwfuNwfwfvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMwgaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvuntvupuxuuuzuyuAtvvMuWuhwyvkvgvfvfvyvyyhzdyIyIyIyIvzvAvHvAvJtOtPtQtRtSpFtytztypFtTtUtVtWtWtxaMaMpZqzqzqzqzqzqzqzqzqAjIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvtvtvtvtvtvtvAgtvuhuhuhuhuhuhtvLsuWuhuhuhuhuhuhuhuhyhyByILtyIyIvEurururvOueufufufufpFtytztypFtWtWtWtWtWtxaMaMugugugugugugugugugugugtxtxtxtxtxtxtxtxtxtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutvPvbuvuwvQuhuhuhuhuhuhuhvRtvtvtvuhuhuhuhuhuhuhuhyhyHvTzqyIyIvzvAvHvAvJueufufufufpFvUumwhpFtWtWtWtWtWtxuguguguguguguowjuqtxurururtxururururururururtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVAIuXuVuVuVuYAIuZvavbvbvctvwluhuhuhuhuhuhuhtvveuhuhuhvpvpwownwpwpyhzrzpzEyIyIyhwqwqwqtvuDuEuFuGuHtxuIuIuItxtWtWtWtWtWtxuJuKuJuLuMuguNuNuNuOurururuOuruPuQuPuruRuSuTtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvvQtvtvtvuhuhuhuhuhuhuhuhtvvKuhuhuhLwtvtvtvtvtvyhyhyhyhyhyhyhxQxQxQtvwzwAvlvmvntxufJyuftxvlvmvowAwBtxvqvrvqvrvqugtxtxtxtxurururtxvsvtuPvuvsvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutvIvbvbwEtvvxwPukxowVwXuhuhtvvSuhuhuhwYtvxawZwZxaxcxbxexdxQxQxQxQxQxgtvufufvBvCvCvCvCvCvCvCvCvCvDufufxhvqvqvqvqvqugvFuNuotxurururtxvGvGxkvGvGvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVwWuXuVuVuVuYwWwivavbvbxltvwFwGwGwGwItvuhuhtvwmuhuhuhxmtvuhxQxQxQxnxQxQxQxQxQxQxQxQxptvufJyvVvWvXvXvXvXvXvXvXvYueJyufugvZwawbwcwdugweuNwjtxurururtxwfwfuNwfwfvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMwgaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutwxvbvbxqxcxrxtxsxvxuxcuhuhxcuhuhuhuhxwxcuhxQxQuwxxxQxQxQxexetvtvtvtvtvufufvVwrwsufwtwuwvufwswrueufufugugugugugugugweuNwjtxurururtxwwwwuNwwwwvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVxyuXuVuVuVuYxyxzvavbvbxAxnxHuhuhuhxIxnuhuhxnuhuhxKxJxLxnxMxQxQxQtvwFwGwHwGwItvwJwJwJxNufufwKwLwMwNwOxOwQwRwSwLwTufufxRwUwUwUwUwUtxtxuOtxtxtxuOtxtxuNuNuNuNuNvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutxXvbvbxYtvyauhuhuhuhtvybybtvycyctvtvtvtvxMxQxQuwuWxfxfxfxfxfydxfxfxfydufufufyeufufxiufxiufufyeufufufxjurururururxjurururururururxjwwwwwwwwwwvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMmu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutxXvbvbxYtvyauhuhuhuhtvybybtvycyctvtvtvtvxMxQxQuwyWxfxfxfxfxfydxfxfxfLyufufufyeufufxiufxiufufyeufufufxjurururururxjurururururururxjwwwwwwwwwwvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMmu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVyfuXuVuVuVuYyfygyivbvbuwyjuhuhuhuhuhyjuhuhykuhuhymylyzyzuhxQxQvdtvwFwGwHwGwItvxBxBxByAufufvBxCxDwNxEufxFwRxGxCvDufufxjurururururxjurururururururxjwwwwwwwwwwtxuOuOtxtxtxtxtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvvbvbuwyjuhuhuhuhuhyjuhuhyCuhuhxQyDyDyDxQxQxQzcyKyGyMxQySyQtvtvtvtvtvufufvVwLxSufxiufxikayqwLueufufwAxTxUxUxUxVtxtxxWtxtxtxuOtxtxtxyXyXyXtxtxurururyYurxZtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvvbvbyZtvwFwGwGwGwItvzezetvzfuhxQzgzizhxQxQxQyRzkyMxQxQxQxQxxxQxKzltvufufvVtxtxynyoufypxStxtxueufuftxaMaMaMaMaMtxyrystxuNytuNuNyuyvywywywzmtxururuQuQururyyaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM From 5c40db0fad36224ea6224ed9df95f5798386f28f Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Sat, 17 Oct 2015 20:39:02 +0200 Subject: [PATCH 02/14] Adds antagonism minimum player age. Round-start and mid-round auto-antagonism selection can now exclude players if they have not reached a given minimum age requirement. Can be enabled/disabled by config, is disabled by default. --- code/controllers/configuration.dm | 6 +++++- code/game/antagonist/antagonist.dm | 7 +++++-- config/example/config.txt | 4 ++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 17e45736c05..fc55faac547 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -153,7 +153,8 @@ var/list/gamemode_cache = list() var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt - var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database + var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database + var/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database var/simultaneous_pm_warning_timeout = 100 @@ -268,6 +269,9 @@ var/list/gamemode_cache = list() if ("use_age_restriction_for_jobs") config.use_age_restriction_for_jobs = 1 + if ("use_age_restriction_for_antags") + config.use_age_restriction_for_antags = 1 + if ("jobs_have_minimal_access") config.jobs_have_minimal_access = 1 diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm index 011ae5ebe6c..32f40ad985d 100644 --- a/code/game/antagonist/antagonist.dm +++ b/code/game/antagonist/antagonist.dm @@ -46,6 +46,7 @@ var/mob_path = /mob/living/carbon/human // Mobtype this antag will use if none is provided. var/feedback_tag = "traitor_objective" // End of round var/bantype = "Syndicate" // Ban to check when spawning this antag. + var/minimum_player_age = 7 // Players need to be at least minimum_player_age days old before they are eligable for auto-spawning var/suspicion_chance = 50 // Prob of being on the initial Command report var/flags = 0 // Various runtime options. @@ -95,6 +96,8 @@ for(var/datum/mind/player in ticker.mode.get_players_for_role(role_type, id)) if(ghosts_only && !istype(player.current, /mob/dead)) log_debug("[key_name(player)] is not eligible to become a [role_text]: Only ghosts may join as this role!") + else if(config.use_age_restriction_for_antags && player.current.client.player_age < minimum_player_age) + log_debug("[key_name(player)] is not eligible to become a [role_text]: Is only [player.current.client.player_age] day\s old, has to be [minimum_player_age] day\s!") else if(player.special_role) log_debug("[key_name(player)] is not eligible to become a [role_text]: They already have a special role ([player.special_role])!") else if (player in pending_antagonists) @@ -198,10 +201,10 @@ for(var/datum/mind/player in pending_antagonists) pending_antagonists -= player add_antagonist(player,0,0,1) - + reset_antag_selection() -//Resets the antag selection, clearing all pending_antagonists and their special_role +//Resets the antag selection, clearing all pending_antagonists and their special_role //(and assigned_role if ANTAG_OVERRIDE_JOB is set) as well as clearing the candidate list. //Existing antagonists are left untouched. /datum/antagonist/proc/reset_antag_selection() diff --git a/config/example/config.txt b/config/example/config.txt index 96f44ae19a7..fe7b0777094 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -25,6 +25,10 @@ JOBS_HAVE_MINIMAL_ACCESS ## you have noone older than 0 days, since noone has been logged yet. Only turn this on once you have had the database up for 30 days. #USE_AGE_RESTRICTION_FOR_JOBS +## Unhash this entry to have certain antag roles require your account to be at least a certain number of days old for round start and auto-spawn selection. +## Non-automatic antagonist recruitment, such as being converted to cultism is not affected. Has the same database requirements and notes as USE_AGE_RESTRICTION_FOR_JOBS. +#USE_AGE_RESTRICTION_FOR_ANTAGS + ## Unhash this to use recursive explosions, keep it hashed to use circle explosions. Recursive explosions react to walls, airlocks and blast doors, making them look a lot cooler than the boring old circular explosions. They require more CPU and are (as of january 2013) experimental #USE_RECURSIVE_EXPLOSIONS From 7ba271ab5d1ef225badca093e5eadb2f8474f8ba Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Sat, 17 Oct 2015 20:39:11 +0200 Subject: [PATCH 03/14] Changelog entry. --- html/changelogs/PsiOmegaDelta-DelayedAntag.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/PsiOmegaDelta-DelayedAntag.yml diff --git a/html/changelogs/PsiOmegaDelta-DelayedAntag.yml b/html/changelogs/PsiOmegaDelta-DelayedAntag.yml new file mode 100644 index 00000000000..c4d17877643 --- /dev/null +++ b/html/changelogs/PsiOmegaDelta-DelayedAntag.yml @@ -0,0 +1,4 @@ +author: PsiOmegaDelta +delete-after: True +changes: + - tweak: "The round start and auto-antag spawners can now check if players have played long enough to be eligable for selection." From dc563c58bdb7b960f0c26b7d85adf110643caf2e Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Fri, 23 Oct 2015 18:58:57 +0200 Subject: [PATCH 04/14] Converts the nuclear bomb to the new wire system. --- baystation12.dme | 1 + code/datums/wires/nuclearbomb.dm | 62 ++++++++++++++++++++++ code/game/machinery/nuclear_bomb.dm | 80 +++-------------------------- 3 files changed, 70 insertions(+), 73 deletions(-) create mode 100644 code/datums/wires/nuclearbomb.dm diff --git a/baystation12.dme b/baystation12.dme index aaad35c05b6..d0886c1839c 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -207,6 +207,7 @@ #include "code\datums\wires\camera.dm" #include "code\datums\wires\explosive.dm" #include "code\datums\wires\mulebot.dm" +#include "code\datums\wires\nuclearbomb.dm" #include "code\datums\wires\particle_accelerator.dm" #include "code\datums\wires\radio.dm" #include "code\datums\wires\robot.dm" diff --git a/code/datums/wires/nuclearbomb.dm b/code/datums/wires/nuclearbomb.dm new file mode 100644 index 00000000000..a8f5357840a --- /dev/null +++ b/code/datums/wires/nuclearbomb.dm @@ -0,0 +1,62 @@ +/datum/wires/nuclearbomb + holder_type = /obj/machinery/nuclearbomb + random = 1 + wire_count = 7 + +var/const/NUCLEARBOMB_WIRE_LIGHT = 1 +var/const/NUCLEARBOMB_WIRE_TIMING = 2 +var/const/NUCLEARBOMB_WIRE_SAFETY = 4 + +/datum/wires/nuclearbomb/CanUse(var/mob/living/L) + var/obj/machinery/nuclearbomb/N = holder + if(N.panel_open) + return 1 + return 0 + +/datum/wires/nuclearbomb/GetInteractWindow() + var/obj/machinery/nuclearbomb/N = holder + . += ..() + . += "
The device is [N.timing ? "shaking!" : "still."]
" + . += "The device is is [N.safety ? "quiet" : "whirring"].
" + . += "The lights are [N.lighthack ? "static" : "functional"].
" + +/datum/wires/nuclearbomb/UpdatePulsed(var/index) + var/obj/machinery/nuclearbomb/N = holder + switch(index) + if(NUCLEARBOMB_WIRE_LIGHT) + N.lighthack = !N.lighthack + spawn(100) + N.lighthack = !N.lighthack + if(NUCLEARBOMB_WIRE_TIMING) + if(N.timing) + spawn + message_admins("[key_name_admin(usr)] pulsed a nuclear bomb's detonation wire, causing it to explode (JMP)") + N.explode() + if(NUCLEARBOMB_WIRE_SAFETY) + N.safety = !N.safety + spawn(100) + N.safety = !N.safety + if(N.safety == 1) + N.visible_message("\The [N] quiets down.") + if(!N.lighthack) + if (N.icon_state == "nuclearbomb2") + N.icon_state = "nuclearbomb1" + else + N.visible_message("\The [N] emits a quiet whirling noise!") + +/datum/wires/nuclearbomb/UpdateCut(var/index, var/mended) + var/obj/machinery/nuclearbomb/N = holder + switch(index) + if(NUCLEARBOMB_WIRE_SAFETY) + if(N.timing) + spawn + message_admins("[key_name_admin(usr)] cut a nuclear bomb's timing wire, causing it to explode (JMP)") + N.explode() + if(NUCLEARBOMB_WIRE_TIMING) + if(!N.lighthack) + if (N.icon_state == "nuclearbomb2") + N.icon_state = "nuclearbomb1" + N.timing = 0 + bomb_set = 0 + if(NUCLEARBOMB_WIRE_LIGHT) + N.lighthack = !N.lighthack diff --git a/code/game/machinery/nuclear_bomb.dm b/code/game/machinery/nuclear_bomb.dm index a8ca3f1dbea..fb2a4994e33 100644 --- a/code/game/machinery/nuclear_bomb.dm +++ b/code/game/machinery/nuclear_bomb.dm @@ -17,34 +17,21 @@ var/bomb_set var/yes_code = 0.0 var/safety = 1.0 var/obj/item/weapon/disk/nuclear/auth = null - var/list/wires = list() - var/light_wire - var/safety_wire - var/timing_wire var/removal_stage = 0 // 0 is no removal, 1 is covers removed, 2 is covers open, // 3 is sealant open, 4 is unwrenched, 5 is removed from bolts. use_power = 0 - + var/datum/wires/nuclearbomb/wires /obj/machinery/nuclearbomb/New() ..() r_code = "[rand(10000, 99999.0)]"//Creates a random code upon object spawn. + wires = new(src) - src.wires["Red"] = 0 - src.wires["Blue"] = 0 - src.wires["Green"] = 0 - src.wires["Marigold"] = 0 - src.wires["Fuschia"] = 0 - src.wires["Black"] = 0 - src.wires["Pearl"] = 0 - var/list/w = list("Red","Blue","Green","Marigold","Black","Fuschia","Pearl") - src.light_wire = pick(w) - w -= src.light_wire - src.timing_wire = pick(w) - w -= src.timing_wire - src.safety_wire = pick(w) - w -= src.safety_wire +/obj/machinery/nuclearbomb/Destroy() + qdel(wires) + wires = null + return ..() /obj/machinery/nuclearbomb/process() if (src.timing) @@ -58,7 +45,6 @@ var/bomb_set return /obj/machinery/nuclearbomb/attackby(obj/item/weapon/O as obj, mob/user as mob) - if (istype(O, /obj/item/weapon/screwdriver)) src.add_fingerprint(user) if (src.auth) @@ -83,7 +69,7 @@ var/bomb_set return if (istype(O, /obj/item/weapon/wirecutters) || istype(O, /obj/item/device/multitool)) if (src.opened == 1) - nukehack_win(user) + wires.Interact(user) return if (src.extended) @@ -202,17 +188,6 @@ var/bomb_set src.extended = 1 return -obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob) - var/dat as text - dat += "Nuclear Fission Explosive
\nNuclear Device Wires:
" - for(var/wire in src.wires) - dat += text("[wire] Wire: [src.wires[wire] ? "Mend" : "Cut"] Pulse
") - dat += text("
The device is [src.timing ? "shaking!" : "still"]
") - dat += text("The device is [src.safety ? "quiet" : "whirring"].
") - dat += text("The lights are [src.lighthack ? "static" : "functional"].
") - user << browse("Bomb Defusion[dat]","window=nukebomb_hack") - onclose(user, "nukebomb_hack") - /obj/machinery/nuclearbomb/verb/make_deployable() set category = "Object" set name = "Make Deployable" @@ -239,47 +214,6 @@ obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob) return if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) usr.set_machine(src) - if(href_list["act"]) - var/temp_wire = href_list["wire"] - if(href_list["act"] == "pulse") - if (!istype(usr.get_active_hand(), /obj/item/device/multitool)) - usr << "You need a multitool!" - else - if(src.wires[temp_wire]) - usr << "You can't pulse a cut wire." - else - if(src.light_wire == temp_wire) - src.lighthack = !src.lighthack - spawn(100) src.lighthack = !src.lighthack - if(src.timing_wire == temp_wire) - if(src.timing) - explode() - if(src.safety_wire == temp_wire) - src.safety = !src.safety - spawn(100) src.safety = !src.safety - if(src.safety == 1) - visible_message("The [src] quiets down.") - if(!src.lighthack) - if (src.icon_state == "nuclearbomb2") - src.icon_state = "nuclearbomb1" - else - visible_message("The [src] emits a quiet whirling noise!") - if(href_list["act"] == "wire") - if (!istype(usr.get_active_hand(), /obj/item/weapon/wirecutters)) - usr << "You need wirecutters!" - else - wires[temp_wire] = !wires[temp_wire] - if(src.safety_wire == temp_wire) - if(src.timing) - explode() - if(src.timing_wire == temp_wire) - if(!src.lighthack) - if (src.icon_state == "nuclearbomb2") - src.icon_state = "nuclearbomb1" - src.timing = 0 - bomb_set = 0 - if(src.light_wire == temp_wire) - src.lighthack = !src.lighthack if (href_list["auth"]) if (src.auth) From 88d85c16fa0be5deac5713770e955883e7c8ea34 Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Sat, 24 Oct 2015 12:41:58 +0200 Subject: [PATCH 05/14] Scheduler now uses btime. Partial port of https://github.com/ParadiseSS13/Paradise/pull/1540. --- baystation12.dme | 6 +- btime.dll | Bin 0 -> 6656 bytes code/__defines/btime.dm | 18 + .../process_scheduler.dm} | 37 +- code/_helpers/datum_pool.dm | 2 - code/_helpers/lists.dm | 4 +- code/_helpers/logging.dm | 9 +- .../ProcessScheduler/ProcessScheduler.dme | 32 - .../ProcessScheduler/core/_stubs.dm | 21 +- .../ProcessScheduler/core/process.dm | 184 +++-- .../ProcessScheduler/core/processScheduler.dm | 702 ++++++++++-------- .../ProcessScheduler/core/updateQueue.dm | 127 ---- .../core/updateQueueWorker.dm | 83 --- .../test/processSchedulerView.dm | 94 --- .../test/testDyingUpdateQueueProcess.dm | 27 - .../ProcessScheduler/test/testHarness.dm | 35 - .../ProcessScheduler/test/testHungProcess.dm | 15 - .../ProcessScheduler/test/testNiceProcess.dm | 13 - .../ProcessScheduler/test/testSlowProcess.dm | 28 - .../ProcessScheduler/test/testUpdateQueue.dm | 209 ------ .../test/testUpdateQueueProcess.dm | 24 - .../test/testZombieProcess.dm | 13 - code/controllers/Processes/air.dm | 1 + code/controllers/Processes/alarm.dm | 38 +- code/controllers/Processes/chemistry.dm | 11 +- code/controllers/Processes/disease.dm | 12 +- code/controllers/Processes/garbage.dm | 54 +- code/controllers/Processes/inactivity.dm | 2 +- code/controllers/Processes/lighting.dm | 1 + code/controllers/Processes/machinery.dm | 34 +- code/controllers/Processes/mob.dm | 28 +- code/controllers/Processes/nanoui.dm | 25 +- code/controllers/Processes/obj.dm | 32 +- code/controllers/Processes/turf.dm | 7 +- code/controllers/configuration.dm | 4 + code/controllers/subsystem/alarms.dm | 30 - code/game/turfs/initialization/maintenance.dm | 2 +- code/global.dm | 1 - code/modules/lighting/lighting_process.dm | 16 +- code/modules/mob/living/carbon/human/human.dm | 4 +- code/modules/mob/mob.dm | 11 +- config/example/config.txt | 3 + 42 files changed, 721 insertions(+), 1278 deletions(-) create mode 100644 btime.dll create mode 100644 code/__defines/btime.dm rename code/{controllers/ProcessScheduler/core/_define.dm => __defines/process_scheduler.dm} (64%) delete mode 100644 code/controllers/ProcessScheduler/ProcessScheduler.dme delete mode 100644 code/controllers/ProcessScheduler/core/updateQueue.dm delete mode 100644 code/controllers/ProcessScheduler/core/updateQueueWorker.dm delete mode 100644 code/controllers/ProcessScheduler/test/processSchedulerView.dm delete mode 100644 code/controllers/ProcessScheduler/test/testDyingUpdateQueueProcess.dm delete mode 100644 code/controllers/ProcessScheduler/test/testHarness.dm delete mode 100644 code/controllers/ProcessScheduler/test/testHungProcess.dm delete mode 100644 code/controllers/ProcessScheduler/test/testNiceProcess.dm delete mode 100644 code/controllers/ProcessScheduler/test/testSlowProcess.dm delete mode 100644 code/controllers/ProcessScheduler/test/testUpdateQueue.dm delete mode 100644 code/controllers/ProcessScheduler/test/testUpdateQueueProcess.dm delete mode 100644 code/controllers/ProcessScheduler/test/testZombieProcess.dm delete mode 100644 code/controllers/subsystem/alarms.dm diff --git a/baystation12.dme b/baystation12.dme index aaad35c05b6..0c9dfeda003 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -19,6 +19,7 @@ #include "code\__defines\_compile_options.dm" #include "code\__defines\admin.dm" #include "code\__defines\atmos.dm" +#include "code\__defines\btime.dm" #include "code\__defines\chemistry.dm" #include "code\__defines\damage_organs.dm" #include "code\__defines\dna.dm" @@ -29,6 +30,7 @@ #include "code\__defines\math_physics.dm" #include "code\__defines\misc.dm" #include "code\__defines\mobs.dm" +#include "code\__defines\process_scheduler.dm" #include "code\__defines\research.dm" #include "code\__defines\species_languages.dm" #include "code\__defines\turfs.dm" @@ -137,13 +139,9 @@ #include "code\controllers\Processes\ticker.dm" #include "code\controllers\Processes\turf.dm" #include "code\controllers\Processes\vote.dm" -#include "code\controllers\ProcessScheduler\core\_define.dm" #include "code\controllers\ProcessScheduler\core\_stubs.dm" #include "code\controllers\ProcessScheduler\core\process.dm" #include "code\controllers\ProcessScheduler\core\processScheduler.dm" -#include "code\controllers\ProcessScheduler\core\updateQueue.dm" -#include "code\controllers\ProcessScheduler\core\updateQueueWorker.dm" -#include "code\controllers\subsystem\alarms.dm" #include "code\datums\ai_law_sets.dm" #include "code\datums\ai_laws.dm" #include "code\datums\browser.dm" diff --git a/btime.dll b/btime.dll new file mode 100644 index 0000000000000000000000000000000000000000..af6c82a99865919316afd9689e56badb20c619de GIT binary patch literal 6656 zcmeHLeQ;FO6~CM8!a{c0MG}bub-~c!2Vp;xU6RNmSquY_4S|rgz_Q7{WH;hkHEvPfPF=)`Djle_%sMgA&E}P>+jy(g`l*Z zv46Ck`ex2O_ndR@dFSh%yKigmd4%K=LX-emCgcDxeVlCk=feoZ({6fo8hLrjdvgyc zR=qcOZ6FvkwDHjv-WN7B`67|1U})qFycjVABZjKgb%t=%&y{GkQ;RaHe^y$1@sssS z_GaOT>JNK=5Bi8|FoQqYdz8^1GdkzF3wuwo^>^$&2z+YMiM<~){6~h5s7`0-PZ?el zYzk1_Sx?+9LRKkMWMl1Z^;zB^$(fs{&=4|}I+W&4o&l@}7#OW*^Bh7ZG4cu~o57&L z!;?dt3bu*vqZ=4bBjY?mn!$Y>xPpqEgbZT!*B&?I;6Gv@#Qrtm6-Ekj=M|FKDNLll zGA|Lhb}H|mf`Qsaea+a78G8(bY%bybKEX%GJu0xkU=C+u0*XCOyt*X4jO?JrV+7;? z@&OYbCn3oaKE^kJ$9x5Yt-Bt0!sDd+crFyhLh3s~4A{ED35zgw5_0F&oNuXrHv;RV z;rMX=9;8rjc`M->-{~55%LT~1Ubo+MAwH~@4)uJhyzLOEi#wGMUZKW7y`o2D{B-mS z2)}IBMUv-rpCy6cJ*V5G8iWea@0`;$96G0)t_@g-{+!OEJq|u-O;O+&X03SvHxo?P zZU&YM0$@rtp*Gcvn|ax2pg|^=oZZD`i<^{~lVPiOzA!tsGL8zbQHnTcF^Agx!jQN5I+$`Y|mVbM!_OpQ%2M;x8wx~?P) zwIqL>duBhIocR?HqNdPwJ&Rd7Fcw)FWt*=Zo?Oet6?NlsaNZm@AX`?*Iv631TuiS<`M3^0*I5h_oJJ z3^&#JH(9{tmAskyAXu|IZp+AJ*fumvsu`9P5=poQYu%|W$b!eyD{(2yN$EUx!EcoJB^<_7 z9?X>9PEAH!dL{96pNhr;0+}8rxu6h^w<@};XgY4h8ftSPaJ-VTpjA}2DpCX-Phg6Y zBvZJZiDx6-ynVO``D>k-x(+M^Pt}^^dGD6)1t!E=TSUhK10CngrlYNpj+OZsn;$B0 zGNiRKG)K>nO2g26HA4%PKu7X!dIX)hM-T z$}jO#q-u5U`{iHoQ}2u?7nC36QOU@qfT& zZuBB8zs&E7?DrS`CqhN~oq*d0uN;VR90;5PSsasG*)E7H_VO9&omi~t z@~%y%Bp)3%T_J&A>tO~BL~0RU6+c+Gu~(kIidkr7;a4w5%MwMO~4C)rvbYFcRziQcd=X`Zqea%#Rn;}Dd}DO`-7}oO)PDcj_|HpEQ2w&T8`i}* zKDNOf3$6}xExrv^Tx^RFZQJ1HqfJ~aR@W5Z{9=gX7lwT?f#Wwc3c)b9VGS4Jd@(Lf zm9+V(zx1IlW!z$Pc0iN9=0k5{D(KJPEWJ8E9orj$O8{B^@d@h^i2swB9AxE(C&;PZ zcV}M7Q8ovmc?4Ht`csYOssZ$7Kmb5jzX;fh`7TOhCG)t%9}1BrjUCa5-`m0oGzdRl_|b!@%leY!BTBy{H{x08pHHc+7D^uKD~YYWi5tU7S$Yfy{>2!X>iOwdQWu zDvO!9OSUV$u}B*qj0nx7rmlY38k5EUkIPb-X>lknp|%%5)`mJOte?#UXHkP=mM{wYZO~rINlqGMz;|1 zJl+EKx=6qm@rO9StG$V96N1qQ`9)f?7Mg+)pTK3RmF&*-;$>TiQsosRY*qrzS1fn| z`;f_KgqgWm>CMa@qWVzM5wFnE#=*+ws5jyZb1_U|Zp0TNOT%`1k-K^lshkB&3sG248t9mb8aMhOM|6(QPV=O(n)+14qwzFw#<4yl(CCh4x}Y zOh8-m(PmOv+`+|)m)xP9TH%YuxNu{r!vF=5SY@%uM;6C$iQ@WP7!Ee^(O9%uSct~4 z*cS_zY&8`daKMAjTui8+_%^6A7%Bu_j0r2yj56Bh{R?fDd2Anc#<(Vt4+Afx0MSSLUgPw_Qh62wnn#be6c|cE^VSe4JwP9 zeW4gvY*=(zPsO5t{FaJESJ_mt=(2OzUa=?}HxOUR#WhLX(X)}a$;RuA9%ImWukk+P z1IC{iA2B{<+;2Q=959|V4jL~Sb4)jzOr}y3XS&a{-L%{Egz05d()5n$sOclqr>5!V z8_eG^-)vrBE-`O5Z!gyR{= this_many_calls) sleepCheck() +#define SCHECK SCHECK_EVERY(50) diff --git a/code/_helpers/datum_pool.dm b/code/_helpers/datum_pool.dm index 5c13c0d8ba2..b5bcea123fe 100644 --- a/code/_helpers/datum_pool.dm +++ b/code/_helpers/datum_pool.dm @@ -74,7 +74,6 @@ var/global/list/GlobalPool = list() D.Destroy() D.ResetVars() - D.disposed = 1 //Set to stop processing while pooled /proc/IsPooled(var/datum/D) if(isnull(GlobalPool[D.type])) @@ -86,7 +85,6 @@ var/global/list/GlobalPool = list() New(arglist(args)) else New(args) - disposed = null /atom/movable/Prepare(args) var/list/args_list = args diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm index fcda2a03d94..b784ae34efd 100644 --- a/code/_helpers/lists.dm +++ b/code/_helpers/lists.dm @@ -610,13 +610,13 @@ proc/dd_sortedTextList(list/incoming) /datum/alarm/dd_SortValue() return "[sanitize_old(last_name)]" -/proc/subtypes(prototype) +/proc/subtypesof(prototype) return (typesof(prototype) - prototype) //creates every subtype of prototype (excluding prototype) and adds it to list L. //if no list/L is provided, one is created. /proc/init_subtypes(prototype, list/L) if(!istype(L)) L = list() - for(var/path in subtypes(prototype)) + for(var/path in subtypesof(prototype)) L += new path() return L diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm index 23119c69ad5..f14d70c8385 100644 --- a/code/_helpers/logging.dm +++ b/code/_helpers/logging.dm @@ -25,7 +25,6 @@ if (config.log_admin) diary << "\[[time_stamp()]]ADMIN: [text][log_end]" - /proc/log_debug(text) if (config.log_debug) diary << "\[[time_stamp()]]DEBUG: [text][log_end]" @@ -34,7 +33,6 @@ if(C.prefs.toggles & CHAT_DEBUGLOGS) C << "DEBUG: [text]" - /proc/log_game(text) if (config.log_game) diary << "\[[time_stamp()]]GAME: [text][log_end]" @@ -79,6 +77,11 @@ if (config.log_pda) diary << "\[[time_stamp()]]PDA: [text][log_end]" +/proc/log_to_dd(text) + world.log << text //this comes before the config check because it can't possibly runtime + if(config.log_world_output) + diary << "\[[time_stamp()]]DD_OUTPUT: [text][log_end]" + /proc/log_misc(text) diary << "\[[time_stamp()]]MISC: [text][log_end]" @@ -91,7 +94,7 @@ if(dir & WEST) comps += "WEST" if(dir & UP) comps += "UP" if(dir & DOWN) comps += "DOWN" - + return english_list(comps, nothing_text="0", and_text="|", comma_text="|") //more or less a logging utility diff --git a/code/controllers/ProcessScheduler/ProcessScheduler.dme b/code/controllers/ProcessScheduler/ProcessScheduler.dme deleted file mode 100644 index bf17734cc28..00000000000 --- a/code/controllers/ProcessScheduler/ProcessScheduler.dme +++ /dev/null @@ -1,32 +0,0 @@ -// DM Environment file for ProcessScheduler.dme. -// All manual changes should be made outside the BEGIN_ and END_ blocks. -// New source code should be placed in .dm files: choose File/New --> Code File. - -// BEGIN_INTERNALS -// END_INTERNALS - -// BEGIN_FILE_DIR -#define FILE_DIR . -// END_FILE_DIR - -// BEGIN_PREFERENCES -// END_PREFERENCES - -// BEGIN_INCLUDE -#include "core\_define.dm" -#include "core\_stubs.dm" -#include "core\process.dm" -#include "core\processScheduler.dm" -#include "core\updateQueue.dm" -#include "core\updateQueueWorker.dm" -#include "test\processSchedulerView.dm" -#include "test\testDyingUpdateQueueProcess.dm" -#include "test\testHarness.dm" -#include "test\testHungProcess.dm" -#include "test\testNiceProcess.dm" -#include "test\testSlowProcess.dm" -#include "test\testUpdateQueue.dm" -#include "test\testUpdateQueueProcess.dm" -#include "test\testZombieProcess.dm" -// END_INCLUDE - diff --git a/code/controllers/ProcessScheduler/core/_stubs.dm b/code/controllers/ProcessScheduler/core/_stubs.dm index 326fd29ac2a..3615c12f192 100644 --- a/code/controllers/ProcessScheduler/core/_stubs.dm +++ b/code/controllers/ProcessScheduler/core/_stubs.dm @@ -4,15 +4,7 @@ * This file contains constructs that the process scheduler expects to exist * in a standard ss13 fork. */ -/* -/** - * message_admins - * - * sends a message to admins - */ -/proc/message_admins(msg) - world << msg -*/ + /** * logTheThing * @@ -25,14 +17,3 @@ world << "Diary: \[[diaryType]:[type]] [text]" else world << "Log: \[[type]] [text]" - -/** - * var/disposed - * - * In goonstation, disposed is set to 1 after an object enters the delete queue - * or the object is placed in an object pool (effectively out-of-play so to speak) - */ -/datum/var/disposed -// Garbage collection (controller). -/datum/var/gcDestroyed -/datum/var/timeDestroyed \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/core/process.dm b/code/controllers/ProcessScheduler/core/process.dm index 1f27f4c1ded..66c80035d11 100644 --- a/code/controllers/ProcessScheduler/core/process.dm +++ b/code/controllers/ProcessScheduler/core/process.dm @@ -48,7 +48,7 @@ // This controls how often the process will yield (call sleep(0)) while it is running. // Every concurrent process should sleep periodically while running in order to allow other // processes to execute concurrently. - var/tmp/sleep_interval = PROCESS_DEFAULT_SLEEP_INTERVAL + var/tmp/sleep_interval // hang_warning_time - this is the time (in 1/10 seconds) after which the server will begin to show "maybe hung" in the context window var/tmp/hang_warning_time = PROCESS_DEFAULT_HANG_WARNING_TIME @@ -59,20 +59,20 @@ // hang_restart_time - After this much time(in 1/10 seconds), the server will automatically kill and restart the process. var/tmp/hang_restart_time = PROCESS_DEFAULT_HANG_RESTART_TIME - // cpu_threshold - if world.cpu >= cpu_threshold, scheck() will call sleep(1) to defer further work until the next tick. This keeps a process from driving a tick into overtime (causing perceptible lag) - var/tmp/cpu_threshold = PROCESS_DEFAULT_CPU_THRESHOLD - // How many times in the current run has the process deferred work till the next tick? var/tmp/cpu_defer_count = 0 + // How many SCHECKs have been skipped (to limit btime calls) + var/tmp/calls_since_last_scheck = 0 + /** * recordkeeping vars */ - // Records the time (server ticks) at which the process last finished sleeping + // Records the time (1/10s timeofday) at which the process last finished sleeping var/tmp/last_slept = 0 - // Records the time (s-ticks) at which the process last began running + // Records the time (1/10s timeofday) at which the process last began running var/tmp/run_start = 0 // Records the number of times this process has been killed and restarted @@ -85,26 +85,33 @@ var/tmp/last_object -datum/controller/process/New(var/datum/controller/processScheduler/scheduler) + // Counts the number of times an exception has occurred; gets reset after 10 + var/tmp/list/exceptions = list() + + // Number of deciseconds to delay before starting the process + var/start_delay = 0 + +/datum/controller/process/New(var/datum/controller/processScheduler/scheduler) ..() main = scheduler previousStatus = "idle" idle() name = "process" schedule_interval = 50 - sleep_interval = 2 + sleep_interval = world.tick_lag / PROCESS_DEFAULT_SLEEP_INTERVAL last_slept = 0 run_start = 0 ticks = 0 last_task = 0 last_object = null -datum/controller/process/proc/started() +/datum/controller/process/proc/started() + var/timeofhour = TimeOfHour // Initialize last_slept so we can know when to sleep - last_slept = world.timeofday + last_slept = timeofhour // Initialize run_start so we can detect hung processes. - run_start = world.timeofday + run_start = timeofhour // Initialize defer count cpu_defer_count = 0 @@ -114,65 +121,65 @@ datum/controller/process/proc/started() onStart() -datum/controller/process/proc/finished() +/datum/controller/process/proc/finished() ticks++ idle() main.processFinished(src) onFinish() -datum/controller/process/proc/doWork() +/datum/controller/process/proc/doWork() -datum/controller/process/proc/setup() +/datum/controller/process/proc/setup() -datum/controller/process/proc/process() +/datum/controller/process/proc/process() started() doWork() finished() -datum/controller/process/proc/running() +/datum/controller/process/proc/running() idle = 0 queued = 0 running = 1 hung = 0 setStatus(PROCESS_STATUS_RUNNING) -datum/controller/process/proc/idle() +/datum/controller/process/proc/idle() queued = 0 running = 0 idle = 1 hung = 0 setStatus(PROCESS_STATUS_IDLE) -datum/controller/process/proc/queued() +/datum/controller/process/proc/queued() idle = 0 running = 0 queued = 1 hung = 0 setStatus(PROCESS_STATUS_QUEUED) -datum/controller/process/proc/hung() +/datum/controller/process/proc/hung() hung = 1 setStatus(PROCESS_STATUS_HUNG) -datum/controller/process/proc/handleHung() +/datum/controller/process/proc/handleHung() + var/timeofhour = TimeOfHour var/datum/lastObj = last_object var/lastObjType = "null" if(istype(lastObj)) lastObjType = lastObj.type - // If world.timeofday has rolled over, then we need to adjust. - if (world.timeofday < run_start) - run_start -= 864000 - - var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(world.timeofday - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]" + // If timeofhour has rolled over, then we need to adjust. + if (timeofhour < run_start) + run_start -= 36000 + var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(timeofhour - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]" logTheThing("debug", null, null, msg) logTheThing("diary", null, null, msg, "debug") message_admins(msg) main.restartProcess(src.name) -datum/controller/process/proc/kill() +/datum/controller/process/proc/kill() if (!killed) var/msg = "[name] process was killed at tick #[ticks]." logTheThing("debug", null, null, msg) @@ -182,59 +189,68 @@ datum/controller/process/proc/kill() // Allow inheritors to clean up if needed onKill() - killed = TRUE + // This should del + del(src) - del(src) // This should del - -datum/controller/process/proc/scheck(var/tickId = 0) +// Do not call this directly - use SHECK or SCHECK_EVERY +/datum/controller/process/proc/sleepCheck(var/tickId = 0) + calls_since_last_scheck = 0 if (killed) // The kill proc is the only place where killed is set. // The kill proc should have deleted this datum, and all sleeping procs that are // owned by it. CRASH("A killed process is still running somehow...") + if (hung) + // This will only really help if the doWork proc ends up in an infinite loop. + handleHung() + CRASH("Process [name] hung and was restarted.") - // For each tick the process defers, it increments the cpu_defer_count so we don't - // defer indefinitely - if (world.cpu >= cpu_threshold + cpu_defer_count * 10) - sleep(1) + if (main.getCurrentTickElapsedTime() > main.timeAllowance) + sleep(world.tick_lag) cpu_defer_count++ - last_slept = world.timeofday + last_slept = TimeOfHour else - // If world.timeofday has rolled over, then we need to adjust. - if (world.timeofday < last_slept) - last_slept -= 864000 + var/timeofhour = TimeOfHour + // If timeofhour has rolled over, then we need to adjust. + if (timeofhour < last_slept) + last_slept -= 36000 - if (world.timeofday > last_slept + sleep_interval) - // If we haven't slept in sleep_interval ticks, sleep to allow other work to proceed. + if (timeofhour > last_slept + sleep_interval) + // If we haven't slept in sleep_interval deciseconds, sleep to allow other work to proceed. sleep(0) - last_slept = world.timeofday + last_slept = TimeOfHour -datum/controller/process/proc/update() +/datum/controller/process/proc/update() // Clear delta if(previousStatus != status) setStatus(status) var/elapsedTime = getElapsedTime() - if (elapsedTime > hang_restart_time) + if (hung) + handleHung() + return + else if (elapsedTime > hang_restart_time) hung() else if (elapsedTime > hang_alert_time) setStatus(PROCESS_STATUS_PROBABLY_HUNG) else if (elapsedTime > hang_warning_time) setStatus(PROCESS_STATUS_MAYBE_HUNG) -datum/controller/process/proc/getElapsedTime() - if (world.timeofday < run_start) - return world.timeofday - (run_start - 864000) - return world.timeofday - run_start -datum/controller/process/proc/tickDetail() +/datum/controller/process/proc/getElapsedTime() + var/timeofhour = TimeOfHour + if (timeofhour < run_start) + return timeofhour - (run_start - 36000) + return timeofhour - run_start + +/datum/controller/process/proc/tickDetail() return -datum/controller/process/proc/getContext() +/datum/controller/process/proc/getContext() return "[name][main.averageRunTime(src)][main.last_run_time[src]][main.highest_run_time[src]][ticks]\n" -datum/controller/process/proc/getContextData() +/datum/controller/process/proc/getContextData() return list( "name" = name, "averageRunTime" = main.averageRunTime(src), @@ -246,10 +262,10 @@ datum/controller/process/proc/getContextData() "disabled" = disabled ) -datum/controller/process/proc/getStatus() +/datum/controller/process/proc/getStatus() return status -datum/controller/process/proc/getStatusText(var/s = 0) +/datum/controller/process/proc/getStatusText(var/s = 0) if(!s) s = status switch(s) @@ -268,21 +284,21 @@ datum/controller/process/proc/getStatusText(var/s = 0) else return "UNKNOWN" -datum/controller/process/proc/getPreviousStatus() +/datum/controller/process/proc/getPreviousStatus() return previousStatus -datum/controller/process/proc/getPreviousStatusText() +/datum/controller/process/proc/getPreviousStatusText() return getStatusText(previousStatus) -datum/controller/process/proc/setStatus(var/newStatus) +/datum/controller/process/proc/setStatus(var/newStatus) previousStatus = status status = newStatus -datum/controller/process/proc/setLastTask(var/task, var/object) +/datum/controller/process/proc/setLastTask(var/task, var/object) last_task = task last_object = object -datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target) +/datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target) main = target.main name = target.name schedule_interval = target.schedule_interval @@ -295,28 +311,62 @@ datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target last_object = target.last_object copyStateFrom(target) -datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target) +/datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target) -datum/controller/process/proc/onKill() +/datum/controller/process/proc/onKill() -datum/controller/process/proc/onStart() +/datum/controller/process/proc/onStart() -datum/controller/process/proc/onFinish() +/datum/controller/process/proc/onFinish() -datum/controller/process/proc/disable() +/datum/controller/process/proc/disable() disabled = 1 -datum/controller/process/proc/enable() +/datum/controller/process/proc/enable() disabled = 0 +/datum/controller/process/proc/getAverageRunTime() + return main.averageRunTime(src) /datum/controller/process/proc/getLastRunTime() return main.getProcessLastRunTime(src) +/datum/controller/process/proc/getHighestRunTime() + return main.getProcessHighestRunTime(src) + /datum/controller/process/proc/getTicks() return ticks -/datum/controller/process/proc/getStatName() - return name +/datum/controller/process/proc/statProcess() + var/averageRunTime = round(getAverageRunTime(), 0.1)/10 + var/lastRunTime = round(getLastRunTime(), 0.1)/10 + var/highestRunTime = round(getHighestRunTime(), 0.1)/10 + stat("[name]", "T#[getTicks()] | AR [averageRunTime] | LR [lastRunTime] | HR [highestRunTime] | D [cpu_defer_count]") -/datum/controller/process/proc/getTickTime() - return "#[getTicks()]\t- [getLastRunTime()]" +/datum/controller/process/proc/catchException(var/exception/e, var/thrower) + var/etext = "[e]" + var/eid = "[e]" // Exception ID, for tracking repeated exceptions + var/ptext = "" // "processing..." text, for what was being processed (if known) + if(istype(e)) + etext += " in [e.file], line [e.line]" + eid = "[e.file]:[e.line]" + if(eid in exceptions) + if(exceptions[eid]++ >= 10) + return + else + exceptions[eid] = 1 + if(istype(thrower, /datum)) + var/datum/D = thrower + ptext = " processing [D.type]" + if(istype(thrower, /atom)) + var/atom/A = thrower + ptext += " ([A]) ([A.x],[A.y],[A.z])" + log_to_dd("\[[time_stamp()]\] Process [name] caught exception[ptext]: [etext]") + if(exceptions[eid] >= 10) + log_to_dd("This exception will now be ignored for ten minutes.") + spawn(6000) + exceptions[eid] = 0 + +/datum/controller/process/proc/catchBadType(var/datum/caught) + if(isnull(caught) || !istype(caught) || !isnull(caught.gcDestroyed)) + return // Only bother with types we can identify and that don't belong + catchException("Type [caught.type] does not belong in process' queue") diff --git a/code/controllers/ProcessScheduler/core/processScheduler.dm b/code/controllers/ProcessScheduler/core/processScheduler.dm index 1be24045938..ab2fe3cb982 100644 --- a/code/controllers/ProcessScheduler/core/processScheduler.dm +++ b/code/controllers/ProcessScheduler/core/processScheduler.dm @@ -1,320 +1,382 @@ -// Singleton instance of game_controller_new, setup in world.New() -var/global/datum/controller/processScheduler/processScheduler - -/datum/controller/processScheduler - // Processes known by the scheduler - var/tmp/datum/controller/process/list/processes = new - - // Processes that are currently running - var/tmp/datum/controller/process/list/running = new - - // Processes that are idle - var/tmp/datum/controller/process/list/idle = new - - // Processes that are queued to run - var/tmp/datum/controller/process/list/queued = new - - // Process name -> process object map - var/tmp/datum/controller/process/list/nameToProcessMap = new - - // Process last start times - var/tmp/datum/controller/process/list/last_start = new - - // Process last run durations - var/tmp/datum/controller/process/list/last_run_time = new - - // Per process list of the last 20 durations - var/tmp/datum/controller/process/list/last_twenty_run_times = new - - // Process highest run time - var/tmp/datum/controller/process/list/highest_run_time = new - - // Sleep 1 tick -- This may be too aggressive. - var/tmp/scheduler_sleep_interval = 1 - - // Controls whether the scheduler is running or not - var/tmp/isRunning = 0 - - // Setup for these processes will be deferred until all the other processes are set up. - var/tmp/list/deferredSetupList = new - -/** - * deferSetupFor - * @param path processPath - * If a process needs to be initialized after everything else, add it to - * the deferred setup list. On goonstation, only the ticker needs to have - * this treatment. - */ -/datum/controller/processScheduler/proc/deferSetupFor(var/processPath) - if (!(processPath in deferredSetupList)) - deferredSetupList += processPath - -/datum/controller/processScheduler/proc/setup() - // There can be only one - if(processScheduler && (processScheduler != src)) - del(src) - return 0 - - var/process - // Add all the processes we can find, except for the ticker - for (process in typesof(/datum/controller/process) - /datum/controller/process) - if (!(process in deferredSetupList)) - addProcess(new process(src)) - - for (process in deferredSetupList) - addProcess(new process(src)) - -/datum/controller/processScheduler/proc/start() - isRunning = 1 - spawn(0) - process() - -/datum/controller/processScheduler/proc/process() - while(isRunning) - checkRunningProcesses() - queueProcesses() - runQueuedProcesses() - sleep(scheduler_sleep_interval) - -/datum/controller/processScheduler/proc/stop() - isRunning = 0 - -/datum/controller/processScheduler/proc/checkRunningProcesses() - for(var/datum/controller/process/p in running) - p.update() - - if (isnull(p)) // Process was killed - continue - - var/status = p.getStatus() - var/previousStatus = p.getPreviousStatus() - - // Check status changes - if(status != previousStatus) - //Status changed. - - switch(status) - if(PROCESS_STATUS_MAYBE_HUNG) - message_admins("Process '[p.name]' is [p.getStatusText(status)].") - if(PROCESS_STATUS_PROBABLY_HUNG) - message_admins("Process '[p.name]' is [p.getStatusText(status)].") - if(PROCESS_STATUS_HUNG) - message_admins("Process '[p.name]' is [p.getStatusText(status)].") - p.handleHung() - -/datum/controller/processScheduler/proc/queueProcesses() - for(var/datum/controller/process/p in processes) - // Don't double-queue, don't queue running processes - if (p.disabled || p.running || p.queued || !p.idle) - continue - - // If world.timeofday has rolled over, then we need to adjust. - if (world.timeofday < last_start[p]) - last_start[p] -= 864000 - - // If the process should be running by now, go ahead and queue it - if (world.timeofday > last_start[p] + p.schedule_interval) - setQueuedProcessState(p) - -/datum/controller/processScheduler/proc/runQueuedProcesses() - for(var/datum/controller/process/p in queued) - runProcess(p) - -/datum/controller/processScheduler/proc/addProcess(var/datum/controller/process/process) - processes.Add(process) - process.idle() - idle.Add(process) - - // init recordkeeping vars - last_start.Add(process) - last_start[process] = 0 - last_run_time.Add(process) - last_run_time[process] = 0 - last_twenty_run_times.Add(process) - last_twenty_run_times[process] = list() - highest_run_time.Add(process) - highest_run_time[process] = 0 - - // init starts and stops record starts - recordStart(process, 0) - recordEnd(process, 0) - - // Set up process - process.setup() - - // Save process in the name -> process map - nameToProcessMap[process.name] = process - -/datum/controller/processScheduler/proc/replaceProcess(var/datum/controller/process/oldProcess, var/datum/controller/process/newProcess) - processes.Remove(oldProcess) - processes.Add(newProcess) - - newProcess.idle() - idle.Remove(oldProcess) - running.Remove(oldProcess) - queued.Remove(oldProcess) - idle.Add(newProcess) - - last_start.Remove(oldProcess) - last_start.Add(newProcess) - last_start[newProcess] = 0 - - last_run_time.Add(newProcess) - last_run_time[newProcess] = last_run_time[oldProcess] - last_run_time.Remove(oldProcess) - - last_twenty_run_times.Add(newProcess) - last_twenty_run_times[newProcess] = last_twenty_run_times[oldProcess] - last_twenty_run_times.Remove(oldProcess) - - highest_run_time.Add(newProcess) - highest_run_time[newProcess] = highest_run_time[oldProcess] - highest_run_time.Remove(oldProcess) - - recordStart(newProcess, 0) - recordEnd(newProcess, 0) - - nameToProcessMap[newProcess.name] = newProcess - - -/datum/controller/processScheduler/proc/runProcess(var/datum/controller/process/process) - spawn(0) - process.process() - -/datum/controller/processScheduler/proc/processStarted(var/datum/controller/process/process) - setRunningProcessState(process) - recordStart(process) - -/datum/controller/processScheduler/proc/processFinished(var/datum/controller/process/process) - setIdleProcessState(process) - recordEnd(process) - -/datum/controller/processScheduler/proc/setIdleProcessState(var/datum/controller/process/process) - if (process in running) - running -= process - if (process in queued) - queued -= process - if (!(process in idle)) - idle += process - - process.idle() - -/datum/controller/processScheduler/proc/setQueuedProcessState(var/datum/controller/process/process) - if (process in running) - running -= process - if (process in idle) - idle -= process - if (!(process in queued)) - queued += process - - // The other state transitions are handled internally by the process. - process.queued() - -/datum/controller/processScheduler/proc/setRunningProcessState(var/datum/controller/process/process) - if (process in queued) - queued -= process - if (process in idle) - idle -= process - if (!(process in running)) - running += process - - process.running() - -/datum/controller/processScheduler/proc/recordStart(var/datum/controller/process/process, var/time = null) - if (isnull(time)) - time = world.timeofday - - last_start[process] = time - -/datum/controller/processScheduler/proc/recordEnd(var/datum/controller/process/process, var/time = null) - if (isnull(time)) - time = world.timeofday - - // If world.timeofday has rolled over, then we need to adjust. - if (time < last_start[process]) - last_start[process] -= 864000 - - var/lastRunTime = time - last_start[process] - - if(lastRunTime < 0) - lastRunTime = 0 - - recordRunTime(process, lastRunTime) - -/** - * recordRunTime - * Records a run time for a process - */ -/datum/controller/processScheduler/proc/recordRunTime(var/datum/controller/process/process, time) - last_run_time[process] = time - if(time > highest_run_time[process]) - highest_run_time[process] = time - - var/list/lastTwenty = last_twenty_run_times[process] - if (lastTwenty.len == 20) - lastTwenty.Cut(1, 2) - lastTwenty.len++ - lastTwenty[lastTwenty.len] = time - -/** - * averageRunTime - * returns the average run time (over the last 20) of the process - */ -/datum/controller/processScheduler/proc/averageRunTime(var/datum/controller/process/process) - var/lastTwenty = last_twenty_run_times[process] - - var/t = 0 - var/c = 0 - for(var/time in lastTwenty) - t += time - c++ - - if(c > 0) - return t / c - return c - -/datum/controller/processScheduler/proc/getStatusData() - var/list/data = new - - for (var/datum/controller/process/p in processes) - data.len++ - data[data.len] = p.getContextData() - - return data - -/datum/controller/processScheduler/proc/getProcessCount() - return processes.len - -/datum/controller/processScheduler/proc/hasProcess(var/processName as text) - if (nameToProcessMap[processName]) - return 1 - -/datum/controller/processScheduler/proc/killProcess(var/processName as text) - restartProcess(processName) - -/datum/controller/processScheduler/proc/restartProcess(var/processName as text) - if (hasProcess(processName)) - var/datum/controller/process/oldInstance = nameToProcessMap[processName] - var/datum/controller/process/newInstance = new oldInstance.type(src) - newInstance._copyStateFrom(oldInstance) - replaceProcess(oldInstance, newInstance) - oldInstance.kill() - -/datum/controller/processScheduler/proc/enableProcess(var/processName as text) - if (hasProcess(processName)) - var/datum/controller/process/process = nameToProcessMap[processName] - process.enable() - -/datum/controller/processScheduler/proc/disableProcess(var/processName as text) - if (hasProcess(processName)) - var/datum/controller/process/process = nameToProcessMap[processName] - process.disable() - -/datum/controller/processScheduler/proc/getProcess(var/name) - return nameToProcessMap[name] - -/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process) - return last_run_time[process] - -/datum/controller/processScheduler/proc/getIsRunning() - return isRunning +// Singleton instance of game_controller_new, setup in world.New() +var/global/datum/controller/processScheduler/processScheduler + +/datum/controller/processScheduler + // Processes known by the scheduler + var/tmp/datum/controller/process/list/processes = new + + // Processes that are currently running + var/tmp/datum/controller/process/list/running = new + + // Processes that are idle + var/tmp/datum/controller/process/list/idle = new + + // Processes that are queued to run + var/tmp/datum/controller/process/list/queued = new + + // Process name -> process object map + var/tmp/datum/controller/process/list/nameToProcessMap = new + + // Process last queued times (world time) + var/tmp/datum/controller/process/list/last_queued = new + + // Process last start times (real time) + var/tmp/datum/controller/process/list/last_start = new + + // Process last run durations + var/tmp/datum/controller/process/list/last_run_time = new + + // Per process list of the last 20 durations + var/tmp/datum/controller/process/list/last_twenty_run_times = new + + // Process highest run time + var/tmp/datum/controller/process/list/highest_run_time = new + + // How long to sleep between runs (set to tick_lag in New) + var/tmp/scheduler_sleep_interval + + // Controls whether the scheduler is running or not + var/tmp/isRunning = 0 + + // Setup for these processes will be deferred until all the other processes are set up. + var/tmp/list/deferredSetupList = new + + var/tmp/currentTick = 0 + + var/tmp/currentTickStart = 0 + + var/tmp/timeAllowance = 0 + + var/tmp/cpuAverage = 0 + + var/tmp/timeAllowanceMax = 0 + +/datum/controller/processScheduler/New() + ..() + // When the process scheduler is first new'd, tick_lag may be wrong, so these + // get re-initialized when the process scheduler is started. + // (These are kept here for any processes that decide to process before round start) + scheduler_sleep_interval = world.tick_lag + timeAllowance = world.tick_lag * 0.5 + timeAllowanceMax = world.tick_lag + +/** + * deferSetupFor + * @param path processPath + * If a process needs to be initialized after everything else, add it to + * the deferred setup list. On goonstation, only the ticker needs to have + * this treatment. + */ +/datum/controller/processScheduler/proc/deferSetupFor(var/processPath) + if (!(processPath in deferredSetupList)) + deferredSetupList += processPath + +/datum/controller/processScheduler/proc/setup() + // There can be only one + if(processScheduler && (processScheduler != src)) + del(src) + return 0 + + var/process + // Add all the processes we can find, except for the ticker + for (process in subtypesof(/datum/controller/process)) + if (!(process in deferredSetupList)) + addProcess(new process(src)) + + for (process in deferredSetupList) + addProcess(new process(src)) + +/datum/controller/processScheduler/proc/start() + isRunning = 1 + // tick_lag will have been set by now, so re-initialize these + scheduler_sleep_interval = world.tick_lag + timeAllowance = world.tick_lag * 0.5 + timeAllowanceMax = world.tick_lag + updateStartDelays() + spawn(0) + process() + +/datum/controller/processScheduler/proc/process() + updateCurrentTickData() + + for(var/i=world.tick_lag,i= last_queued[p] + p.schedule_interval) + setQueuedProcessState(p) + +/datum/controller/processScheduler/proc/runQueuedProcesses() + for(var/datum/controller/process/p in queued) + runProcess(p) + +/datum/controller/processScheduler/proc/addProcess(var/datum/controller/process/process) + processes.Add(process) + process.idle() + idle.Add(process) + + // init recordkeeping vars + last_start.Add(process) + last_start[process] = 0 + last_run_time.Add(process) + last_run_time[process] = 0 + last_twenty_run_times.Add(process) + last_twenty_run_times[process] = list() + highest_run_time.Add(process) + highest_run_time[process] = 0 + + // init starts and stops record starts + recordStart(process, 0) + recordEnd(process, 0) + + // Set up process + process.setup() + + // Save process in the name -> process map + nameToProcessMap[process.name] = process + +/datum/controller/processScheduler/proc/replaceProcess(var/datum/controller/process/oldProcess, var/datum/controller/process/newProcess) + processes.Remove(oldProcess) + processes.Add(newProcess) + + newProcess.idle() + idle.Remove(oldProcess) + running.Remove(oldProcess) + queued.Remove(oldProcess) + idle.Add(newProcess) + + last_start.Remove(oldProcess) + last_start.Add(newProcess) + last_start[newProcess] = 0 + + last_run_time.Add(newProcess) + last_run_time[newProcess] = last_run_time[oldProcess] + last_run_time.Remove(oldProcess) + + last_twenty_run_times.Add(newProcess) + last_twenty_run_times[newProcess] = last_twenty_run_times[oldProcess] + last_twenty_run_times.Remove(oldProcess) + + highest_run_time.Add(newProcess) + highest_run_time[newProcess] = highest_run_time[oldProcess] + highest_run_time.Remove(oldProcess) + + recordStart(newProcess, 0) + recordEnd(newProcess, 0) + + nameToProcessMap[newProcess.name] = newProcess + +/datum/controller/processScheduler/proc/updateStartDelays() + for(var/datum/controller/process/p in processes) + if(p.start_delay) + last_queued[p] = world.time - p.start_delay + +/datum/controller/processScheduler/proc/runProcess(var/datum/controller/process/process) + spawn(0) + process.process() + +/datum/controller/processScheduler/proc/processStarted(var/datum/controller/process/process) + setRunningProcessState(process) + recordStart(process) + +/datum/controller/processScheduler/proc/processFinished(var/datum/controller/process/process) + setIdleProcessState(process) + recordEnd(process) + +/datum/controller/processScheduler/proc/setIdleProcessState(var/datum/controller/process/process) + if (process in running) + running -= process + if (process in queued) + queued -= process + if (!(process in idle)) + idle += process + +/datum/controller/processScheduler/proc/setQueuedProcessState(var/datum/controller/process/process) + if (process in running) + running -= process + if (process in idle) + idle -= process + if (!(process in queued)) + queued += process + + // The other state transitions are handled internally by the process. + process.queued() + +/datum/controller/processScheduler/proc/setRunningProcessState(var/datum/controller/process/process) + if (process in queued) + queued -= process + if (process in idle) + idle -= process + if (!(process in running)) + running += process + +/datum/controller/processScheduler/proc/recordStart(var/datum/controller/process/process, var/time = null) + if (isnull(time)) + time = TimeOfHour + last_queued[process] = world.time + last_start[process] = time + else + last_queued[process] = (time == 0 ? 0 : world.time) + last_start[process] = time + +/datum/controller/processScheduler/proc/recordEnd(var/datum/controller/process/process, var/time = null) + if (isnull(time)) + time = TimeOfHour + + // If world.timeofday has rolled over, then we need to adjust. + if (time < last_start[process]) + last_start[process] -= 36000 + + var/lastRunTime = time - last_start[process] + + if(lastRunTime < 0) + lastRunTime = 0 + + recordRunTime(process, lastRunTime) + +/** + * recordRunTime + * Records a run time for a process + */ +/datum/controller/processScheduler/proc/recordRunTime(var/datum/controller/process/process, time) + last_run_time[process] = time + if(time > highest_run_time[process]) + highest_run_time[process] = time + + var/list/lastTwenty = last_twenty_run_times[process] + if (lastTwenty.len == 20) + lastTwenty.Cut(1, 2) + lastTwenty.len++ + lastTwenty[lastTwenty.len] = time + +/** + * averageRunTime + * returns the average run time (over the last 20) of the process + */ +/datum/controller/processScheduler/proc/averageRunTime(var/datum/controller/process/process) + var/lastTwenty = last_twenty_run_times[process] + + var/t = 0 + var/c = 0 + for(var/time in lastTwenty) + t += time + c++ + + if(c > 0) + return t / c + return c + +/datum/controller/processScheduler/proc/getProcessLastRunTime(var/datum/controller/process/process) + return last_run_time[process] + +/datum/controller/processScheduler/proc/getProcessHighestRunTime(var/datum/controller/process/process) + return highest_run_time[process] + +/datum/controller/processScheduler/proc/getStatusData() + var/list/data = new + + for (var/datum/controller/process/p in processes) + data.len++ + data[data.len] = p.getContextData() + + return data + +/datum/controller/processScheduler/proc/getProcessCount() + return processes.len + +/datum/controller/processScheduler/proc/hasProcess(var/processName as text) + if (nameToProcessMap[processName]) + return 1 + +/datum/controller/processScheduler/proc/killProcess(var/processName as text) + restartProcess(processName) + +/datum/controller/processScheduler/proc/restartProcess(var/processName as text) + if (hasProcess(processName)) + var/datum/controller/process/oldInstance = nameToProcessMap[processName] + var/datum/controller/process/newInstance = new oldInstance.type(src) + newInstance._copyStateFrom(oldInstance) + replaceProcess(oldInstance, newInstance) + oldInstance.kill() + +/datum/controller/processScheduler/proc/enableProcess(var/processName as text) + if (hasProcess(processName)) + var/datum/controller/process/process = nameToProcessMap[processName] + process.enable() + +/datum/controller/processScheduler/proc/disableProcess(var/processName as text) + if (hasProcess(processName)) + var/datum/controller/process/process = nameToProcessMap[processName] + process.disable() + +/datum/controller/processScheduler/proc/getCurrentTickElapsedTime() + if (world.time > currentTick) + updateCurrentTickData() + return 0 + else + return TimeOfHour - currentTickStart + +/datum/controller/processScheduler/proc/updateCurrentTickData() + if (world.time > currentTick) + // New tick! + currentTick = world.time + currentTickStart = TimeOfHour + updateTimeAllowance() + cpuAverage = (world.cpu + cpuAverage + cpuAverage) / 3 + +/datum/controller/processScheduler/proc/updateTimeAllowance() + // Time allowance goes down linearly with world.cpu. + var/tmp/error = cpuAverage - 100 + var/tmp/timeAllowanceDelta = sign(error) * -0.5 * world.tick_lag * max(0, 0.001 * abs(error)) + + //timeAllowance = world.tick_lag * min(1, 0.5 * ((200/max(1,cpuAverage)) - 1)) + timeAllowance = min(timeAllowanceMax, max(0, timeAllowance + timeAllowanceDelta)) + +/datum/controller/processScheduler/proc/sign(var/x) + if (x == 0) + return 1 + return x / abs(x) + +/datum/controller/processScheduler/proc/statProcesses() + if(!isRunning) + stat("Processes", "Scheduler not running") + return + stat("Processes", "[processes.len] (R [running.len] / Q [queued.len] / I [idle.len])") + stat(null, "[round(cpuAverage, 0.1)] CPU, [round(timeAllowance, 0.1)/10] TA") + for(var/datum/controller/process/p in processes) + p.statProcess() diff --git a/code/controllers/ProcessScheduler/core/updateQueue.dm b/code/controllers/ProcessScheduler/core/updateQueue.dm deleted file mode 100644 index 118b6692b5a..00000000000 --- a/code/controllers/ProcessScheduler/core/updateQueue.dm +++ /dev/null @@ -1,127 +0,0 @@ -/** - * updateQueue.dm - */ - -#ifdef UPDATE_QUEUE_DEBUG -#define uq_dbg(text) world << text -#else -#define uq_dbg(text) -#endif -/datum/updateQueue - var/tmp/list/objects - var/tmp/previousStart - var/tmp/procName - var/tmp/list/arguments - var/tmp/datum/updateQueueWorker/currentWorker - var/tmp/workerTimeout - var/tmp/adjustedWorkerTimeout - var/tmp/currentKillCount - var/tmp/totalKillCount - -/datum/updateQueue/New(list/objects = list(), procName = "update", list/arguments = list(), workerTimeout = 2, inplace = 0) - ..() - - uq_dbg("Update queue created.") - - // Init proc allows for recycling the worker. - init(objects = objects, procName = procName, arguments = arguments, workerTimeout = workerTimeout, inplace = inplace) - -/** - * init - * @param list objects objects to update - * @param text procName the proc to call on each item in the object list - * @param list arguments optional arguments to pass to the update proc - * @param number workerTimeout number of ticks to wait for an update to - finish before forking a new update worker - * @param bool inplace whether the updateQueue should make a copy of objects. - the internal list will be modified, so it is usually - a good idea to leave this alone. Default behavior is to - copy. - */ -/datum/updateQueue/proc/init(list/objects = list(), procName = "update", list/arguments = list(), workerTimeout = 2, inplace = 0) - uq_dbg("Update queue initialization started.") - - if (!inplace) - // Make an internal copy of the list so we're not modifying the original. - initList(objects) - else - src.objects = objects - - // Init vars - src.procName = procName - src.arguments = arguments - src.workerTimeout = workerTimeout - - adjustedWorkerTimeout = workerTimeout - currentKillCount = 0 - totalKillCount = 0 - - uq_dbg("Update queue initialization finished. procName = '[procName]'") - -/datum/updateQueue/proc/initList(list/toCopy) - /** - * We will copy the list in reverse order, as our doWork proc - * will access them by popping an element off the end of the list. - * This ends up being quite a lot faster than taking elements off - * the head of the list. - */ - objects = new - - uq_dbg("Copying [toCopy.len] items for processing.") - - for(var/i=toCopy.len,i>0,) - objects.len++ - objects[objects.len] = toCopy[i--] - -/datum/updateQueue/proc/Run() - uq_dbg("Starting run...") - - startWorker() - while (istype(currentWorker) && !currentWorker.finished) - sleep(2) - checkWorker() - - uq_dbg("UpdateQueue completed run.") - -/datum/updateQueue/proc/checkWorker() - if(istype(currentWorker)) - // If world.timeofday has rolled over, then we need to adjust. - if(world.timeofday < currentWorker.lastStart) - currentWorker.lastStart -= 864000 - - if(world.timeofday - currentWorker.lastStart > adjustedWorkerTimeout) - // This worker is a bit slow, let's spawn a new one and kill the old one. - uq_dbg("Current worker is lagging... starting a new one.") - killWorker() - startWorker() - else // No worker! - uq_dbg("update queue ended up without a worker... starting a new one...") - startWorker() - -/datum/updateQueue/proc/startWorker() - // only run the worker if we have objects to work on - if(objects.len) - uq_dbg("Starting worker process.") - - // No need to create a fresh worker if we already have one... - if (istype(currentWorker)) - currentWorker.init(objects, procName, arguments) - else - currentWorker = new(objects, procName, arguments) - currentWorker.start() - else - uq_dbg("Queue is empty. No worker was started.") - currentWorker = null - -/datum/updateQueue/proc/killWorker() - // Kill the worker - currentWorker.kill() - currentWorker = null - // After we kill a worker, yield so that if the worker's been tying up the cpu, other stuff can immediately resume - sleep(-1) - currentKillCount++ - totalKillCount++ - if (currentKillCount >= 3) - uq_dbg("[currentKillCount] workers have been killed with a timeout of [adjustedWorkerTimeout]. Increasing worker timeout to compensate.") - adjustedWorkerTimeout++ - currentKillCount = 0 \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/core/updateQueueWorker.dm b/code/controllers/ProcessScheduler/core/updateQueueWorker.dm deleted file mode 100644 index 66f66bbcc01..00000000000 --- a/code/controllers/ProcessScheduler/core/updateQueueWorker.dm +++ /dev/null @@ -1,83 +0,0 @@ -datum/updateQueueWorker - var/tmp/list/objects - var/tmp/killed - var/tmp/finished - var/tmp/procName - var/tmp/list/arguments - var/tmp/lastStart - var/tmp/cpuThreshold - -datum/updateQueueWorker/New(var/list/objects, var/procName, var/list/arguments, var/cpuThreshold = 90) - ..() - uq_dbg("updateQueueWorker created.") - - init(objects, procName, arguments, cpuThreshold) - -datum/updateQueueWorker/proc/init(var/list/objects, var/procName, var/list/arguments, var/cpuThreshold = 90) - src.objects = objects - src.procName = procName - src.arguments = arguments - src.cpuThreshold = cpuThreshold - - killed = 0 - finished = 0 - -datum/updateQueueWorker/proc/doWork() - // If there's nothing left to execute or we were killed, mark finished and return. - if (!objects || !objects.len) return finished() - - lastStart = world.timeofday // Absolute number of ticks since the world started up - - var/datum/object = objects[objects.len] // Pull out the object - objects.len-- // Remove the object from the list - - if (istype(object) && !isturf(object) && !object.disposed && isnull(object.gcDestroyed)) // We only work with real objects - call(object, procName)(arglist(arguments)) - - // If there's nothing left to execute - // or we were killed while running the above code, mark finished and return. - if (!objects || !objects.len) return finished() - - if (world.cpu > cpuThreshold) - // We don't want to force a tick into overtime! - // If the tick is about to go overtime, spawn the next update to go - // in the next tick. - uq_dbg("tick went into overtime with world.cpu = [world.cpu], deferred next update to next tick [1+(world.time / world.tick_lag)]") - - spawn(1) - doWork() - else - spawn(0) // Execute anonymous function immediately as if we were in a while loop... - doWork() - -datum/updateQueueWorker/proc/finished() - uq_dbg("updateQueueWorker finished.") - /** - * If the worker was killed while it was working on something, it - * should delete itself when it finally finishes working on it. - * Meanwhile, the updateQueue will have proceeded on with the rest of - * the queue. This will also terminate the spawned function that was - * created in the kill() proc. - */ - if(killed) - del(src) - - finished = 1 - -datum/updateQueueWorker/proc/kill() - uq_dbg("updateQueueWorker killed.") - killed = 1 - objects = null - - /** - * If the worker is not done in 30 seconds after it's killed, - * we'll forcibly delete it, causing the anonymous function it was - * running to be terminated. Hasta la vista, baby. - */ - spawn(300) - del(src) - -datum/updateQueueWorker/proc/start() - uq_dbg("updateQueueWorker started.") - spawn(0) - doWork() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/processSchedulerView.dm b/code/controllers/ProcessScheduler/test/processSchedulerView.dm deleted file mode 100644 index ae78b3f0154..00000000000 --- a/code/controllers/ProcessScheduler/test/processSchedulerView.dm +++ /dev/null @@ -1,94 +0,0 @@ -/datum/processSchedulerView - -/datum/processSchedulerView/Topic(href, href_list) - if (!href_list["action"]) - return - - switch (href_list["action"]) - if ("kill") - var/toKill = href_list["name"] - processScheduler.killProcess(toKill) - refreshProcessTable() - if ("enable") - var/toEnable = href_list["name"] - processScheduler.enableProcess(toEnable) - refreshProcessTable() - if ("disable") - var/toDisable = href_list["name"] - processScheduler.disableProcess(toDisable) - refreshProcessTable() - if ("refresh") - refreshProcessTable() - -/datum/processSchedulerView/proc/refreshProcessTable() - windowCall("handleRefresh", getProcessTable()) - -/datum/processSchedulerView/proc/windowCall(var/function, var/data = null) - usr << output(data, "processSchedulerContext.browser:[function]") - -/datum/processSchedulerView/proc/getProcessTable() - var/text = "" - // and the context of each - for (var/list/data in processScheduler.getStatusData()) - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - text += "" - - text += "
NameAvg(s)Last(s)Highest(s)TickcountTickrateStateAction
[data["name"]][num2text(data["averageRunTime"]/10,3)][num2text(data["lastRunTime"]/10,3)][num2text(data["highestRunTime"]/10,3)][num2text(data["ticks"],4)][data["schedule"]][data["status"]]" - if (data["disabled"]) - text += "" - else - text += "" - text += "
" - return text - -/** - * getContext - * Outputs an interface showing stats for all processes. - */ -/datum/processSchedulerView/proc/getContext() - bootstrap_browse() - usr << browse('processScheduler.js', "file=processScheduler.js;display=0") - - var/text = {" - Process Scheduler Detail - - [bootstrap_includes()] - - - -

Process Scheduler

-
- -
- -

The process scheduler controls [processScheduler.getProcessCount()] loops.

"} - - text += "
" - text += getProcessTable() - text += "
" - - usr << browse(text, "window=processSchedulerContext;size=800x600") - -/datum/processSchedulerView/proc/bootstrap_browse() - usr << browse('bower_components/jquery/dist/jquery.min.js', "file=jquery.min.js;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/js/bootstrap.min.js', "file=bootstrap.min.js;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/css/bootstrap.min.css', "file=bootstrap.min.css;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/img/glyphicons-halflings-white.png', "file=glyphicons-halflings-white.png;display=0") - usr << browse('bower_components/bootstrap2.3.2/bootstrap/img/glyphicons-halflings.png', "file=glyphicons-halflings.png;display=0") - usr << browse('bower_components/json2/json2.js', "file=json2.js;display=0") - -/datum/processSchedulerView/proc/bootstrap_includes() - return {" - - - - - "} diff --git a/code/controllers/ProcessScheduler/test/testDyingUpdateQueueProcess.dm b/code/controllers/ProcessScheduler/test/testDyingUpdateQueueProcess.dm deleted file mode 100644 index d08ec46c7da..00000000000 --- a/code/controllers/ProcessScheduler/test/testDyingUpdateQueueProcess.dm +++ /dev/null @@ -1,27 +0,0 @@ -/** - * testDyingUpdateQueueProcess - * This process is an example of a process using an updateQueue. - * The datums updated by this process behave badly and block the update loop - * by sleeping. If you #define UPDATE_QUEUE_DEBUG, you will see the updateQueue - * killing off its worker processes and spawning new ones to work around slow - * updates. This means that if you have a code path that sleeps for a long time - * in mob.Life once in a blue moon, the mob update loop will not hang. - */ -/datum/slowTestDatum/proc/wackyUpdateProcessName() - sleep(rand(0,20)) // Randomly REALLY slow :| - -/datum/controller/process/testDyingUpdateQueueProcess - var/tmp/datum/updateQueue/updateQueueInstance - var/tmp/list/testDatums = list() - -/datum/controller/process/testDyingUpdateQueueProcess/setup() - name = "Dying UpdateQueue Process" - schedule_interval = 30 // every 3 seconds - updateQueueInstance = new - for(var/i = 1, i < 30, i++) - testDatums.Add(new /datum/slowTestDatum) - -/datum/controller/process/testDyingUpdateQueueProcess/doWork() - updateQueueInstance.init(testDatums, "wackyUpdateProcessName") - updateQueueInstance.Run() - \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testHarness.dm b/code/controllers/ProcessScheduler/test/testHarness.dm deleted file mode 100644 index 2b5f1dff813..00000000000 --- a/code/controllers/ProcessScheduler/test/testHarness.dm +++ /dev/null @@ -1,35 +0,0 @@ -/* - These are simple defaults for your project. - */ -#define DEBUG - -var/global/datum/processSchedulerView/processSchedulerView - -world - loop_checks = 0 - New() - ..() - processScheduler = new - processSchedulerView = new - -mob - step_size = 8 - - New() - ..() - - - verb - startProcessScheduler() - set name = "Start Process Scheduler" - processScheduler.setup() - processScheduler.start() - - getProcessSchedulerContext() - set name = "Get Process Scheduler Status Panel" - processSchedulerView.getContext() - - runUpdateQueueTests() - set name = "Run Update Queue Testsuite" - var/datum/updateQueueTests/t = new - t.runTests() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testHungProcess.dm b/code/controllers/ProcessScheduler/test/testHungProcess.dm deleted file mode 100644 index ced05dd4d70..00000000000 --- a/code/controllers/ProcessScheduler/test/testHungProcess.dm +++ /dev/null @@ -1,15 +0,0 @@ -/** - * testHungProcess - * This process is an example of a simple update loop process that hangs. - */ - -/datum/controller/process/testHungProcess/setup() - name = "Hung Process" - schedule_interval = 30 // every 3 seconds - -/datum/controller/process/testHungProcess/doWork() - sleep(1000) // FUCK - // scheck is also responsible for handling hung processes. If a process - // hangs, and later resumes, but has already been killed by the scheduler, - // scheck will force the process to bail out. - scheck() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testNiceProcess.dm b/code/controllers/ProcessScheduler/test/testNiceProcess.dm deleted file mode 100644 index aa921bc62fa..00000000000 --- a/code/controllers/ProcessScheduler/test/testNiceProcess.dm +++ /dev/null @@ -1,13 +0,0 @@ -/** - * testNiceProcess - * This process is an example of a simple update loop process that is - * relatively fast. - */ - -/datum/controller/process/testNiceProcess/setup() - name = "Nice Process" - schedule_interval = 10 // every second - -/datum/controller/process/testNiceProcess/doWork() - sleep(rand(1,5)) // Just to pretend we're doing something - \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testSlowProcess.dm b/code/controllers/ProcessScheduler/test/testSlowProcess.dm deleted file mode 100644 index b7c9e6e21e8..00000000000 --- a/code/controllers/ProcessScheduler/test/testSlowProcess.dm +++ /dev/null @@ -1,28 +0,0 @@ -/** - * testSlowProcess - * This process is an example of a simple update loop process that is slow. - * The update loop here sleeps inside to provide an example, but if you had - * a computationally intensive loop process that is simply slow, you can use - * scheck() inside the loop to force it to yield periodically according to - * the sleep_interval var. By default, scheck will cause a loop to sleep every - * 2 ticks. - */ - -/datum/controller/process/testSlowProcess/setup() - name = "Slow Process" - schedule_interval = 30 // every 3 seconds - -/datum/controller/process/testSlowProcess/doWork() - // set background = 1 will cause loop constructs to sleep periodically, - // whenever the BYOND scheduler deems it productive to do so. - // This behavior is not always sufficient, nor is it always consistent. - // Rather than leaving it up to the BYOND scheduler, we can control it - // ourselves and leave nothing to the black box. - set background = 1 - - for(var/i=1,i<30,i++) - // Just to pretend we're doing something here - sleep(rand(3, 5)) - - // Forces this loop to yield(sleep) periodically. - scheck() \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/test/testUpdateQueue.dm b/code/controllers/ProcessScheduler/test/testUpdateQueue.dm deleted file mode 100644 index 07b64e927f3..00000000000 --- a/code/controllers/ProcessScheduler/test/testUpdateQueue.dm +++ /dev/null @@ -1,209 +0,0 @@ -var/global/list/updateQueueTestCount = list() - -/datum/updateQueueTests - var/start - proc - runTests() - world << "Running 9 tests..." - testUpdateQueuePerformance() - sleep(1) - testInplace() - sleep(1) - testInplaceUpdateQueuePerformance() - sleep(1) - testUpdateQueueReinit() - sleep(1) - testCrashingQueue() - sleep(1) - testEmptyQueue() - sleep(1) - testManySlowItemsInQueue() - sleep(1) - testVariableWorkerTimeout() - sleep(1) - testReallySlowItemInQueue() - sleep(1) - world << "Finished!" - - beginTiming() - start = world.time - - endTiming(text) - var/time = (world.time - start) / world.tick_lag - world << {"Performance - [text] - [time] ticks"} - - getCount() - return updateQueueTestCount[updateQueueTestCount.len] - - incrementTestCount() - updateQueueTestCount.len++ - updateQueueTestCount[updateQueueTestCount.len] = 0 - - assertCountEquals(count, text) - assertThat(getCount() == count, text) - - assertCountLessThan(count, text) - assertThat(getCount() < count, text) - - assertCountGreaterThan(count, text) - assertThat(getCount() > count, text) - - assertThat(condition, text) - if (condition) - world << {"PASS: [text]"} - else - world << {"FAIL: [text]"} - - testUpdateQueuePerformance() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100000,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - - beginTiming() - uq.Run() - endTiming("updating 100000 simple objects") - - assertCountEquals(100000, "test that update queue updates all objects expected") - del(objs) - del(uq) - - testUpdateQueueReinit() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - uq.Run() - objs = new - - for(var/i=1,i<=100,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - uq.init(objs) - uq.Run() - assertCountEquals(200, "test that update queue reinitializes properly and updates all objects as expected.") - del(objs) - del(uq) - - testInplace() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objects = objs, inplace = 1) - uq.Run() - assertThat(objs.len == 0, "test that update queue inplace option really works inplace") - assertCountEquals(100, "test that inplace update queue updates the right number of objects") - del(objs) - del(uq) - - testInplaceUpdateQueuePerformance() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=100000,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - - beginTiming() - uq.Run() - endTiming("updating 100000 simple objects in place") - del(objs) - del(uq) - - testCrashingQueue() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - objs.Add(new /datum/uqTestDatum/crasher(updateQueueTestCount.len)) - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(20, "test that update queue handles crashed update procs OK") - del(objs) - del(uq) - - testEmptyQueue() - incrementTestCount() - var/list/objs = new - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(0, "test that update queue doesn't barf on empty lists") - del(objs) - del(uq) - - testManySlowItemsInQueue() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=30,i++) - objs.Add(new /datum/uqTestDatum/slow(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(30, "test that update queue slows down execution if too many objects are slow to update") - del(objs) - del(uq) - - testVariableWorkerTimeout() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=20,i++) - objs.Add(new /datum/uqTestDatum/slow(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objs, workerTimeout=6) - uq.Run() - assertCountEquals(20, "test that variable worker timeout works properly") - del(objs) - del(uq) - - testReallySlowItemInQueue() - incrementTestCount() - var/list/objs = new - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - objs.Add(new /datum/uqTestDatum/reallySlow(updateQueueTestCount.len)) - for(var/i=1,i<=10,i++) - objs.Add(new /datum/uqTestDatum/fast(updateQueueTestCount.len)) - var/datum/updateQueue/uq = new(objs) - uq.Run() - assertCountEquals(20, "test that update queue skips objects that are too slow to update") - del(objs) - del(uq) - - - -datum/uqTestDatum - var/testNum - New(testNum) - ..() - src.testNum = testNum - proc/update() - updateQueueTestCount[testNum]++ - proc/lag(cycles) - set background = 1 - for(var/i=0,i= 0) - if(dels >= maxDels) + if(remaining_force_dels <= 0) #ifdef GC_DEBUG testing("GC: Reached max force dels per tick [dels] vs [maxDels]") #endif @@ -88,13 +94,22 @@ world/loop_checks = 0 testing("GC: -- \ref[A] | [A.type] was unable to be GC'd and was deleted --") logging["[A.type]"]++ del(A) - ++dels - ++hard_dels - #ifdef GC_DEBUG + + hard_dels++ + remaining_force_dels-- else + #ifdef GC_DEBUG testing("GC: [refID] properly GC'd at [world.time] with timeout [GCd_at_time]") - #endif + #endif + soft_dels++ + tick_dels++ + total_dels++ destroyed.Cut(1, 2) + SCHECK + +#undef GC_FORCE_DEL_PER_TICK +#undef GC_COLLECTION_TIMEOUT +#undef GC_COLLECTIONS_PER_TICK #ifdef GC_FINDREF /datum/controller/process/garbage_collector/proc/LookForRefs(var/datum/D, var/list/targ) @@ -132,8 +147,11 @@ world/loop_checks = 0 destroyed -= "\ref[A]" // Removing any previous references that were GC'd so that the current object will be at the end of the list. destroyed["\ref[A]"] = world.time -/datum/controller/process/garbage_collector/getStatName() - return ..()+"([garbage_collector.destroyed.len]/[garbage_collector.dels]/[garbage_collector.hard_dels])" +/datum/controller/process/garbage_collector/statProcess() + ..() + stat(null, "[garbage_collect ? "On" : "Off"], [destroyed.len] queued") + stat(null, "Dels: [total_dels], [soft_dels] soft, [hard_dels] hard, [tick_dels] last run") + // Tests if an atom has been deleted. /proc/deleted(atom/A) @@ -149,7 +167,7 @@ world/loop_checks = 0 crash_with("qdel() passed object of type [A.type]. qdel() can only handle /datum types.") del(A) if(garbage_collector) - garbage_collector.dels++ + garbage_collector.total_dels++ garbage_collector.hard_dels++ else if(isnull(A.gcDestroyed)) // Let our friend know they're about to get collected diff --git a/code/controllers/Processes/inactivity.dm b/code/controllers/Processes/inactivity.dm index cd01e24829a..6ec07aebd3e 100644 --- a/code/controllers/Processes/inactivity.dm +++ b/code/controllers/Processes/inactivity.dm @@ -10,4 +10,4 @@ log_access("AFK: [key_name(C)]") C << "You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected." del(C) // Don't qdel, cannot override finalize_qdel behaviour for clients. - scheck() + SCHECK diff --git a/code/controllers/Processes/lighting.dm b/code/controllers/Processes/lighting.dm index 9399fe0253d..519b860d539 100644 --- a/code/controllers/Processes/lighting.dm +++ b/code/controllers/Processes/lighting.dm @@ -1,5 +1,6 @@ /datum/controller/process/lighting/setup() name = "lighting" + start_delay = 1 schedule_interval = 5 // every .5 second lighting_controller.initializeLighting() diff --git a/code/controllers/Processes/machinery.dm b/code/controllers/Processes/machinery.dm index 7959ee4fa7b..c31f1bc7726 100644 --- a/code/controllers/Processes/machinery.dm +++ b/code/controllers/Processes/machinery.dm @@ -3,6 +3,7 @@ /datum/controller/process/machinery/setup() name = "machinery" schedule_interval = 20 // every 2 seconds + start_delay = 12 /datum/controller/process/machinery/doWork() internal_sort() @@ -19,10 +20,6 @@ /datum/controller/process/machinery/proc/internal_process_machinery() for(var/obj/machinery/M in machines) if(M && !M.gcDestroyed) - #ifdef PROFILE_MACHINES - var/time_start = world.timeofday - #endif - if(M.process() == PROCESS_KILL) //M.inMachineList = 0 We don't use this debugging function machines.Remove(M) @@ -31,22 +28,13 @@ if(M && M.use_power) M.auto_use_power() - #ifdef PROFILE_MACHINES - var/time_end = world.timeofday - - if(!(M.type in machine_profiling)) - machine_profiling[M.type] = 0 - - machine_profiling[M.type] += (time_end - time_start) - #endif - - scheck() + SCHECK /datum/controller/process/machinery/proc/internal_process_power() for(var/datum/powernet/powerNetwork in powernets) - if(istype(powerNetwork) && !powerNetwork.disposed) + if(istype(powerNetwork) && isnull(powerNetwork.gcDestroyed)) powerNetwork.reset() - scheck() + SCHECK continue powernets.Remove(powerNetwork) @@ -56,16 +44,20 @@ for(var/obj/item/I in processing_power_items) if(!I.pwr_drain()) // 0 = Process Kill, remove from processing list. processing_power_items.Remove(I) - scheck() + SCHECK /datum/controller/process/machinery/proc/internal_process_pipenets() for(var/datum/pipe_network/pipeNetwork in pipe_networks) - if(istype(pipeNetwork) && !pipeNetwork.disposed) + if(istype(pipeNetwork) && isnull(pipeNetwork.gcDestroyed)) pipeNetwork.process() - scheck() + SCHECK continue pipe_networks.Remove(pipeNetwork) -/datum/controller/process/machinery/getStatName() - return ..()+"(MCH:[machines.len] PWR:[powernets.len] PIP:[pipe_networks.len])" +/datum/controller/process/machinery/statProcess() + ..() + stat(null, "[machines.len] machines") + stat(null, "[powernets.len] powernets") + stat(null, "[pipe_networks.len] pipenets") + stat(null, "[processing_power_items.len] power item\s") diff --git a/code/controllers/Processes/mob.dm b/code/controllers/Processes/mob.dm index 39d4844a021..acc15bff0be 100644 --- a/code/controllers/Processes/mob.dm +++ b/code/controllers/Processes/mob.dm @@ -4,20 +4,26 @@ /datum/controller/process/mob/setup() name = "mob" schedule_interval = 20 // every 2 seconds - updateQueueInstance = new + start_delay = 16 /datum/controller/process/mob/started() ..() - if(!updateQueueInstance) - if(!mob_list) - mob_list = list() - else if(mob_list.len) - updateQueueInstance = new + if(!mob_list) + mob_list = list() /datum/controller/process/mob/doWork() - if(updateQueueInstance) - updateQueueInstance.init(mob_list, "Life") - updateQueueInstance.Run() + for(last_object in mob_list) + var/mob/M = last_object + if(isnull(M.gcDestroyed)) + try + M.Life() + catch(var/exception/e) + catchException(e, M) + SCHECK + else + catchBadType(M) + mob_list -= M -/datum/controller/process/mob/getStatName() - return ..()+"([mob_list.len])" +/datum/controller/process/mob/statProcess() + ..() + stat(null, "[mob_list.len] mobs") diff --git a/code/controllers/Processes/nanoui.dm b/code/controllers/Processes/nanoui.dm index 654b1621be5..1667af943da 100644 --- a/code/controllers/Processes/nanoui.dm +++ b/code/controllers/Processes/nanoui.dm @@ -1,14 +1,19 @@ -/datum/controller/process/nanoui - var/tmp/datum/updateQueue/updateQueueInstance - /datum/controller/process/nanoui/setup() name = "nanoui" - schedule_interval = 10 // every 1 second - updateQueueInstance = new + schedule_interval = 20 // every 2 seconds + +/datum/controller/process/nanoui/statProcess() + ..() + stat(null, "[nanomanager.processing_uis.len] UIs") /datum/controller/process/nanoui/doWork() - updateQueueInstance.init(nanomanager.processing_uis, "process") - updateQueueInstance.Run() - -/datum/controller/process/nanoui/getStatName() - return ..()+"([nanomanager.processing_uis.len])" + for(last_object in nanomanager.processing_uis) + var/datum/nanoui/NUI = last_object + if(istype(NUI) && isnull(NUI.gcDestroyed)) + try + NUI.process() + catch(var/exception/e) + catchException(e, NUI) + else + catchBadType(NUI) + nanomanager.processing_uis -= NUI diff --git a/code/controllers/Processes/obj.dm b/code/controllers/Processes/obj.dm index 37766cf92d1..b3f52a9bcfc 100644 --- a/code/controllers/Processes/obj.dm +++ b/code/controllers/Processes/obj.dm @@ -1,24 +1,26 @@ -var/global/list/object_profiling = list() -/datum/controller/process/obj - var/tmp/datum/updateQueue/updateQueueInstance - /datum/controller/process/obj/setup() name = "obj" schedule_interval = 20 // every 2 seconds - updateQueueInstance = new + start_delay = 8 /datum/controller/process/obj/started() ..() - if(!updateQueueInstance) - if(!processing_objects) - processing_objects = list() - else if(processing_objects.len) - updateQueueInstance = new + if(!processing_objects) + processing_objects = list() /datum/controller/process/obj/doWork() - if(updateQueueInstance) - updateQueueInstance.init(processing_objects, "process") - updateQueueInstance.Run() + for(last_object in processing_objects) + var/datum/O = last_object + if(isnull(O.gcDestroyed)) + try + O:process() + catch(var/exception/e) + catchException(e, O) + SCHECK + else + catchBadType(O) + processing_objects -= O -/datum/controller/process/obj/getStatName() - return ..()+"([processing_objects.len])" +/datum/controller/process/obj/statProcess() + ..() + stat(null, "[processing_objects.len] objects") diff --git a/code/controllers/Processes/turf.dm b/code/controllers/Processes/turf.dm index 2ac33f48ba7..fd36a6900fd 100644 --- a/code/controllers/Processes/turf.dm +++ b/code/controllers/Processes/turf.dm @@ -8,7 +8,8 @@ var/global/list/turf/processing_turfs = list() for(var/turf/T in processing_turfs) if(T.process() == PROCESS_KILL) processing_turfs.Remove(T) - scheck() + SCHECK -/datum/controller/process/turf/getStatName() - return ..()+"([processing_turfs.len])" +/datum/controller/process/turf/statProcess() + ..() + stat(null, "[processing_turfs.len] turf\s") diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 17e45736c05..2200ab965cf 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -21,6 +21,7 @@ var/list/gamemode_cache = list() var/log_pda = 0 // log pda messages var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits var/log_runtime = 0 // logs world.log to a file + var/log_world_output = 0 // log world.log << messages var/sql_enabled = 1 // for sql switching var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour var/allow_vote_restart = 0 // allow votes to restart @@ -319,6 +320,9 @@ var/list/gamemode_cache = list() if ("log_pda") config.log_pda = 1 + if ("log_world_output") + config.log_world_output = 1 + if ("log_hrefs") config.log_hrefs = 1 diff --git a/code/controllers/subsystem/alarms.dm b/code/controllers/subsystem/alarms.dm deleted file mode 100644 index b05be7ccbfb..00000000000 --- a/code/controllers/subsystem/alarms.dm +++ /dev/null @@ -1,30 +0,0 @@ -// We manually initialize the alarm handlers instead of looping over all existing types -// to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof. -/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new() -/var/global/datum/alarm_handler/camera/camera_alarm = new() -/var/global/datum/alarm_handler/fire/fire_alarm = new() -/var/global/datum/alarm_handler/motion/motion_alarm = new() -/var/global/datum/alarm_handler/power/power_alarm = new() - -/datum/subsystem/alarm - name = "Alarm" - var/list/datum/alarm/all_handlers - -/datum/subsystem/alarm/New() - all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm) - -/datum/subsystem/alarm/fire() - for(var/datum/alarm_handler/AH in all_handlers) - AH.process() - -/datum/subsystem/alarm/proc/active_alarms() - var/list/all_alarms = new - for(var/datum/alarm_handler/AH in all_handlers) - var/list/alarms = AH.alarms - all_alarms += alarms - - return all_alarms - -/datum/subsystem/alarm/proc/number_of_active_alarms() - var/list/alarms = active_alarms() - return alarms.len diff --git a/code/game/turfs/initialization/maintenance.dm b/code/game/turfs/initialization/maintenance.dm index 5a9574810b1..16b1d03d21e 100644 --- a/code/game/turfs/initialization/maintenance.dm +++ b/code/game/turfs/initialization/maintenance.dm @@ -26,7 +26,7 @@ var/global/list/random_junk if(prob(25)) return /obj/effect/decal/cleanable/generic if(!random_junk) - random_junk = subtypes(/obj/item/trash) + random_junk = subtypesof(/obj/item/trash) random_junk += typesof(/obj/item/weapon/cigbutt) random_junk += /obj/effect/decal/cleanable/spiderling_remains random_junk += /obj/effect/decal/remains/mouse diff --git a/code/global.dm b/code/global.dm index ea2be0b0447..3c4c558fb46 100644 --- a/code/global.dm +++ b/code/global.dm @@ -103,7 +103,6 @@ var/join_motd = null var/datum/nanomanager/nanomanager = new() // NanoManager, the manager for Nano UIs. var/datum/event_manager/event_manager = new() // Event Manager, the manager for events. -var/datum/subsystem/alarm/alarm_manager = new() // Alarm Manager, the manager for alarms. var/list/awaydestinations = list() // Away missions. A list of landmarks that the warpgate can take you to. diff --git a/code/modules/lighting/lighting_process.dm b/code/modules/lighting/lighting_process.dm index 1c8361dbaf6..916920393ba 100644 --- a/code/modules/lighting/lighting_process.dm +++ b/code/modules/lighting/lighting_process.dm @@ -1,11 +1,10 @@ -/datum/controller/process/lighting/setup() - name = "lighting" - schedule_interval = LIGHTING_INTERVAL - - create_lighting_overlays() +/datum/controller/process/lighting + var/last_light_count = 0 + var/last_overlay_count = 0 /datum/controller/process/lighting/doWork() - var/list/lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from scheck() don't cause things to be cut from the list without being updated. + var/list/lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from SCHECK don't cause things to be cut from the list without being updated. + last_light_count = lighting_update_lights.len lighting_update_lights = null //Nulling it first because of http://www.byond.com/forum/?post=1854520 lighting_update_lights = list() @@ -22,9 +21,10 @@ L.force_update = 0 L.needs_update = 0 - scheck() + SCHECK var/list/lighting_update_overlays_old = lighting_update_overlays //Same as above. + last_overlay_count = lighting_update_overlays.len lighting_update_overlays = null //Same as above lighting_update_overlays = list() @@ -32,4 +32,4 @@ O.update_overlay() O.needs_update = 0 - scheck() + SCHECK diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 11ae1407778..738765a5d08 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -56,8 +56,8 @@ /mob/living/carbon/human/Stat() ..() if(statpanel("Status")) - stat(null, "Intent: [a_intent]") - stat(null, "Move Mode: [m_intent]") + stat("Intent:", "[a_intent]") + stat("Move Mode:", "[m_intent]") if(emergency_shuttle) var/eta_status = emergency_shuttle.get_status_panel_eta() if(eta_status) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 648b1b28155..fafaea9b25d 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -658,15 +658,12 @@ if(client.holder) if(statpanel("Status")) - stat("Location:","([x], [y], [z])") - if(statpanel("Processes")) + stat("Location:", "([x], [y], [z]) [loc]") stat("CPU:","[world.cpu]") stat("Instances:","[world.contents.len]") - if(processScheduler && processScheduler.getIsRunning()) - for(var/datum/controller/process/P in processScheduler.processes) - stat(P.getStatName(), P.getTickTime()) - else - stat("processScheduler is not running.") + if(statpanel("Processes")) + if(processScheduler) + processScheduler.statProcesses() if(listed_turf && client) if(!TurfAdjacent(listed_turf)) diff --git a/config/example/config.txt b/config/example/config.txt index 96f44ae19a7..bf59e98c8ac 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -58,6 +58,9 @@ LOG_ATTACK ## log pda messages LOG_PDA +## log world.log messages +# LOG_WORLD_OUTPUT + ## log all Topic() calls (for use by coders in tracking down Topic issues) # LOG_HREFS From 858451365284c66d77a7972cd328b9a88fa71044 Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Sat, 14 Nov 2015 00:43:11 +0100 Subject: [PATCH 06/14] Fixes the mining rig camera not properly showing up on the station camera list. Was using "Mine" instead of "MINE. Corrected by replacing all networks with the defined presets. --- code/modules/clothing/spacesuits/rig/suits/ert.dm | 2 +- code/modules/clothing/spacesuits/rig/suits/light.dm | 2 +- .../modules/clothing/spacesuits/rig/suits/station.dm | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/modules/clothing/spacesuits/rig/suits/ert.dm b/code/modules/clothing/spacesuits/rig/suits/ert.dm index c46b019a4d2..88c33cee261 100644 --- a/code/modules/clothing/spacesuits/rig/suits/ert.dm +++ b/code/modules/clothing/spacesuits/rig/suits/ert.dm @@ -1,6 +1,6 @@ /obj/item/clothing/head/helmet/space/rig/ert light_overlay = "helmet_light_dual" - camera_networks = list("ERT") + camera_networks = list(NETWORK_ERT) /obj/item/weapon/rig/ert name = "ERT-C hardsuit control module" diff --git a/code/modules/clothing/spacesuits/rig/suits/light.dm b/code/modules/clothing/spacesuits/rig/suits/light.dm index 270e7a37613..3eeb7988755 100644 --- a/code/modules/clothing/spacesuits/rig/suits/light.dm +++ b/code/modules/clothing/spacesuits/rig/suits/light.dm @@ -40,7 +40,7 @@ airtight = 0 seal_delay = 5 //not being vaccum-proof has an upside I guess - + helm_type = /obj/item/clothing/head/lightrig/hacker chest_type = /obj/item/clothing/suit/lightrig/hacker glove_type = /obj/item/clothing/gloves/lightrig/hacker diff --git a/code/modules/clothing/spacesuits/rig/suits/station.dm b/code/modules/clothing/spacesuits/rig/suits/station.dm index 50a18c9ace1..e3ac8906d3c 100644 --- a/code/modules/clothing/spacesuits/rig/suits/station.dm +++ b/code/modules/clothing/spacesuits/rig/suits/station.dm @@ -1,23 +1,23 @@ /obj/item/clothing/head/helmet/space/rig/industrial - camera_networks = list("Mine") + camera_networks = list(NETWORK_MINE) /obj/item/clothing/head/helmet/space/rig/ce - camera_networks = list("Engineering") + camera_networks = list(NETWORK_ENGINEERING) /obj/item/clothing/head/helmet/space/rig/eva light_overlay = "helmet_light_dual" - camera_networks = list("Engineering") + camera_networks = list(NETWORK_ENGINEERING) /obj/item/clothing/head/helmet/space/rig/hazmat light_overlay = "hardhat_light" - camera_networks = list("Research") + camera_networks = list(NETWORK_RESEARCH) /obj/item/clothing/head/helmet/space/rig/medical - camera_networks = list("Medbay") + camera_networks = list(NETWORK_MEDICAL) /obj/item/clothing/head/helmet/space/rig/hazard light_overlay = "helmet_light_dual" - camera_networks = list("Security") + camera_networks = list(NETWORK_SECURITY) /obj/item/weapon/rig/industrial name = "industrial suit control module" From dbedb0b414c83820bae430bfbf3c062ef08e9c21 Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Sun, 15 Nov 2015 10:51:13 +0100 Subject: [PATCH 07/14] Corrects AI sight. Fixes #11450. --- code/modules/mob/living/life.dm | 22 +++++----- code/modules/mob/living/silicon/ai/life.dm | 51 ++++++++++------------ 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 0815dac4364..fd9dd7b4bfa 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -136,7 +136,6 @@ /mob/living/proc/handle_vision() client.screen.Remove(global_hud.blurry, global_hud.druggy, global_hud.vimpaired, global_hud.darkMask, global_hud.nvg, global_hud.thermal, global_hud.meson, global_hud.science) - update_sight() if(stat == DEAD) @@ -159,24 +158,27 @@ reset_view(null, 0) else if(viewflags) sight |= viewflags - else if(eyeobj && eyeobj.owner != src) - reset_view(null) - else - if(!client.adminobs) + else if(eyeobj) + if(eyeobj.owner != src) reset_view(null) + else if(!client.adminobs) + reset_view(null) /mob/living/proc/update_sight() if(stat == DEAD) - sight |= SEE_TURFS - sight |= SEE_MOBS - sight |= SEE_OBJS - see_in_dark = 8 - see_invisible = SEE_INVISIBLE_LEVEL_TWO + update_dead_sight() else sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) see_in_dark = 2 see_invisible = SEE_INVISIBLE_LIVING +/mob/living/proc/update_dead_sight() + sight |= SEE_TURFS + sight |= SEE_MOBS + sight |= SEE_OBJS + see_in_dark = 8 + see_invisible = SEE_INVISIBLE_LEVEL_TWO + /mob/living/proc/handle_hud_icons() handle_hud_icons_health() handle_hud_glasses() diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index b5ddfcedd91..6879284cb7a 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -38,21 +38,7 @@ src << "APU GENERATOR FAILURE! (System Damaged)" stop_apu(1) - var/blind = 0 - var/area/loc = null - if (istype(T, /turf)) - loc = T.loc - if (istype(loc, /area)) - if (!loc.power_equip && !istype(src.loc,/obj/item) && !APU_power) - blind = 1 - - if (!blind) - src.sight |= SEE_TURFS - src.sight |= SEE_MOBS - src.sight |= SEE_OBJS - src.see_in_dark = 8 - src.see_invisible = SEE_INVISIBLE_LIVING - + if (!is_blinded()) if (aiRestorePowerRoutine==2) src << "Alert cancelled. Power has been restored without our assistance." aiRestorePowerRoutine = 0 @@ -77,25 +63,13 @@ if (aiRestorePowerRoutine==0) aiRestorePowerRoutine = 1 - //Blind the AI - updateicon() - src.blind.screen_loc = ui_entire_screen - if (src.blind.layer!=18) - src.blind.layer = 18 - src.sight = src.sight&~SEE_TURFS - src.sight = src.sight&~SEE_MOBS - src.sight = src.sight&~SEE_OBJS - src.see_in_dark = 0 - src.see_invisible = SEE_INVISIBLE_LIVING - //Now to tell the AI why they're blind and dying slowly. - src << "You've lost power!" spawn(20) src << "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection." sleep(50) - if (loc.power_equip) + if (current_area.power_equip) if (!istype(T, /turf/space)) src << "Alert cancelled. Power has been restored without our assistance." aiRestorePowerRoutine = 0 @@ -125,7 +99,7 @@ else src << "Lost connection with the APC!" src:aiRestorePowerRoutine = 2 return - if (loc.power_equip) + if (current_area.power_equip) if (!istype(T, /turf/space)) src << "Alert cancelled. Power has been restored without our assistance." aiRestorePowerRoutine = 0 @@ -177,3 +151,22 @@ ..() add_ai_verbs(src) +/mob/living/silicon/ai/update_sight() + if(is_blinded()) + updateicon() + src.blind.screen_loc = ui_entire_screen + if (src.blind.layer!=18) + src.blind.layer = 18 + src.sight = src.sight&~SEE_TURFS + src.sight = src.sight&~SEE_MOBS + src.sight = src.sight&~SEE_OBJS + src.see_in_dark = 0 + src.see_invisible = SEE_INVISIBLE_LIVING + else + update_dead_sight() + +/mob/living/silicon/ai/proc/is_blinded() + var/area/A = get_area(src) + if (A && !A.power_equip && !istype(src.loc,/obj/item) && !APU_power) + return 1 + return 0 From 9e321ff6d504bec5d654088ebf2d5eef5e037ecf Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Sun, 15 Nov 2015 11:52:18 +0100 Subject: [PATCH 08/14] Updates the nuclear bomb code and makes it utilize NanoUI, ported from Paradise. --- code/datums/wires/nuclearbomb.dm | 24 +- code/defines/obj/weapon.dm | 7 - code/game/gamemodes/gameticker.dm | 7 +- code/game/machinery/nuclear_bomb.dm | 370 ++++++++++++--------- code/modules/mob/dead/observer/observer.dm | 5 +- nano/templates/nuclear_bomb.tmpl | 68 ++++ 6 files changed, 300 insertions(+), 181 deletions(-) create mode 100644 nano/templates/nuclear_bomb.tmpl diff --git a/code/datums/wires/nuclearbomb.dm b/code/datums/wires/nuclearbomb.dm index a8f5357840a..a83532ef143 100644 --- a/code/datums/wires/nuclearbomb.dm +++ b/code/datums/wires/nuclearbomb.dm @@ -9,9 +9,7 @@ var/const/NUCLEARBOMB_WIRE_SAFETY = 4 /datum/wires/nuclearbomb/CanUse(var/mob/living/L) var/obj/machinery/nuclearbomb/N = holder - if(N.panel_open) - return 1 - return 0 + return N.panel_open /datum/wires/nuclearbomb/GetInteractWindow() var/obj/machinery/nuclearbomb/N = holder @@ -25,12 +23,14 @@ var/const/NUCLEARBOMB_WIRE_SAFETY = 4 switch(index) if(NUCLEARBOMB_WIRE_LIGHT) N.lighthack = !N.lighthack + N.update_icon() spawn(100) N.lighthack = !N.lighthack + N.update_icon() if(NUCLEARBOMB_WIRE_TIMING) if(N.timing) spawn - message_admins("[key_name_admin(usr)] pulsed a nuclear bomb's detonation wire, causing it to explode (JMP)") + log_and_message_admins_with_location("pulsed a nuclear bomb's detonation wire, causing it to explode.", holder.x, holder.y, holder.z) N.explode() if(NUCLEARBOMB_WIRE_SAFETY) N.safety = !N.safety @@ -38,9 +38,7 @@ var/const/NUCLEARBOMB_WIRE_SAFETY = 4 N.safety = !N.safety if(N.safety == 1) N.visible_message("\The [N] quiets down.") - if(!N.lighthack) - if (N.icon_state == "nuclearbomb2") - N.icon_state = "nuclearbomb1" + N.secure_device() else N.visible_message("\The [N] emits a quiet whirling noise!") @@ -48,15 +46,13 @@ var/const/NUCLEARBOMB_WIRE_SAFETY = 4 var/obj/machinery/nuclearbomb/N = holder switch(index) if(NUCLEARBOMB_WIRE_SAFETY) + N.safety = mended if(N.timing) spawn - message_admins("[key_name_admin(usr)] cut a nuclear bomb's timing wire, causing it to explode (JMP)") + log_and_message_admins_with_location("cut a nuclear bomb's timing wire, causing it to explode.", holder.x, holder.y, holder.z) N.explode() if(NUCLEARBOMB_WIRE_TIMING) - if(!N.lighthack) - if (N.icon_state == "nuclearbomb2") - N.icon_state = "nuclearbomb1" - N.timing = 0 - bomb_set = 0 + N.secure_device() if(NUCLEARBOMB_WIRE_LIGHT) - N.lighthack = !N.lighthack + N.lighthack = !mended + N.update_icon() diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index 54ca78aa398..1d36dd21145 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -133,13 +133,6 @@ name = "disk" icon = 'icons/obj/items.dmi' -/obj/item/weapon/disk/nuclear - name = "nuclear authentication disk" - desc = "Better keep this safe." - icon_state = "nucleardisk" - item_state = "card-id" - w_class = 2.0 - /* /obj/item/weapon/game_kit name = "Gaming Kit" diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index bb8abe67578..dba58fa35a7 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -326,8 +326,11 @@ var/global/datum/controller/gameticker/ticker spawn(50) callHook("roundend") - if (mode.station_was_nuked) - feedback_set_details("end_proper","nuke") + if (universe_has_ended) + if(mode.station_was_nuked) + feedback_set_details("end_proper","nuke") + else + feedback_set_details("end_proper","universe destroyed") if(!delay_end) world << "Rebooting due to destruction of station in [restart_timeout/10] seconds" else diff --git a/code/game/machinery/nuclear_bomb.dm b/code/game/machinery/nuclear_bomb.dm index fb2a4994e33..0bd3e922000 100644 --- a/code/game/machinery/nuclear_bomb.dm +++ b/code/game/machinery/nuclear_bomb.dm @@ -6,27 +6,27 @@ var/bomb_set icon = 'icons/obj/stationobjs.dmi' icon_state = "nuclearbomb0" density = 1 - var/deployable = 0.0 - var/extended = 0.0 + var/deployable = 0 + var/extended = 0 var/lighthack = 0 - var/opened = 0.0 - var/timeleft = 60.0 - var/timing = 0.0 + var/timeleft = 120 + var/timing = 0 var/r_code = "ADMIN" var/code = "" - var/yes_code = 0.0 - var/safety = 1.0 + var/yes_code = 0 + var/safety = 1 var/obj/item/weapon/disk/nuclear/auth = null - var/removal_stage = 0 // 0 is no removal, 1 is covers removed, 2 is covers open, - // 3 is sealant open, 4 is unwrenched, 5 is removed from bolts. + var/removal_stage = 0 // 0 is no removal, 1 is covers removed, 2 is covers open, 3 is sealant open, 4 is unwrenched, 5 is removed from bolts. + var/lastentered use_power = 0 - var/datum/wires/nuclearbomb/wires - + unacidable = 1 + var/previous_level = "" + var/datum/wires/nuclearbomb/wires = null /obj/machinery/nuclearbomb/New() ..() r_code = "[rand(10000, 99999.0)]"//Creates a random code upon object spawn. - wires = new(src) + wires = new/datum/wires/nuclearbomb(src) /obj/machinery/nuclearbomb/Destroy() qdel(wires) @@ -35,42 +35,40 @@ var/bomb_set /obj/machinery/nuclearbomb/process() if (src.timing) - bomb_set = 1 //So long as there is one nuke timing, it means one nuke is armed. - src.timeleft-- - if (src.timeleft <= 0) - explode() - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) + src.timeleft = max(timeleft - 2, 0) // 2 seconds per process() + if (timeleft <= 0) + spawn + explode() + nanomanager.update_uis(src) return -/obj/machinery/nuclearbomb/attackby(obj/item/weapon/O as obj, mob/user as mob) +/obj/machinery/nuclearbomb/attackby(obj/item/weapon/O as obj, mob/user as mob, params) if (istype(O, /obj/item/weapon/screwdriver)) src.add_fingerprint(user) if (src.auth) - if (src.opened == 0) - src.opened = 1 + if (panel_open == 0) + panel_open = 1 overlays += image(icon, "npanel_open") user << "You unscrew the control panel of [src]." - + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) else - src.opened = 0 + panel_open = 0 overlays -= image(icon, "npanel_open") user << "You screw the control panel of [src] back on." + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) else - if (src.opened == 0) - user << "The [src] emits a buzzing noise, the panel staying locked in." - if (src.opened == 1) - src.opened = 0 + if (panel_open == 0) + user << "\The [src] emits a buzzing noise, the panel staying locked in." + if (panel_open == 1) + panel_open = 0 overlays -= image(icon, "npanel_open") - user << "You screw the control panel of [src] back on." + user << "You screw the control panel of \the [src] back on." + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) flick("nuclearbombc", src) + return - return - if (istype(O, /obj/item/weapon/wirecutters) || istype(O, /obj/item/device/multitool)) - if (src.opened == 1) - wires.Interact(user) - return + if (panel_open && (istype(O, /obj/item/device/multitool) || istype(O, /obj/item/weapon/wirecutters))) + return attack_hand(user) if (src.extended) if (istype(O, /obj/item/weapon/disk/nuclear)) @@ -78,13 +76,12 @@ var/bomb_set O.loc = src src.auth = O src.add_fingerprint(user) - return + return attack_hand(user) if (src.anchored) switch(removal_stage) if(0) if(istype(O,/obj/item/weapon/weldingtool)) - var/obj/item/weapon/weldingtool/WT = O if(!WT.isOn()) return if (WT.get_fuel() < 5) // uses up 5 fuel. @@ -150,54 +147,67 @@ var/bomb_set return ..() -/obj/machinery/nuclearbomb/attack_hand(mob/user as mob) - if (src.extended) - if (!ishuman(user)) - usr << "You don't have the dexterity to do this!" - return 1 +/obj/machinery/nuclearbomb/attack_ghost(mob/user as mob) + attack_hand(user) - user.set_machine(src) - var/dat = text("Nuclear Fission Explosive
\nAuth. Disk: []
", src, (src.auth ? "++++++++++" : "----------")) - if (src.auth) - if (src.yes_code) - dat += text("\nStatus: []-[]
\nTimer: []
\n
\nTimer: [] Toggle
\nTime: - - [] + +
\n
\nSafety: [] Toggle
\nAnchor: [] Toggle
\n", (src.timing ? "Func/Set" : "Functional"), (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src, src, src, src.timeleft, src, src, (src.safety ? "On" : "Off"), src, (src.anchored ? "Engaged" : "Off"), src) - else - dat += text("\nStatus: Auth. S2-[]
\nTimer: []
\n
\nTimer: [] Toggle
\nTime: - - [] + +
\n
\n[] Safety: Toggle
\nAnchor: [] Toggle
\n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off")) +/obj/machinery/nuclearbomb/attack_hand(mob/user as mob) + if (extended) + if (panel_open) + wires.Interact(user) else - if (src.timing) - dat += text("\nStatus: Set-[]
\nTimer: []
\n
\nTimer: [] Toggle
\nTime: - - [] + +
\n
\nSafety: [] Toggle
\nAnchor: [] Toggle
\n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off")) - else - dat += text("\nStatus: Auth. S1-[]
\nTimer: []
\n
\nTimer: [] Toggle
\nTime: - - [] + +
\n
\nSafety: [] Toggle
\nAnchor: [] Toggle
\n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off")) - var/message = "AUTH" - if (src.auth) - message = text("[]", src.code) - if (src.yes_code) - message = "*****" - dat += text("
\n>[]
\n1-2-3
\n4-5-6
\n7-8-9
\nR-0-E
\n
", message, src, src, src, src, src, src, src, src, src, src, src, src) - user << browse(dat, "window=nuclearbomb;size=300x400") - onclose(user, "nuclearbomb") - else if (src.deployable) + ui_interact(user) + else if (deployable) if(removal_stage < 5) src.anchored = 1 visible_message("With a steely snap, bolts slide out of [src] and anchor it to the flooring!") else visible_message("\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") + extended = 1 if(!src.lighthack) flick("nuclearbombc", src) - src.icon_state = "nuclearbomb1" - src.extended = 1 + update_icon() return -/obj/machinery/nuclearbomb/verb/make_deployable() +/obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["hacking"] = 0 + data["auth"] = is_auth(user) + if (is_auth(user)) + if (yes_code) + data["authstatus"] = timing ? "Functional/Set" : "Functional" + else + data["authstatus"] = "Auth. S2" + else + if (timing) + data["authstatus"] = "Set" + else + data["authstatus"] = "Auth. S1" + data["safe"] = safety ? "Safe" : "Engaged" + data["time"] = timeleft + data["timer"] = timing + data["safety"] = safety + data["anchored"] = anchored + data["yescode"] = yes_code + data["message"] = "AUTH" + if (is_auth(user)) + data["message"] = code + if (yes_code) + data["message"] = "*****" + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "nuclear_bomb.tmpl", "Nuke Control Panel", 300, 510) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/nuclearbomb/verb/toggle_deployable() set category = "Object" - set name = "Make Deployable" + set name = "Toggle Deployable" set src in oview(1) - if (!usr.canmove || usr.stat || usr.restrained()) + if(usr.incapacitated()) return - if (!ishuman(usr)) - usr << "You don't have the dexterity to do this!" - return 1 if (src.deployable) usr << "You close several panels to make [src] undeployable." @@ -207,106 +217,127 @@ var/bomb_set src.deployable = 1 return +/obj/machinery/nuclearbomb/proc/is_auth(var/mob/user) + if(auth) + return 1 + if(user.can_admin_interact()) + return 1 + return 0 /obj/machinery/nuclearbomb/Topic(href, href_list) - ..() - if (!usr.canmove || usr.stat || usr.restrained()) - return - if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) - usr.set_machine(src) + if(..()) + return 1 - if (href_list["auth"]) - if (src.auth) - src.auth.loc = src.loc - src.yes_code = 0 - src.auth = null - else - var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/disk/nuclear)) - usr.drop_item() - I.loc = src - src.auth = I - if (src.auth) - if (href_list["type"]) - if (href_list["type"] == "E") - if (src.code == src.r_code) - src.yes_code = 1 - src.code = null - else - src.code = "ERROR" + if (href_list["auth"]) + if (auth) + auth.loc = loc + yes_code = 0 + auth = null + else + var/obj/item/I = usr.get_active_hand() + if (istype(I, /obj/item/weapon/disk/nuclear)) + usr.drop_item() + I.loc = src + auth = I + if (is_auth(usr)) + if (href_list["type"]) + if (href_list["type"] == "E") + if (code == r_code) + yes_code = 1 + code = null else - if (href_list["type"] == "R") - src.yes_code = 0 - src.code = null + code = "ERROR" + else + if (href_list["type"] == "R") + yes_code = 0 + code = null + else + lastentered = text("[]", href_list["type"]) + if (text2num(lastentered) == null) + var/turf/LOC = get_turf(usr) + message_admins("[key_name_admin(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered]! ([LOC ? "JMP" : "null"])", 0) + log_admin("EXPLOIT: [key_name(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered]!") else - src.code += text("[]", href_list["type"]) - if (length(src.code) > 5) - src.code = "ERROR" - if (src.yes_code) - if (href_list["time"]) - var/time = text2num(href_list["time"]) - src.timeleft += time - src.timeleft = min(max(round(src.timeleft), 60), 600) - if (href_list["timer"]) - if (src.timing == -1.0) - return - if (src.safety) - usr << "The safety is still on." - return - src.timing = !( src.timing ) - if (src.timing) - if(!src.lighthack) - src.icon_state = "nuclearbomb2" - if(!src.safety) - bomb_set = 1//There can still be issues with this reseting when there are multiple bombs. Not a big deal tho for Nuke/N - else - bomb_set = 0 - else - bomb_set = 0 - if(!src.lighthack) - src.icon_state = "nuclearbomb1" - if (href_list["safety"]) - src.safety = !( src.safety ) - if(safety) - src.timing = 0 - bomb_set = 0 - if (href_list["anchor"]) + code += lastentered + if (length(code) > 5) + code = "ERROR" + if (yes_code) + if (href_list["time"]) + var/time = text2num(href_list["time"]) + timeleft += time + timeleft = Clamp(timeleft, 120, 600) + if (href_list["timer"]) + if (timing == -1) + nanomanager.update_uis(src) + return + if (!anchored) + usr << "\The [src] needs to be anchored." + nanomanager.update_uis(src) + return + if (safety) + usr << "The safety is still on." + nanomanager.update_uis(src) + return + if (wires.IsIndexCut(NUCLEARBOMB_WIRE_TIMING)) + usr << "Nothing happens, something might be wrong with the wiring." + nanomanager.update_uis(src) + return - if(removal_stage == 5) - src.anchored = 0 - visible_message("\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") - return + if (!timing && !safety) + timing = 1 + log_and_message_admins_with_location("engaged a nuclear bomb", x, y, ,z) + bomb_set++ //There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke/N + update_icon() + else + secure_device() + if (href_list["safety"]) + if (wires.IsIndexCut(NUCLEARBOMB_WIRE_SAFETY)) + usr << "Nothing happens, something might be wrong with the wiring." + nanomanager.update_uis(src) + return + safety = !safety + if(safety) + secure_device() + if (href_list["anchor"]) + if(removal_stage == 5) + anchored = 0 + visible_message("\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") + nanomanager.update_uis(src) + return - src.anchored = !( src.anchored ) - if(src.anchored) + if(!isinspace()) + anchored = !anchored + if(anchored) visible_message("With a steely snap, bolts slide out of [src] and anchor it to the flooring.") else + secure_device() visible_message("The anchoring bolts slide back into the depths of [src].") + else + usr << "There is nothing to anchor to!" - src.add_fingerprint(usr) - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - else - usr << browse(null, "window=nuclearbomb") + nanomanager.update_uis(src) + +/obj/machinery/nuclearbomb/proc/secure_device() + if(timing <= 0) return - return + bomb_set-- + timing = 0 + timeleft = Clamp(timeleft, 120, 600) + update_icon() /obj/machinery/nuclearbomb/ex_act(severity) return - #define NUKERANGE 80 /obj/machinery/nuclearbomb/proc/explode() if (src.safety) - src.timing = 0 + timing = 0 return - src.timing = -1.0 + src.timing = -1 src.yes_code = 0 src.safety = 1 - if(!src.lighthack) - src.icon_state = "nuclearbomb3" + update_icon() playsound(src,'sound/machines/Alarm.ogg',100,0,5) if (ticker && ticker.mode) ticker.mode.explosion_in_progress = 1 @@ -329,24 +360,49 @@ var/bomb_set ticker.station_explosion_cinematic(off_station,null) if(ticker.mode) ticker.mode.explosion_in_progress = 0 - world << "The station was destoyed by the nuclear blast!" + if(off_station == 1) + world << "A nuclear device was set off, but the explosion was out of reach of the station!" + else if(off_station == 2) + world << "A nuclear device was set off, but the device was not on the station!" + else + world << "The station was destoyed by the nuclear blast!" ticker.mode.station_was_nuked = (off_station<2) //offstation==1 is a draw. the station becomes irradiated and needs to be evacuated. //kinda shit but I couldn't get permission to do what I wanted to do. if(!ticker.mode.check_finished())//If the mode does not deal with the nuke going off so just reboot because everyone is stuck as is - world << "Resetting in 30 seconds!" - - feedback_set_details("end_error","nuke - unhandled ending") - - if(blackbox) - blackbox.save_all_data_to_sql() - sleep(300) - log_game("Rebooting due to nuclear detonation") - world.Reboot() + universe_has_ended = 1 return return +/obj/machinery/nuclearbomb/update_icon() + if(lighthack) + icon_state = "nuclearbomb0" + return + + else if(timing == -1) + icon_state = "nuclearbomb3" + else if(timing) + icon_state = "nuclearbomb2" + else if(extended) + icon_state = "nuclearbomb1" + else + icon_state = "nuclearbomb0" +/* +if(!N.lighthack) + if (N.icon_state == "nuclearbomb2") + N.icon_state = "nuclearbomb1" + */ + +//====The nuclear authentication disc==== +/obj/item/weapon/disk/nuclear + name = "nuclear authentication disk" + desc = "Better keep this safe." + icon = 'icons/obj/items.dmi' + icon_state = "nucleardisk" + item_state = "card-id" + w_class = 1.0 + /obj/item/weapon/disk/nuclear/New() ..() nuke_disks |= src @@ -360,7 +416,7 @@ var/bomb_set log_and_message_admins_with_location("[src], the last authentication disk, has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).", T.x, T.y, T.z) else log_and_message_admins("[src], the last authentication disk, has been destroyed. Failed to respawn disc!") - ..() + return ..() /obj/item/weapon/disk/nuclear/touch_map_edge() qdel(src) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 83526bfc03e..54ecebc1599 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -667,7 +667,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/canface() return 1 -/mob/dead/observer/proc/can_admin_interact() +/mob/proc/can_admin_interact() + return 0 + +/mob/dead/observer/can_admin_interact() return check_rights(R_ADMIN, 0, src) /mob/dead/observer/verb/toggle_ghostsee() diff --git a/nano/templates/nuclear_bomb.tmpl b/nano/templates/nuclear_bomb.tmpl new file mode 100644 index 00000000000..b178f99bf60 --- /dev/null +++ b/nano/templates/nuclear_bomb.tmpl @@ -0,0 +1,68 @@ + +
+ Authorization Disk: {{if data.auth}}{{:helper.link('++++++++++', 'eject', {'auth' : 1})}} {{else}} {{:helper.link('----------', 'disk', {'auth' : 1})}}{{/if}} +
+
+
+
Status: {{:data.authstatus}} - {{:data.safe}}
+
Timer: {{:data.time}}
+
+
+
+ {{if data.auth && data.yescode}} +
+ Timer: {{:helper.link('On', 'play', {'timer' : 1}, data.timer ? 'redButton' : '')}}{{:helper.link('Off', 'stop', {'timer' : 0}, !data.timer ? 'selected' : '')}} +
+
+ Time: {{:helper.link('--', '', {'time' : -10}, data.time <= 120 ? 'disabled' : '')}}{{:helper.link('-', '', {'time' : -1}, data.time <= 120 ? 'disabled' : '')}} {{:data.time}} {{:helper.link('+', '', {'time' : 1})}}{{:helper.link('++', '', {'time' : 10})}} +
+ {{else}} +
+ Timer: {{:helper.link('On', 'play', null, 'disabled')}}{{:helper.link('Off', 'pause', null, 'disabled')}} +
+
+ Time: {{:helper.link('-', '', null, 'disabled')}}{{:helper.link('-', '', null, 'disabled')}} {{:data.time}} {{:helper.link('+', '', null, 'disabled')}}{{:helper.link('++', '', null, 'disabled')}} +
+ {{/if}} +
+
+ {{if data.auth && data.yescode}} +
+ Safety: {{:helper.link('Engaged', 'info', {'safety' : 1}, data.safety ? 'selected' : '')}}{{:helper.link('Disengaged', 'alert', {'safety' : 0}, data.safety ? '' : 'redButton')}} +
+
+ Anchor: {{:helper.link('Engaged', 'locked', {'anchor' : 1}, data.anchored ? 'selected' : '')}}{{:helper.link('Disengaged', 'unlocked', {'anchor' : 0}, data.anchored ? '' : 'selected')}} +
+ {{else}} +
+ Safety: {{:helper.link('Engaged', 'info', null, 'disabled')}}{{:helper.link('Disengaged', 'alert', null, 'disabled')}} +
+
+ Anchor: {{:helper.link('Engaged', 'locked', null, 'disabled')}}{{:helper.link('Disengaged', 'unlocked', null, 'disabled')}} +
+ {{/if}} +
+
+
+
+
+ >{{if data.message}} {{:data.message}}{{/if}} +
+
+
+ {{:helper.link('1', '', {'type' : 1})}}{{:helper.link('2', '', {'type' : 2})}}{{:helper.link('3', '', {'type' : 3})}} +
+
+ {{:helper.link('4', '', {'type' : 4})}}{{:helper.link('5', '', {'type' : 5})}}{{:helper.link('6', '', {'type' : 6})}} +
+
+ {{:helper.link('7', '', {'type' : 7})}}{{:helper.link('8', '', {'type' : 8})}}{{:helper.link('9', '', {'type' : 9})}} +
+
+ {{:helper.link('R', '', {'type' : 'R'})}}{{:helper.link('0', '', {'type' : 0})}}{{:helper.link('E', '', {'type' : 'E'})}} +
+
+
From 596de3f3caf498196aef6c0720c40a97fef7667f Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Sun, 15 Nov 2015 14:19:33 +0100 Subject: [PATCH 09/14] Now includes btime.so. --- btime.so | Bin 0 -> 7232 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 btime.so diff --git a/btime.so b/btime.so new file mode 100644 index 0000000000000000000000000000000000000000..edb3cc3113f8ba3a9bab731613ee77877c6be83b GIT binary patch literal 7232 zcmeHMZETa*6~4xygeJU%ED%1TV$lr36ucyS6s<^$^9d}ZAqmie))&Wiu!Cc#_UkC= zkVr60q$U+(zqU#Rm2H|fexQXP9qlB7LkCkeQMwhRLWMRloRMv*#%P9Ez2~{FZ}KMn z&^BrRIOycu=bm%Vy}s|cUx$OW4Rtn~O(?PpyC7)r-u`6<*;8p;V_=p9w{YDFRp!@;2 zlm$?pSR_Uv&pC*Q3&lwmFz;0m`65RoAe(@fWbiG>srH2;2Hc0qIhfINPR?+WLHU@y zMUX+XC*_M=A#{CTXE>xs4R^%Qb)g4B0Ym8R5JKP5x=r``BEEfrsNsvWZmSN4L%vpb zThM3fK3}7Idfas24hCL^;nr@wIpd)^=#EBxQK9cHFEaw2zHqxg9E)@dPcZD+ukZ62 ztP}w5AWM3LmTTL3!y&KIc4NTNP*)@nGTL>If4>L@+9HNC8g`bm=wWGt(0yLF;f85j zG;01dRE4~vjc#Eg>KnFHRqGYbipf&BbM0igY_hc0$ptAR&MsqA2(CEWjDKd$Ff^QR z2RJ_vKuFFOpP)>#A+q0vq@EOA9zfV;32pieIBAKG zWv5;fLi8uUwM>Xa{C+x}K61gBovK4+d?b5MQly6%VCmBwA1QqraV7jLj^2iO`ZRx` zpX$-85_6^dSvh(^;>E=LGkR8Hu0p?q_>{yf`b&t9OI%D`M%)LSC@N02AD{Y{;-vLo zd~K-^gRgLt8a(uM{9S!HKJi3%VdBsj+TbV5+c9t_K31?jeKkIkcjfQNfd_+cuY#RO zUB{pPi+j+1hjKtS19w_hUml*A6(7qQNDkjyZoBc`gi(+<@reGe8Bb!WnzpB}!CT_n zkFHGlLq9F4T`=lT&Vf%f?|Z8f{zPn5B0g>oW%aIG_JF}d6R=KXAGs2nJ6eMVgT_jcI59z|*NnfIzpzP;>B?v^Y7+&;$(=2! zD`?f9?1hK;Skd6n893b8VN1P%>gNaJeSo{0cBZNU_s0(dZ3-lgLgXPb&R-gO<9oJY zdxBO2mp}RQ0On-5?Ki^@b5>srT%*bA_XZk@i$1IY$Irs*#?axr{7uDsUi@e{c^v(3 zk^TP@pB%H1S_X6@aTGR#LwjM55zu}t_f}DHQ%6pRts`e=>L>q_E(XT;yqFw3w-RO| z^SxS9525Q%{!F^dPQ5KH8JU^*{ZOhCR5M_|+Ac)N{!k;L-DO*5f0nb(2(E!y4di_c z#}8>>zJ3Hb0(l#fQA@JD+$?MdvTe(9v$BpN)EuZ|#7-a(`XGgtU8m)4ou6Z5^@wjS zefDb=#Vab24;t*lNft=CFiTB%Dbo7Jr4x{_M9 z>m4nNZ4ZDiqb<*YX>Id%YehAhqe?5T(n_ji+s#^Tb*8Bt*PCc^6K(OeW!w0yMlEkM zd?z*j?8o$Y1|HAA;~9871CM9m|1txWxQCAO+6=;RDTXuhT}a#(#9zU=V7^muX_oI3 zo>jc_;?610X55?P-IwPq53PTEnhtM-GrB#7`!Bi>2Y{c1d>Rs0S$VJKn^8E-8$8cZ zp5Y6?d}14L#PT{wzRfDZUjb)>aa@LfhsHSi!*DNfO$(m|eh4XjqV9hszP}ay34K2R z^Ul5qyb`Fo`nr74YwspaZx*_OhH%O!qto#9pe!Gb&PZ6kznnh5-X3w|CFl2|r9x&4-5rUzd(9TA+~I*4 zoVz;%9&{XrL;P{dUQCa8&y7n?n%rqX~qd9^DZRD4@tf7 z_?=CRj{ssEknA$b%y==e`H*HDnV69?_1?D2Y=sb4C-sa@GtWb5mr*+P9=FR?AVi<( z7J9A*Gv`8Sm#amHHz)P;SuNKIr9JbyPi@WwZ;yH>8O(H(ZCp z3uS?ENV3c90oI8_LSU|ja(%0sEb(!g>ss}1!z$yt-fK=PUbi{I34F?eUBGIu zpnexH`{O6Hp+8*R>a(^Mw{s)lUH%K&Y}XMSlI*qZSo2dF@Ra{Tu@u;vuUbQ#AqS)jxDUUdZy@Hgwp;Yh!Hhn?d?tv(mh+NoArh*Ev-moP35h0qfFPp?YkD@Uw!&bBY(`}{l5(hqVj(0*rI4=g@Y>t(Gs8rJ>pkeBJbnim>f+qP7r7HL1_xxV4KDp!O4TwPsDZL8ku zs%ofZf7X0lWu;23F?IH(8N^JEPM#Q+oZpm(GWfRU5~nmw*3C>@GQT%1;rE%@`tNg* zQ$1FES;kWyfGT~7p#2YtcN=cy40&tbT{X`f8*-0)khzEOEF;&zNZmtdN9O&8`xgE2 zE<~Q0W6y)G63n)=NM-j^lzFe_e98Y00#G_sO_tB0%o_ylcxSl(1$GypXTP-L zSvT%x1gQ;eJ17$^yOyMph{gq`f?bc+<6x5Mn78_C!1e2drJ?foZ*J%-&;S4c literal 0 HcmV?d00001 From 31d2edc0918ba13b0cb7a4ac9796332c8f10034c Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Mon, 16 Nov 2015 18:21:11 +0100 Subject: [PATCH 10/14] Updates changelog. --- html/changelog.html | 6 ++++++ html/changelogs/.all_changelog.yml | 4 ++++ html/changelogs/PsiOmegaDelta-CharacterSetup.yml | 4 ---- 3 files changed, 10 insertions(+), 4 deletions(-) delete mode 100644 html/changelogs/PsiOmegaDelta-CharacterSetup.yml diff --git a/html/changelog.html b/html/changelog.html index d0d2dcf652f..dea56093842 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,6 +56,12 @@ -->
+

16 November 2015

+

PsiOmegaDelta updated:

+
    +
  • Added new verb, 'Character Setup' under the Preferences tab, to allow modifying your character settings at any time.
  • +
+

10 November 2015

Atlantis updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index b1d6b2535c6..06439e5b3a9 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -2374,3 +2374,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - tweak: Changes standard and specific plant traits, more diverse plants. Sligneris: - tweak: Modified the wording of NT Default's laws. +2015-11-16: + PsiOmegaDelta: + - rscadd: Added new verb, 'Character Setup' under the Preferences tab, to allow + modifying your character settings at any time. diff --git a/html/changelogs/PsiOmegaDelta-CharacterSetup.yml b/html/changelogs/PsiOmegaDelta-CharacterSetup.yml deleted file mode 100644 index 6e065834bab..00000000000 --- a/html/changelogs/PsiOmegaDelta-CharacterSetup.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: PsiOmegaDelta -delete-after: Truelog. -changes: - - rscadd: "Added new verb, 'Character Setup' under the Preferences tab, to allow modifying your character settings at any time." From d247584d1b163eaa95c5f39521979afdf85ed5a2 Mon Sep 17 00:00:00 2001 From: GinjaNinja32 Date: Wed, 18 Nov 2015 14:38:46 +0000 Subject: [PATCH 11/14] add a sleep inbetween disabling and enabling hardware mode i've been seeing HW mode not always re-enabling, hopefully this'll fix it --- code/modules/client/client procs.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index ecbd78b14d5..3ee7ebcdebe 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -161,6 +161,7 @@ spawn(5) // And wait a half-second, since it sounds like you can do this too fast. if(src) winset(src, null, "command=\".configure graphics-hwmode off\"") + sleep(2) // wait a bit more, possibly fixes hardware mode not re-activating right winset(src, null, "command=\".configure graphics-hwmode on\"") log_client_to_db() From ed7386f30626bb0121250f58d1c63dfed1f375b1 Mon Sep 17 00:00:00 2001 From: Chinsky Date: Thu, 19 Nov 2015 04:06:14 +0300 Subject: [PATCH 12/14] Fixes #11356 --- code/game/machinery/cloning.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index af33673a1f7..5c73084e5db 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -131,6 +131,7 @@ else H.dna = R.dna H.UpdateAppearance() + H.sync_organ_dna() if(heal_level < 60) randmutb(H) //Sometimes the clones come out wrong. H.dna.UpdateSE() @@ -252,7 +253,7 @@ locked = 0 go_out() return 1 - + //Put messages in the connected computer's temp var for display. /obj/machinery/clonepod/proc/connected_message(var/message) if((isnull(connected)) || (!istype(connected, /obj/machinery/computer/cloning))) From ae62b1064ca0d6054ddbc0830a7f2086025ae032 Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Thu, 19 Nov 2015 09:14:04 +0100 Subject: [PATCH 13/14] Map merge conflict fixes. --- maps/exodus-2.dmm | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/maps/exodus-2.dmm b/maps/exodus-2.dmm index 252e587e5ff..0d4dae316b1 100644 --- a/maps/exodus-2.dmm +++ b/maps/exodus-2.dmm @@ -1029,7 +1029,7 @@ "tO" = (/obj/machinery/teleport/station,/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/control) "tP" = (/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/control) "tQ" = (/obj/structure/table/rack,/obj/item/weapon/storage/secure/briefcase,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter/zippo,/obj/item/weapon/storage/belt/utility,/obj/item/weapon/storage/backpack/satchel,/turf/unsimulated/floor{icon_state = "lino"},/area/centcom/creed) -"tR" = (/obj/structure/table/woodentable{dir = 10},/obj/machinery/button/remote/blast_door{id = "CREED"; name = "Spec Ops Ready Room"; pixel_y = 4; req_access = list(108)},/obj/machinery/button/remote/blast_door{icon_state = "doorctrl0"; id = "ASSAULT"; name = "Mech Storage"; pixel_y = -4; req_access = list(108)},/turf/unsimulated/floor{icon_state = "lino"},/area/centcom/creed) +"tR" = (/obj/structure/table/woodentable{dir = 10},/obj/machinery/button/remote/blast_door{id = "CREED"; name = "Spec Ops Ready Room"; pixel_x = -5; pixel_y = 4; req_access = list(108)},/obj/machinery/button/remote/blast_door{icon_state = "doorctrl0"; id = "ASSAULT"; name = "Mech Storage"; pixel_y = -4; req_access = list(108)},/obj/machinery/button/remote/blast_door{id = "ert_synth_equipment"; name = "Synth Equipment"; pixel_x = 5; pixel_y = 4; req_access = list(108)},/turf/unsimulated/floor{icon_state = "lino"},/area/centcom/creed) "tS" = (/obj/machinery/porta_turret/crescent{check_synth = 1; enabled = 1; layer = 2.69},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/unsimulated/floor{icon_state = "lino"},/area/centcom/creed) "tT" = (/obj/effect/floor_decal/corner/green{dir = 9},/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/control) "tU" = (/obj/machinery/mech_recharger,/turf/unsimulated/floor{icon_state = "plating"; name = "plating"},/area/centcom/specops) @@ -1182,7 +1182,7 @@ "wL" = (/obj/mecha/working/hoverpod,/turf/unsimulated/floor{icon_state = "plating"; name = "plating"},/area/centcom/specops) "wM" = (/obj/effect/floor_decal/industrial/outline/yellow,/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/specops) "wN" = (/obj/machinery/door/blast/regular{icon_state = "pdoor1"; id = "CREED"; name = "Ready Room"; p_open = 0},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/specops) -"wO" = (/obj/machinery/door/airlock/centcom{name = "Special Operations"; opacity = 1; req_access = list(103)},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/specops) +"wO" = (/obj/machinery/door/airlock/centcom{name = "Special Operations"; opacity = 1; req_access = list(103)},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/blast/regular{icon_state = "pdoor1"; id = "CREED"; name = "Ready Room"; p_open = 0},/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/specops) "wP" = (/obj/structure/table/reinforced,/obj/item/weapon/storage/box/handcuffs,/obj/item/clothing/glasses/night{pixel_x = -1; pixel_y = -3},/obj/item/clothing/glasses/night{pixel_x = -1; pixel_y = -3},/obj/item/clothing/glasses/night{pixel_x = -1; pixel_y = -3},/obj/item/clothing/glasses/night,/obj/item/weapon/storage/box/handcuffs,/obj/item/clothing/glasses/sunglasses/sechud/tactical,/obj/item/clothing/glasses/sunglasses/sechud/tactical,/obj/item/clothing/glasses/sunglasses/sechud/tactical,/obj/item/clothing/glasses/sunglasses/sechud/tactical,/obj/item/clothing/glasses/sunglasses/sechud/tactical,/obj/item/clothing/glasses/sunglasses/sechud/tactical,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom/specops) "wQ" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/control) "wR" = (/obj/machinery/door/airlock/centcom{name = "Bridge"; opacity = 1; req_access = list(109)},/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/control) @@ -1259,15 +1259,12 @@ "yk" = (/obj/structure/sign/securearea{name = "\improper ARMORY"; pixel_y = 32},/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) "yl" = (/obj/effect/floor_decal/carpet{dir = 1},/obj/effect/floor_decal/carpet,/turf/unsimulated/floor{icon_state = "carpet"; dir = 2},/area/centcom/control) "ym" = (/obj/structure/sign/securearea{name = "ENGINEERING ACCESS"; pixel_y = 32},/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) -"yn" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/unsimulated/floor{icon_state = "white"},/area/centcom/evac) -"yo" = (/turf/unsimulated/floor{icon_state = "white"},/area/centcom/evac) -"yp" = (/obj/structure/table/standard,/turf/unsimulated/floor{icon_state = "white"},/area/centcom/evac) +"yn" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/unsimulated/floor{icon_state = "white"},/area/centcom/control) +"yo" = (/obj/structure/table/standard,/obj/machinery/microwave{pixel_x = -3; pixel_y = 6},/turf/unsimulated/floor{icon_state = "white"},/area/centcom/control) "yq" = (/obj/effect/wingrille_spawn/reinforced/crescent,/turf/unsimulated/floor{icon_state = "dark"},/area/centcom/control) "yr" = (/obj/structure/bed/chair,/turf/unsimulated/floor{icon_state = "white"},/area/centcom/control) "ys" = (/turf/unsimulated/floor{icon_state = "white"},/area/centcom/control) "yt" = (/obj/effect/floor_decal/carpet{dir = 4},/obj/effect/floor_decal/carpet{dir = 8},/turf/unsimulated/floor{icon_state = "carpet"; dir = 2},/area/centcom/control) -"yu" = (/turf/unsimulated/wall,/area/centcom/evac) -"yv" = (/obj/structure/table/standard,/obj/machinery/microwave{pixel_x = -3; pixel_y = 6},/turf/unsimulated/floor{icon_state = "white"},/area/centcom/evac) "yw" = (/obj/effect/floor_decal/corner/green{dir = 4},/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/control) "yx" = (/obj/structure/table/rack,/obj/item/weapon/rig/merc/empty,/turf/unsimulated/floor{icon_state = "dark"},/area/syndicate_mothership) "yy" = (/obj/effect/floor_decal/corner/green{dir = 5},/turf/unsimulated/floor{icon_state = "steel"},/area/centcom/control) @@ -2102,14 +2099,14 @@ aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtUwLvbvbxYtvyauhuhuhuhtvybybtvycyctvtvtvtvxMxQxQuwwNwMwMwMwMwMwOwMwMwMwOtPtPwQwRtPtPwSuFwTtPtPwRwUtPtPxjurururururxjurururururururxjwiwwwwwwwjxcwWxftxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMmu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMujufufufufufufufufufufufufufxhufufufufufxhxixkvbvbuwyjuhuhuhuhuhyjuhuhykuhuhymxnyzyzuhxQxQvdtvvlvlwsvlvltvxQxQxQyAtPtPxytuxzwxxBtPxCwGxDtuxEtPtPxjurururururxjurururururururxjxFxGxGxGxOtxxjxjtxtxtxtxtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvvbvbuwyjuhuhuhuhuhyjuhuhyCuhuhxQyDyDyDxQxQxQzcvlMbyMxQySyQtvtvtvtvtvtPtPvGtuxPtPwItPwIxTxStutTtPtPwAxUxUxUxUxUtxtxxVtxtxtxuOtxtxtxxWxWxWtxtxurururyYurxZtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvvbvbyZtvvlvlvlvlvltvzezetvzfuhxQzgzizhxQxQxQyRzkyMxQxQxQxQxxxQxKzltvtPtPvGtxtxydxXtPyexPtxtxtTtPtPtxaMaMaMaMaMtxyrystxygyfylyiyuynyoyoyoyptxururuQuQururyqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvtvtvtvtvznztzszvzuuhuhuhvlzwuhxQzizCzxxQxQxQxQxxxQxQxQzFzDvlxQxQzGtvtPuVvGtxtxtutututututxtxtTuVtPtxaMaMaMaMaMtxysystxyLyLyLytyuyoyoyoyoyvtxuryNuPuPyOuryqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvuhuhuhuhuhuhuhuhvlzIuhxQzJzJzJxQxQxQxQxxxQxQxQzFzDvlyJyEyFtvtPtPywyyyyyyyyyyyyyyyyyyyBtPtPtxaMaMaMaMaMtxyUystxyLyVyLytyuyuyuyuyuyutxuryNuPuPyOuryqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvuhuhuhuhuhuhuhuhtvwCuhuhzOuhuhuhxQxQwCzkxQxQxQzFzDtvtvtvtvtvtxwAyHxRtxtPtPuVtPtPtxtxtxtxtxtxaMaMaMaMaMtxAbystxyIylylyKyuaMaMaMaMaMtxuryNuPuPyOuryqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM -mtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvAfAfAhAoAnAqApwDtvAsArwqtvxQyPtvwqArAsvlAFxQxQzFzDtvAGAKAJAGyTzayXzbCNtxwAzdxRtxtxaMaMaMaMaMaMaMaMaMaMtxtxtxtxtxtxtxtxyuaMaMaMaMaMyquryNuPuPyOuryqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMzzmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtwgmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmt +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvvbvbyZtvvlvlvlvlvltvzezetvzfuhxQzgzizhxQxQxQyRzkyMxQxQxQxQxxxQxKzltvtPtPvGtxtxydxXtPyexPtxtxtTtPtPtxaMaMaMaMaMtxyrystxygyfylyitxynysysysxWtxururuQuQururyqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvtvtvtvtvznztzszvzuuhuhuhvlzwuhxQzizCzxxQxQxQxQxxxQxQxQzFzDvlxQxQzGtvtPuVvGtxtxtutututututxtxtTuVtPtxaMaMaMaMaMtxysystxyLyLyLyttxysysysysyotxuryNuPuPyOuryqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvuhuhuhuhuhuhuhuhvlzIuhxQzJzJzJxQxQxQxQxxxQxQxQzFzDvlyJyEyFtvtPtPywyyyyyyyyyyyyyyyyyyyBtPtPtxaMaMaMaMaMtxyUystxyLyVyLyttxtxtxtxtxtxtxuryNuPuPyOuryqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvuhuhuhuhuhuhuhuhtvwCuhuhzOuhuhuhxQxQwCzkxQxQxQzFzDtvtvtvtvtvtxwAyHxRtxtPtPuVtPtPtxtxtxtxtxtxaMaMaMaMaMtxAbystxyIylylyKtxaMaMaMaMaMtxuryNuPuPyOuryqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM +mtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvAfAfAhAoAnAqApwDtvAsArwqtvxQyPtvwqArAsvlAFxQxQzFzDtvAGAKAJAGyTzayXzbCNtxwAzdxRtxtxaMaMaMaMaMaMaMaMaMaMtxtxtxtxtxtxtxtxtxaMaMaMaMaMyquryNuPuPyOuryqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMzzmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtwgmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmtmt dCdCdCdCdCdCdCdCdCdCdCAZAZAZAZAZAZAZAZAZAZAZAZAZAZAZAZAZAZAZAZAZdCdCdCdCdCdCdCmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvtvtvtvtvtvtvtvtvtvtvtvtvtvzjzjtvtvtvtvtvBaxQxQzFzDtvAGBbBbAGyTzmyXzbCNzpzozrzqzyCNaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMyqururzLzLururyqaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumumumumumumumumudCBvBvBvBvBvAZBFBzBGAZBvBvBvBvBvBvBvBvBvBvBvmumudCmumumumumtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMzBzNzNzNzNzEzEzNzNzPaMtvBNxQxQzFzDtvAGAJAJAGyTzmyXzbCNzHyXyXyXzKCNaMaMaMaMaMaMaMaMaMaMaMaMzQzMNaNaNazTzRaMaMaMaMaMtxzVururururzWtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM -dCmumumumumumumumumudCBvBvBvBvBvAZBRBzBzAZBvBvBvBvBvBvBvBvBvBvBvmumudCmumumumumtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMzUzXzZAaBSAcAcAdjZzNzPtvtvxxxxtvtvtvlqAGAGAGzYzmyXzbCNAjAiAjAkAjCNaMaMaMaMaMaMaMaMaMaMaMzQAlNiNjNkNlNmAtzRaMaMaMaMtxtxtxtxtxtxtxtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM +dCmumumumumumumumumudCBvBvBvBvBvAZBRBzBzAZBvBvBvBvBvBvBvBvBvBvBvmumudCmumumumumtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMzUzXzZAaBSAcAcAdjZzNzPtvtvyWyWtvtvtvlqAGAGAGzYzmyXzbCNAjAiAjAkAjCNaMaMaMaMaMaMaMaMaMaMaMzQAlNiNjNkNlNmAtzRaMaMaMaMtxtxtxtxtxtxtxtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumumumumumuBvBvBvAZAZAZAZBvAZAZAZAZCgAZAZAZAZAZAZAZBvBvBvBvBvmumudCmumumumumtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMzUAuAmAcAcAcAcAcAcCiChvlxQxQxQxQxQxNAGCjAGCjyTzmyXAwzYyXyXAxyXABCNaMaMaMaMaMaMaMaMaMaMzQAlCoAvADAvADAvCpAtzRaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumumuBvBvBvBvCuCvBzBzBzBzBzBzBzBzBzBzBzBzBzBzBzBzAZBvBvBvBvBvmumudCmumumumumtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMzUAuAEAyAzjSAzAzAzzNAAvlxQxQxQxQxQyWAGCjAGCjyTzmyXAwzYyXyXALAIAMCNaMaMaMaMaMaMaMaMaMaMACADADADCANcANADADADACaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM dCmumumuBvBvBzCFCuCFBzBzBzBzBzBzBzBzBzBzBzBzBzBzBzBzAZCHCGBvBvBvmumudCmumumumumtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMAOzNzNzNzNzNzNzNzNAAaMvlxQxQxQxQxQtvAGCjAGCjyTAQAPARCNAjASAUATAjCNaMaMaMaMaMaMaMaMaMaMAWCRBuNhAXNgAXNfCrCSAWaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM From ff38a6e16a897a228b12d25f3ecfe4cb379d6d86 Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Thu, 19 Nov 2015 09:14:29 +0100 Subject: [PATCH 14/14] Changelog update. --- html/changelog.html | 6 ++++++ html/changelogs/.all_changelog.yml | 4 ++++ html/changelogs/PsiOmegaDelta-DelayedAntag.yml | 4 ---- 3 files changed, 10 insertions(+), 4 deletions(-) delete mode 100644 html/changelogs/PsiOmegaDelta-DelayedAntag.yml diff --git a/html/changelog.html b/html/changelog.html index dea56093842..a630b0accd8 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,6 +56,12 @@ -->
    +

    19 November 2015

    +

    PsiOmegaDelta updated:

    +
      +
    • The round start and auto-antag spawners can now check if players have played long enough to be eligable for selection.
    • +
    +

    16 November 2015

    PsiOmegaDelta updated:

      diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 06439e5b3a9..658500ad035 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -2378,3 +2378,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. PsiOmegaDelta: - rscadd: Added new verb, 'Character Setup' under the Preferences tab, to allow modifying your character settings at any time. +2015-11-19: + PsiOmegaDelta: + - tweak: The round start and auto-antag spawners can now check if players have played + long enough to be eligable for selection. diff --git a/html/changelogs/PsiOmegaDelta-DelayedAntag.yml b/html/changelogs/PsiOmegaDelta-DelayedAntag.yml deleted file mode 100644 index c4d17877643..00000000000 --- a/html/changelogs/PsiOmegaDelta-DelayedAntag.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: PsiOmegaDelta -delete-after: True -changes: - - tweak: "The round start and auto-antag spawners can now check if players have played long enough to be eligable for selection."