diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index 15dccc0a805..4946add50f2 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -134,7 +134,7 @@ CREATE TABLE `SS13_death` ( DROP TABLE IF EXISTS `SS13_donators`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `donators` ( +CREATE TABLE `SS13_donators` ( `patreon_name` varchar(32) NOT NULL, `tier` int(2), `ckey` varchar(32) COMMENT 'Manual Field', diff --git a/_maps/map_files/RandomZLevels/centcomAway.dmm b/_maps/map_files/RandomZLevels/centcomAway.dmm index 479699ce0f2..f37709c438e 100644 --- a/_maps/map_files/RandomZLevels/centcomAway.dmm +++ b/_maps/map_files/RandomZLevels/centcomAway.dmm @@ -520,7 +520,7 @@ "jZ" = (/obj/structure/table,/obj/item/firstaid_arm_assembly,/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/awaymission/centcomAway/hangar) "ka" = (/obj/structure/table,/obj/item/flash,/obj/item/flash,/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/awaymission/centcomAway/hangar) "kb" = (/obj/structure/stool/bed/chair{dir = 1},/mob/living/simple_animal/hostile/russian/ranged{loot = list(/obj/effect/landmark/mobcorpse/russian/ranged)},/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/awaymission/centcomAway/hangar) -"kc" = (/obj/structure/table,/obj/item/mmi/radio_enabled,/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/awaymission/centcomAway/hangar) +"kc" = (/obj/structure/table,/obj/item/mmi,/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/awaymission/centcomAway/hangar) "kd" = (/obj/structure/table,/obj/item/storage/toolbox/mechanical,/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/awaymission/centcomAway/hangar) "ke" = (/obj/machinery/door/airlock/maintenance_hatch{req_access_txt = "101"},/turf/simulated/floor/plating,/area/awaymission/centcomAway/general) "kf" = (/obj/machinery/door/window/northright,/obj/machinery/door/window/southleft,/turf/simulated/floor/plasteel{icon_state = "floor"},/area/awaymission/centcomAway/general) @@ -971,4 +971,3 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "} - diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index 6a8a1ef134c..61aeaa07620 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -6182,7 +6182,7 @@ "coT" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/apmaint) "coU" = (/obj/effect/decal/cleanable/dirt,/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/turf/simulated/floor/plating,/area/maintenance/apmaint) "coV" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/sortjunction{dir = 8; icon_state = "pipe-j1s"; name = "HoP Office"; sortType = 15},/turf/simulated/floor/plating,/area/maintenance/apmaint) -"coW" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/maintenance/apmaint) +"coW" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/maintenance/apmaint) "coX" = (/obj/structure/table/wood,/obj/item/ashtray/glass{pixel_x = -4; pixel_y = -4},/obj/item/lighter/zippo/blue{pixel_x = 7; pixel_y = 4},/turf/simulated/floor/plasteel{icon_state = "bcarpet05"},/area/blueshield) "coY" = (/obj/machinery/keycard_auth{pixel_x = -24; pixel_y = 0},/obj/machinery/door/window{dir = 1; name = "Desk Door"; req_access_txt = "67"},/turf/simulated/floor/wood,/area/blueshield) "coZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4; level = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/turf/simulated/floor/plasteel{dir = 2; icon_state = "whitegreencorner"},/area/medical/virology/lab{name = "\improper Virology Lobby"}) @@ -6279,7 +6279,7 @@ "cqM" = (/turf/simulated/wall/r_wall,/area/medical/cmostore) "cqN" = (/obj/machinery/space_heater,/turf/simulated/floor/plating,/area/medical/cmostore) "cqO" = (/obj/structure/stool/bed/chair/comfy/black{dir = 4},/turf/simulated/floor/carpet,/area/ntrep) -"cqP" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/apmaint) +"cqP" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/maintenance/apmaint) "cqQ" = (/obj/structure/stool/bed/chair/office/dark{dir = 8},/obj/effect/landmark/start{name = "Nanotrasen Representative"},/turf/simulated/floor/carpet,/area/ntrep) "cqR" = (/obj/machinery/requests_console{announcementConsole = 1; department = "Blueshield"; departmentType = 5; name = "Blueshield Requests Console"; pixel_x = -30},/turf/simulated/floor/wood,/area/blueshield) "cqS" = (/obj/structure/table/wood,/obj/item/paper_bin,/obj/item/flashlight/lamp/green{pixel_x = -5; pixel_y = 12},/obj/item/paper/ntrep,/turf/simulated/floor/carpet,/area/ntrep) @@ -6363,7 +6363,7 @@ "css" = (/turf/simulated/floor/plasteel/airless{dir = 4; icon_state = "warning"},/area/toxins/test_area) "cst" = (/turf/simulated/floor/plasteel/airless{tag = "icon-warningcorner (NORTH)"; icon_state = "warningcorner"; dir = 1},/area/toxins/test_area) "csu" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/apmaint) -"csv" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/maintenance/apmaint) +"csv" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/maintenance/apmaint) "csw" = (/obj/structure/filingcabinet,/turf/simulated/floor/wood,/area/ntrep) "csx" = (/obj/machinery/door_control{id = "blueshield"; name = "Privacy Shutters Control"; pixel_x = 0; pixel_y = -24; req_access_txt = "67"},/obj/machinery/computer/crew,/turf/simulated/floor/wood,/area/blueshield) "csy" = (/obj/structure/closet/secure_closet/blueshield,/obj/machinery/firealarm{dir = 8; pixel_x = -24},/turf/simulated/floor/wood,/area/blueshield) @@ -6897,7 +6897,7 @@ "cCG" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/consarea) "cCH" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plating,/area/maintenance/apmaint) "cCI" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0; tag = ""},/obj/machinery/door/firedoor,/obj/machinery/door/airlock/maintenance{name = "Alternate Construction Area"; req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/consarea) -"cCJ" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/apmaint) +"cCJ" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/maintenance/apmaint) "cCK" = (/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/storage/tech) "cCL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/wall,/area/storage/tech) "cCM" = (/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/structure/cable,/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/storage/tech) @@ -7023,7 +7023,7 @@ "cFc" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cFd" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'KEEP CLEAR OF DOCKING AREA'."; name = "KEEP CLEAR: DOCKING AREA"; pixel_y = 0},/turf/simulated/wall/r_wall,/area/engine/mechanic_workshop) "cFe" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/door/firedoor,/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/apmaint) -"cFf" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/apmaint) +"cFf" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/structure/disposalpipe/junction{dir = 1; icon_state = "pipe-y"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/plasteel{dir = 4; icon_state = "yellowcorner"},/area/hallway/primary/aft) "cFg" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/disposalpipe/segment,/obj/item/radio/intercom{dir = 8; name = "station intercom (General)"; pixel_x = -28},/turf/simulated/floor/plasteel{dir = 8; icon_state = "cautioncorner"},/area/hallway/primary/aft) "cFh" = (/obj/machinery/atmospherics/unary/portables_connector{dir = 4},/obj/machinery/portable_atmospherics/pump,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/plasteel{icon_state = "arrival"; dir = 8},/area/hallway/primary/aft) "cFi" = (/obj/machinery/camera{c_tag = "Atmospherics Access"; dir = 4; network = list("SS13")},/obj/machinery/light{dir = 8},/obj/item/radio/intercom{frequency = 1459; name = "station intercom (General)"; pixel_x = -28},/obj/machinery/atmospherics/pipe/simple/hidden/yellow{tag = "icon-intact (SOUTHEAST)"; icon_state = "intact"; dir = 6},/turf/simulated/floor/plasteel,/area/engine/controlroom) @@ -7091,7 +7091,6 @@ "cGs" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1; initialize_directions = 11; level = 1},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel{dir = 4; icon_state = "yellowcorner"},/area/hallway/primary/aft) "cGt" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel{dir = 4; icon_state = "yellowcorner"},/area/hallway/primary/aft) "cGu" = (/obj/structure/disposalpipe/junction{dir = 8; icon_state = "pipe-j2"; tag = "icon-pipe-j1 (WEST)"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{dir = 4; icon_state = "yellowcorner"},/area/hallway/primary/aft) -"cGv" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/disposalpipe/junction{dir = 1; icon_state = "pipe-y"},/turf/simulated/floor/plasteel{dir = 4; icon_state = "yellowcorner"},/area/hallway/primary/aft) "cGw" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{dir = 4; icon_state = "yellowcorner"},/area/hallway/primary/aft) "cGx" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{dir = 4; icon_state = "yellowcorner"},/area/hallway/primary/aft) "cGy" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/camera{c_tag = "Aft Primary Hallway 3"; dir = 2; network = list("SS13")},/turf/simulated/floor/plasteel{dir = 4; icon_state = "yellowcorner"},/area/hallway/primary/aft) @@ -9065,18 +9064,18 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaebPIclCclDclEbRGbRAclFbRGclGclIbRAbPIbPIbYvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaceYcincincinceYbYPclJclMclKckncfbcfbclLclOclNclQclPclPclPclTcgQcgQcgQciCcgSclRcktclScktclVcgWckvckwclUckwclWcgWclYcHDclZchccmccmacmbcmechbcgXchcchdchgchfchfchichfchfchfcsLcbvchfchkchjchmchlcfEchncfGcfFchocfHchqchpchtchscDfchuchvcDfchxchwchzchychBchAchEchDcepchFcgachGclpclncmMcjGcjGcjGcmQcmOclpcbjcmPccZclrclrcbjcmTbUzcbnbPtcmScmVcmUcgscmWcmYcmXcnbcmZcnacnfcgucnccndcnecgucgscgscgscgEcgEcgEcgEcgEaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaacnkcieclBciecieckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaebPIbPIbPIbPIbPIbPIbPIbPIbPIbPIbYvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaabafOcgQcngcngcgQcngcngcgQaaaaaacgFcnhcnicnjcgFbYPbYPbYPcamcnmcnlcnocnocnocamcamcgQcnncnpcnrcnqcgQcnscntcgSclRcktcktcktcnvcgWckvckwckwcnuchHcgWcpicHDcnAchcchcchcchcchcchIchcchccnCdgCcsLcsLcsLchfcABchJcsLcbvchfchLchKciEchNcfEciFcfGcfFcfIcfHciOciJciQciPcDfciRciScDfciUciTchrciVciXciWchrchrcepciYcjaciZclpcjbcodcoicoicoicodcogcodcodcohcojclrclrcbjcokclscbncomcolcooconcorcopcoqcoqcotcoscovcoucoxcowcozcoycoCcoAcoBcoDcoEcoFcoHcoGcoIaabaabaabaabaabaabaabaabaaaaaaaaaaaaaaacidciecoMcoJcoJckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaacgQcoKcoLcgQcoKcoLcgQaaaaaacoOceZcoNceZcoQaaaaabaaacamcamcamcamcamcamcamcoPcgQcoScoRcoUcoTclPcoVcoWcgScoYcoXcpfcktcjccgWcjdckwcjfcjecjgcgWcjicjhcjkcjjcpqcpqcpqcpqcjlcpmcppcpocjncjmcjmcjocjqcjpcjscjrcjtchfcjwcjucjycjxcjAcjzcjCcjBcjCcjDckrcjEckxcksckzckyckAcDfckBcuvckCcjvckDcmDckFckEciYckJckLcgacpRcpTcpRcpUcpWcpVcpRcpXcpYcodcqacpZcdacbjcbjcqccqbcqfcqdcqecqicqgcqhcqlcqjcqkcqncqmcqpcqocqtcqqcqrcqqcqscqrcqrcqucqwcqvcqycqxcqCaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaacieciecqDckbckbckbckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafOaaaafOcgQcqzcoLcgQcqzcoLcgQaaaaaaaabaabaabaabaabaabaabaabaabcgQcoLcqAcqBcgQcqEcqGcgQcqHcgQcgQcqFcgQcgQcqPcgScqRcqIcqJcqKcqLcgWckMcqOcqScqQcqTcgWckOckNckPcJZcsDcsDcsDcsDcsDcrdcqZcrackQchfcucckRcsLckSckTcsLcsKchfckVckUckXckWcCWckYclackZclbcDfcldclcclfclecDfcDfcDfcDfclhclgckCchCcljclicllclkciYcmdcgacmfcpRcrNcrQcrLcrMcrLcrTcrOcrPcodcbjcrUcbjcbjcrRcrSclsbLRbPtcgscrVcgscgscrWcrYcrXcsacrZcsdcsbcsfcsecsgcsecsgcshcsgcsicgEcsncrwcsqcsraabaabaabaabaabaabaabaabaaaaaaaaaaaaaaacieckbckbckbckbckbckbcssckbcstckbckbckbckbckbciecieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcsjafOaabaMraMrafOcgQcgQcqFcgQcgQcqFcgQcgQcgQcngcngcngcgQcgQcgQcgQcgQcgQcgQcoLcskcslcgQcsmcgQcgQcsucgQcsocspcoLcgQcsvcgScsycsxcszclRcmgcgWcswckvcsEcsCcmhcgWcsIcsHcmicsDcsDcsNcsOcsGcmjcsQcsJcsKcsLcsUchfcmkcsLckSckTchfchfchfcCWcCWcmlcCWcCWcxhcnwcmmcxhcDfcDfcDfcDfcDfcDfcmncmpcmocmrcmqcmtcmscmvcmucmxcmwciYcgacgaaqEcpRcttctxctwctyctwctActzcrLctuctvctBbLRctCbLRcrSclsbLRbIictFctHctGcgscgscgscgscgsctIcqkctKctDcsccqkctEcqkclucqkctLcgEctOctQctPcgEaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaciectJctJctJctJctJctJctSckbctTctJcstckbckbckbckbcieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabafOafOcngcoLcoLcoLcoLctMctNcoLcoLcoSctUctUctVctUctUctUctUctUctUctUctUctUctUctUctUcoRcgQcskcqzctWcgQcsvctRctRctRctRctRctRcgWcgWcgWcgWcgWcgWcgWcuactXcmBcmzcmEcmCcmFcmFcmGcuicsJcmHcsLcubcuccmIcsLckScmJchicsLcsLcsKcCWcmLcmKcmNcCWcHWcnxcnBcnzcnEcnDcnGcnFcnIcnHcnKcnJcnMcnLckCcnNcnPcnOcnRcnQciYbQXcgacgacpRcuGcnTcnScnUcrLcuKcuJcuOcuLcuScuRcuVbLRcuXcrSclscuMbIibPAcuNcuYcuPcuQbGGbGGcgscvccvecuTcuUcvfcuWcvgcvicuZcvacvbcgEcvjdoKdoFcvraaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaacvscjZcjZcjZcjZcjZcjZcjZcvhcvtckbckbckbckbcvvckccieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabafOaabaabafOcngcvkcvlcvmcoLcoLcvncoLcoLcsucgQcgQcgQcgQcgQcgQcqFcgQcgQcgQcgQcvocvocvocvocvocvocvocvocvocgQcsvcvpaaaaaaaaaaaacvqcvwcvzcvycvucvAcvDcvxcvJcvGcvKcvBcvCcvLcvEcvEcvFcvMcvHcvIcvIcvIcvIcvNcvIckScmJchfcnVcKOdercCWcnXcnWcnZcnYcobcoacoccoccofcoecpacoZcpccpbcpecpdcphcpgciYciYciYciYciYciYciYciYcpkcpjcpRcwjcplcwqcptcpncpvcpucpRcpRbIicwpbIibIibIicwvcwJcwwbIibGGcuNcwKcwucuQcuQcuQcgscgscgscgscgscgscgscgscgscgscgscgscgEcgEcgEcgEcgEaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaciecoJcoJcoJcoJcoJcoJcwLckbcoMcoJcwMckbckbckbckbcieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcgQcwxcwxcwxcwxcwxcwxcwycwxcsucwzcgQcoLcwAcwBcwCcoLcwCcwDcwEcwBcvocwFcwFcvocwGcvocwHcwIcvocoLcqPcngaaacwPcwUcwQcwVcwNcwOcwWcwXcwRcwScwTcwZcwYcxbcxacxdcxccxfcxecxjcxgcvHcxkcxmcxmcxmcxocvIckScmJchfdgmcQkcQkcQkcQkcpwcpxcQkcpycpycpycpycQkcpzcpBcpAcQkcQncQncpCcpDcuocukbQXbQXcpEbQXbQXbQXbQXbQXcpFcpRcpRcpRcpRcpGcpRcpRcpRcxIcpHcpIcxKcxUcxMcxNcxOcxWcxQcxNbGGcuNcylbGGbGGcxScxZcyactFbGGbGGbGGbGGbGGbGGbGGcxVcymbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacieckbckbckbckbckbckbcssckbcwMckbckbckbckbckbciecieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxXcxYcxYcxYcxYcxYcxYcyocyncybcyccydcyecyfcwycsucygcgQcoLcoLcwBcoLcoLcoLcwDcqBcwBcvocwFcyicwIcwIcyjcwIcykcvocypcqPcngaaacyrcytcyscyvcyqcwOcywcyAcyycyucvxcyCcsHcyEcvBcyxctYcyFctYcyzcyGcyBcyHcyDcyDcyDcyIcvIckScmJchfcQkcQkcpKcpJcQkcQkcQkcQkcpMcpLcpOcpNcQkcQkcpPcQkcQkcTBdgmbQVcpScuvcqMcqMcqMcqMcqMcqMcqNbQXcqWcqUcqXcqXcqXcqYcrccrbcrbcrfcrbcrbcrbcrgczmczmcricrhcrjczwczzczyczBczAczCczCczDczCczCczCczCczGczIczCczCczCczOczLbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacieciecqDckbckbckbckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaczEczFczFczFczFczPczHczQczJczKczKczRcwxcsucoLcqFcoLcoLcoLcoLcoLcoLcoLcoLcoLcvocvocwIczMcwIcvocwIczMcvoczNcsvcngaaacyrczTczSczVczUczXczWczYczUczUcAacAccAbcAdczZczZcAecAfctYcAhcAgcyBcyDcyDcyDcyDcAicvIcrkcmJcrlcQkcrmcrocrncUTcrpcrrcrqcrtcrscrvcrucQncrxctecrycQkcrzcsLcukcrBcuvcrEcrCcrGcrFcrHcqMcqMbUxcrJcrIcrKcrKcrKcrKcsBcsAcsMcsFcsRcsPcsPcAKcAKcAJcALcAVcAYcAWcAPcAPcAQcAZcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAScBecAUbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacnkcieciectJctJckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacBicBgcAXcBjcAXcBmcBacBbcBccBdcBncwxcsucgQcgQcBfcngcngcngcngcngcngcngcBocvocwIcwIcwIcwIcBhcwIcwIcvocygcqPcngaaacyrcBrcBqcBkcBlcwOcBscBucBtcBpcvxcyCcsHcnycBvcsDcBzcsDcvBcvBcvBcBDcBBcyDcyDcBFcBEcvIckScmJcsLcQkcsScsVcsTcsXcsWcsZcsYctbctactdctcctfctgcthcuqcQkcsLcJGbQVctjctictlctkctnctmctpctocqMctqctrcfZcepcepcepcepcepctsctsctscepcepaaaaaaaaaaaacBRcBScCacBUcAPcCdcCfcCecCgcBZcChcCbcCccCicCkcCjcCmcClcCncAPcAScCocCrcCpcCscCscCscCscCscCscCscCscCscCscCscCscCscCscCscCscCscCscCvcCucieclBcieckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacBicCwcCxcCqcCyczJcCtcCzcCBczJcCDcCCcCEcskcgQcoLcngaaaaaaaaaaaaaaacngcoLcCFcwFcCAcwIcwIcwIcwIcCGcCIcCHcCJcngaaacCMcwUcCNcwVcCOcwOcwOcCRcCPcCKcCLcCUcCTcCVcBvcsDcCYcCQcCZcCScDacvHcDccyDcyDcyDcDdcvIckScmJctZcQkcudcufcuecUTcugcujcuhcumculcupcuncQncurcvdcuscQkcsLcrDcrDcuucutcuxcuwcuzcuycuBcuAcqMcuCcuDbQXcepaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcDycDAcDzcDucDBcDwcDwcDCcDwcDwcDwcDwcDwcDEcDDcDGcDFcDHbGHcDIcjYbGHbGHaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciecDJcDMcDKciecieckbckbcDNckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacBicDPcAXcDUcAXcDVcDLcDXcDZcBbcDOcwxcAFcqBcgQcqzcvpaaaaaaaaaaaaaaacvpcDQcvocwFcwFcwFcDScDTcwIcEbcvocoLcqPcvpaaaaaaaaaaaacvqcEdcDWcEecEecvxcDYcvxcEfcsHcnycEicEjcEccElcEkcEkcEkcEscEgcyDcEhcyDcEtcvIckScmJcuEcQkcuFcuIcuHcQkcvOcUTcvPcvQcQncQncQncQkcQkcQkcQkcQkcsLcrDcvRcvTcvScuxcvUcvWcvVcvYcvXcqMcsLctrbQXcepaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcEHcEOcENcERcEQcEXcEVcEZcDwcDwcEPcDwcDwcDEcDGcDGcDGcFbbGHcFcbGGbGHaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciccEScETclAcidciecieckbckcckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacEUcEUcEUcEUcEUcwxcFdcEWcEWcEWcEWcEWcFecEYcEYcEYcEWcEWcEWcEWcEWcEWcEWcEYcEYcEYcvocvocvocvocvocvocvocqFcFfcFacFacFacFacFacvqcvxcvxcvxcvxcvxcvxcvxcFgcsHcnycFhcFjcFicFlcFkcFrcFocFucFtcFwcFmcFncFBcvIckScmJcKOcBPcvZdcCcQkcQkcwacwbcUTcwdcwccwfcwecwhcwgcwicQkcPccnVcrDcwkcwmcwlcuxcuxbUAcwncwscwrcqMcsLctrbQXctsaaaaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcFNcFPcFOcFKcFQcFMcFRcFScDwcDwcDwcDwcFTcFYcFUcGacFZcGdbGHcFcbGGbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacicciccicciccidcidcieciecieciecijaabaabaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaacFVcFWcFXcGecFXcGfcFWcGgcGbcGccGccGicAGcGkcDRcGmcGlcGocGncGqcGpcGpcGrcGpcGscGtcGtcGvcGucGxcGwcGycGwcGwcGwcGxcGwcGwcGzcGBcGAcGDcsHcnycGJcGNcGMcGCcsDcGOczZcGEcGFcGGcGHcxicwtcGKckScmJcxlchfdcDcxpcxncQkcxqcxrcUTcxtcxscxvcxucUTcxwcxxcQkcsLcBwcrDcxycmycxzcxBcuxcBPcBPcBPcBPchfcebctrbQXctsaaaaaaaabaabaabaaaaaaaaaaaaaaaaaaaaaaaacBScBRcHmcHgcBScHncHicHjcHvcHtcHxcHwcDwcDwcHocHpcHqcHrcHsbGHcFcbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafOaaaafOcgQcqzcoLcgQcqzcoLcgQaaaaaaaabaabaabaabaabaabaabaabaabcgQcoLcqAcqBcgQcqEcqGcgQcqHcgQcgQcqFcgQcgQciCcgScqRcqIcqJcqKcqLcgWckMcqOcqScqQcqTcgWckOckNckPcJZcsDcsDcsDcsDcsDcrdcqZcrackQchfcucckRcsLckSckTcsLcsKchfckVckUckXckWcCWckYclackZclbcDfcldclcclfclecDfcDfcDfcDfclhclgckCchCcljclicllclkciYcmdcgacmfcpRcrNcrQcrLcrMcrLcrTcrOcrPcodcbjcrUcbjcbjcrRcrSclsbLRbPtcgscrVcgscgscrWcrYcrXcsacrZcsdcsbcsfcsecsgcsecsgcshcsgcsicgEcsncrwcsqcsraabaabaabaabaabaabaabaabaaaaaaaaaaaaaaacieckbckbckbckbckbckbcssckbcstckbckbckbckbckbciecieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcsjafOaabaMraMrafOcgQcgQcqFcgQcgQcqFcgQcgQcgQcngcngcngcgQcgQcgQcgQcgQcgQcgQcoLcskcslcgQcsmcgQcgQcsucgQcsocspcoLcgQcqPcgScsycsxcszclRcmgcgWcswckvcsEcsCcmhcgWcsIcsHcmicsDcsDcsNcsOcsGcmjcsQcsJcsKcsLcsUchfcmkcsLckSckTchfchfchfcCWcCWcmlcCWcCWcxhcnwcmmcxhcDfcDfcDfcDfcDfcDfcmncmpcmocmrcmqcmtcmscmvcmucmxcmwciYcgacgaaqEcpRcttctxctwctyctwctActzcrLctuctvctBbLRctCbLRcrSclsbLRbIictFctHctGcgscgscgscgscgsctIcqkctKctDcsccqkctEcqkclucqkctLcgEctOctQctPcgEaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaciectJctJctJctJctJctJctSckbctTctJcstckbckbckbckbcieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabafOafOcngcoLcoLcoLcoLctMctNcoLcoLcoSctUctUctVctUctUctUctUctUctUctUctUctUctUctUctUcoRcgQcskcqzctWcgQcqPctRctRctRctRctRctRcgWcgWcgWcgWcgWcgWcgWcuactXcmBcmzcmEcmCcmFcmFcmGcuicsJcmHcsLcubcuccmIcsLckScmJchicsLcsLcsKcCWcmLcmKcmNcCWcHWcnxcnBcnzcnEcnDcnGcnFcnIcnHcnKcnJcnMcnLckCcnNcnPcnOcnRcnQciYbQXcgacgacpRcuGcnTcnScnUcrLcuKcuJcuOcuLcuScuRcuVbLRcuXcrSclscuMbIibPAcuNcuYcuPcuQbGGbGGcgscvccvecuTcuUcvfcuWcvgcvicuZcvacvbcgEcvjdoKdoFcvraaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaacvscjZcjZcjZcjZcjZcjZcjZcvhcvtckbckbckbckbcvvckccieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabafOaabaabafOcngcvkcvlcvmcoLcoLcvncoLcoLcsucgQcgQcgQcgQcgQcgQcqFcgQcgQcgQcgQcvocvocvocvocvocvocvocvocvocgQcqPcvpaaaaaaaaaaaacvqcvwcvzcvycvucvAcvDcvxcvJcvGcvKcvBcvCcvLcvEcvEcvFcvMcvHcvIcvIcvIcvIcvNcvIckScmJchfcnVcKOdercCWcnXcnWcnZcnYcobcoacoccoccofcoecpacoZcpccpbcpecpdcphcpgciYciYciYciYciYciYciYciYcpkcpjcpRcwjcplcwqcptcpncpvcpucpRcpRbIicwpbIibIibIicwvcwJcwwbIibGGcuNcwKcwucuQcuQcuQcgscgscgscgscgscgscgscgscgscgscgscgscgEcgEcgEcgEcgEaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaciecoJcoJcoJcoJcoJcoJcwLckbcoMcoJcwMckbckbckbckbcieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcgQcwxcwxcwxcwxcwxcwxcwycwxcsucwzcgQcoLcwAcwBcwCcoLcwCcwDcwEcwBcvocwFcwFcvocwGcvocwHcwIcvocoLciCcngaaacwPcwUcwQcwVcwNcwOcwWcwXcwRcwScwTcwZcwYcxbcxacxdcxccxfcxecxjcxgcvHcxkcxmcxmcxmcxocvIckScmJchfdgmcQkcQkcQkcQkcpwcpxcQkcpycpycpycpycQkcpzcpBcpAcQkcQncQncpCcpDcuocukbQXbQXcpEbQXbQXbQXbQXbQXcpFcpRcpRcpRcpRcpGcpRcpRcpRcxIcpHcpIcxKcxUcxMcxNcxOcxWcxQcxNbGGcuNcylbGGbGGcxScxZcyactFbGGbGGbGGbGGbGGbGGbGGcxVcymbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacieckbckbckbckbckbckbcssckbcwMckbckbckbckbckbciecieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxXcxYcxYcxYcxYcxYcxYcyocyncybcyccydcyecyfcwycsucygcgQcoLcoLcwBcoLcoLcoLcwDcqBcwBcvocwFcyicwIcwIcyjcwIcykcvocypciCcngaaacyrcytcyscyvcyqcwOcywcyAcyycyucvxcyCcsHcyEcvBcyxctYcyFctYcyzcyGcyBcyHcyDcyDcyDcyIcvIckScmJchfcQkcQkcpKcpJcQkcQkcQkcQkcpMcpLcpOcpNcQkcQkcpPcQkcQkcTBdgmbQVcpScuvcqMcqMcqMcqMcqMcqMcqNbQXcqWcqUcqXcqXcqXcqYcrccrbcrbcrfcrbcrbcrbcrgczmczmcricrhcrjczwczzczyczBczAczCczCczDczCczCczCczCczGczIczCczCczCczOczLbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacieciecqDckbckbckbckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaczEczFczFczFczFczPczHczQczJczKczKczRcwxcsucoLcqFcoLcoLcoLcoLcoLcoLcoLcoLcoLcvocvocwIczMcwIcvocwIczMcvoczNcqPcngaaacyrczTczSczVczUczXczWczYczUczUcAacAccAbcAdczZczZcAecAfctYcAhcAgcyBcyDcyDcyDcyDcAicvIcrkcmJcrlcQkcrmcrocrncUTcrpcrrcrqcrtcrscrvcrucQncrxctecrycQkcrzcsLcukcrBcuvcrEcrCcrGcrFcrHcqMcqMbUxcrJcrIcrKcrKcrKcrKcsBcsAcsMcsFcsRcsPcsPcAKcAKcAJcALcAVcAYcAWcAPcAPcAQcAZcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAScBecAUbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacnkcieciectJctJckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacBicBgcAXcBjcAXcBmcBacBbcBccBdcBncwxcsucgQcgQcBfcngcngcngcngcngcngcngcBocvocwIcwIcwIcwIcBhcwIcwIcvocygciCcngaaacyrcBrcBqcBkcBlcwOcBscBucBtcBpcvxcyCcsHcnycBvcsDcBzcsDcvBcvBcvBcBDcBBcyDcyDcBFcBEcvIckScmJcsLcQkcsScsVcsTcsXcsWcsZcsYctbctactdctcctfctgcthcuqcQkcsLcJGbQVctjctictlctkctnctmctpctocqMctqctrcfZcepcepcepcepcepctsctsctscepcepaaaaaaaaaaaacBRcBScCacBUcAPcCdcCfcCecCgcBZcChcCbcCccCicCkcCjcCmcClcCncAPcAScCocCrcCpcCscCscCscCscCscCscCscCscCscCscCscCscCscCscCscCscCscCscCvcCucieclBcieckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacBicCwcCxcCqcCyczJcCtcCzcCBczJcCDcCCcCEcskcgQcoLcngaaaaaaaaaaaaaaacngcoLcCFcwFcCAcwIcwIcwIcwIcCGcCIcCHcsvcngaaacCMcwUcCNcwVcCOcwOcwOcCRcCPcCKcCLcCUcCTcCVcBvcsDcCYcCQcCZcCScDacvHcDccyDcyDcyDcDdcvIckScmJctZcQkcudcufcuecUTcugcujcuhcumculcupcuncQncurcvdcuscQkcsLcrDcrDcuucutcuxcuwcuzcuycuBcuAcqMcuCcuDbQXcepaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcDycDAcDzcDucDBcDwcDwcDCcDwcDwcDwcDwcDwcDEcDDcDGcDFcDHbGHcDIcjYbGHbGHaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciecDJcDMcDKciecieckbckbcDNckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacBicDPcAXcDUcAXcDVcDLcDXcDZcBbcDOcwxcAFcqBcgQcqzcvpaaaaaaaaaaaaaaacvpcDQcvocwFcwFcwFcDScDTcwIcEbcvocoLciCcvpaaaaaaaaaaaacvqcEdcDWcEecEecvxcDYcvxcEfcsHcnycEicEjcEccElcEkcEkcEkcEscEgcyDcEhcyDcEtcvIckScmJcuEcQkcuFcuIcuHcQkcvOcUTcvPcvQcQncQncQncQkcQkcQkcQkcQkcsLcrDcvRcvTcvScuxcvUcvWcvVcvYcvXcqMcsLctrbQXcepaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcEHcEOcENcERcEQcEXcEVcEZcDwcDwcEPcDwcDwcDEcDGcDGcDGcFbbGHcFcbGGbGHaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciccEScETclAcidciecieckbckcckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacEUcEUcEUcEUcEUcwxcFdcEWcEWcEWcEWcEWcFecEYcEYcEYcEWcEWcEWcEWcEWcEWcEWcEYcEYcEYcvocvocvocvocvocvocvocqFcCJcFacFacFacFacFacvqcvxcvxcvxcvxcvxcvxcvxcFgcsHcnycFhcFjcFicFlcFkcFrcFocFucFtcFwcFmcFncFBcvIckScmJcKOcBPcvZdcCcQkcQkcwacwbcUTcwdcwccwfcwecwhcwgcwicQkcPccnVcrDcwkcwmcwlcuxcuxbUAcwncwscwrcqMcsLctrbQXctsaaaaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcFNcFPcFOcFKcFQcFMcFRcFScDwcDwcDwcDwcFTcFYcFUcGacFZcGdbGHcFcbGGbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacicciccicciccidcidcieciecieciecijaabaabaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaacFVcFWcFXcGecFXcGfcFWcGgcGbcGccGccGicAGcGkcDRcGmcGlcGocGncGqcGpcGpcGrcGpcGscGtcGtcFfcGucGxcGwcGycGwcGwcGwcGxcGwcGwcGzcGBcGAcGDcsHcnycGJcGNcGMcGCcsDcGOczZcGEcGFcGGcGHcxicwtcGKckScmJcxlchfdcDcxpcxncQkcxqcxrcUTcxtcxscxvcxucUTcxwcxxcQkcsLcBwcrDcxycmycxzcxBcuxcBPcBPcBPcBPchfcebctrbQXctsaaaaaaaabaabaabaaaaaaaaaaaaaaaaaaaaaaaacBScBRcHmcHgcBScHncHicHjcHvcHtcHxcHwcDwcDwcHocHpcHqcHrcHsbGHcFcbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacFVcFWcFXcFXcFXcGfcFWcHycFXcANcFXcHBcEacHEcGjcHzcHucHzcHFcHJcHDclXcHDcHDcHKcnAcnAcHDcHGcHDcHDcHDcHDcHDcHDcHDcHDcHDcHDcHHcHIcHMcHLcHOcHNcHUcHTcHPcHQcHRbWTcdGcaycHVcHYcxDcxCcGKckScmJctZcucdducxEddwcQkcxFcxGcUTcxJcxHcxPcxLcUTcxRcxTcQkcyJcsLcrDcyKcyMcyLcpQcrDcyNcyNchfcyOcyPcebctrbQXctsaaaaaaaaaaabaabaabaaaaaaaaaaaaaaaaaaaaacBRcHAcHXcHCcBRcAPcAPcAPcAPcAPcAPcICcHwcIDcIHcIFcIEcAPcAPbGHcFcbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacFVcIIcFXcIGcFXcGfcIJcIMcIKcINcILcITcIzcIBcIAcIQcIRcIScIVcIXcIWcJacIYcJbcqVcIZcqVcIXcJccIXcIXcIXcIXcIXcIXcIXcIXcIXcIXcJdcHDcKmcJecJicJhcJgcJjcJodcdcfjcfhcgRcfucJycJpcyRcyQcGKckScmJcsLchfchfcySchfcQkcQkcQkcQkcyVcyUcyXcyWcUTcyYczacyZcyJcsLchfchfchfchfchfchfcsLcyNchfczbchfcsLctrbQXcepaaaaaaaaaaaaaabcBRcBRcBRcBRcBRcBRcBRcBRcBRcIOcJNcIPcxNcJKcJKcJLcBRaabcAPcAPcJOcAPcJTcJRcJPcAPcJQcuQcFcbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacJUcJScEWcEWcEWcEWcJYcEYcEYcEYcEYcKacEYcJVcJVcJVcJWcJXcKdcEYcJZcKgcKbcKbcKicKbcKjcKbcKbcKecKfcKbcKbcKfcKfcKfcKbcKbcKbcKbcKkcKhcLKcKlcKtcKqcKxcKndcgcKncKncKncKnchWcKycKrczccKzcGKczdczecsLczfcsLcYiczgcuccTBcKOcyZcQkcQkcQkcQkcQkcQkcQkcQkcsLcKOchfczhczjcziczkchfczlchfchfchfchfchfctrbQXcepaaaaaaaaaaaaaaacBRcKPcKQcKRcKWcIUcKYcKXcxNcJkcJmcJlcxNcJKcKZcLacBRaabaabcLbcLkcLjcLecLlcLgcLbbGGbGGcFccLhbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 67a187c45db..4612c8cdce3 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -370,4 +370,7 @@ // used for alternate_option #define GET_RANDOM_JOB 0 #define BE_ASSISTANT 1 -#define RETURN_TO_LOBBY 2 \ No newline at end of file +#define RETURN_TO_LOBBY 2 + +//Melting Temperatures for various specific objects +#define GIRDER_MELTING_TEMP 5000 \ No newline at end of file diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 1d47ae409b3..056bc25be5d 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -129,6 +129,9 @@ #define TINT_BLIND 3 //Threshold of tint level to obscure vision fully #define EYE_SHINE_THRESHOLD 6 //dark_view threshold past which a humanoid's eyes will 'shine' in the dark. +#define EMOTE_VISUAL 1 //A mob emote is visual +#define EMOTE_SOUND 2 //A mob emote is sound + //Human sub-species #define isshadowling(A) (is_species(A, /datum/species/shadow/ling)) #define isshadowlinglesser(A) (is_species(A, /datum/species/shadow/ling/lesser)) diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 9f21eb23e2d..16193241ca8 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -284,9 +284,12 @@ SUBSYSTEM_DEF(air) /datum/controller/subsystem/air/proc/setup_allturfs(var/list/turfs_to_init = block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz))) var/list/active_turfs = src.active_turfs + // Clear active turfs - faster than removing every single turf in the world + // one-by-one, and Initalize_Atmos only ever adds `src` back in. + active_turfs.Cut() + for(var/thing in turfs_to_init) var/turf/T = thing - active_turfs -= T if(T.blocks_air) continue T.Initialize_Atmos(times_fired) diff --git a/code/datums/diseases/lycancoughy.dm b/code/datums/diseases/lycancoughy.dm index 2c5a8752cbb..b50b7e0a0c3 100644 --- a/code/datums/diseases/lycancoughy.dm +++ b/code/datums/diseases/lycancoughy.dm @@ -10,6 +10,7 @@ viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/human/monkey) desc = "If left untreated subject will regurgitate... puppies." severity = MEDIUM + var/barklimit = 0 /datum/disease/lycan/stage_act() ..() @@ -33,13 +34,21 @@ affected_mob.visible_message("[affected_mob] howls!", \ "You howl!") affected_mob.AdjustConfused(rand(6, 8)) - if(prob(3)) + if(prob(3) && barklimit <= 10) var/list/puppytype = list(/mob/living/simple_animal/pet/corgi/puppy, /mob/living/simple_animal/pet/pug, /mob/living/simple_animal/pet/fox) var/mob/living/puppypicked = pick(puppytype) affected_mob.visible_message("[affected_mob] coughs up [initial(puppypicked.name)]!", \ "You cough up [initial(puppypicked.name)]?!") - affected_mob.emote("cough") - affected_mob.adjustBruteLoss(5) new puppypicked(affected_mob.loc) new puppypicked(affected_mob.loc) + barklimit ++ + if(prob(1)) + var/list/plushtype = list(/obj/item/toy/plushie/orange_fox, /obj/item/toy/plushie/corgi, /obj/item/toy/plushie/robo_corgi, /obj/item/toy/plushie/pink_fox) + var/obj/item/toy/plushie/coughfox = pick(plushtype) + new coughfox(affected_mob.loc) + affected_mob.visible_message("[affected_mob] coughs up a [initial(coughfox.name)]!", \ + "You cough [initial(coughfox.name)] up ?!") + + affected_mob.emote("cough") + affected_mob.adjustBruteLoss(5) return diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 72f5b6545c8..015fa78df29 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -1,5 +1,5 @@ //wrapper -/proc/do_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null) +/proc/do_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, bypass_area_flag=FALSE) var/datum/teleport/instant/science/D = new if(D.start(arglist(args))) return 1 @@ -14,14 +14,15 @@ var/soundin //soundfile to play before teleportation var/soundout //soundfile to play after teleportation var/force_teleport = 1 //if false, teleport will use Move() proc (dense objects will prevent teleportation) + var/ignore_area_flag = FALSE -/datum/teleport/proc/start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null) +/datum/teleport/proc/start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, bypass_area_flag=FALSE) if(!initTeleport(arglist(args))) return 0 return 1 -/datum/teleport/proc/initTeleport(ateleatom,adestination,aprecision,afteleport,aeffectin,aeffectout,asoundin,asoundout) +/datum/teleport/proc/initTeleport(ateleatom, adestination, aprecision, afteleport, aeffectin, aeffectout, asoundin, asoundout, bypass_area_flag=FALSE) if(!setTeleatom(ateleatom)) return 0 if(!setDestination(adestination)) @@ -31,6 +32,7 @@ setEffects(aeffectin,aeffectout) setForceTeleport(afteleport) setSounds(asoundin,asoundout) + ignore_area_flag = bypass_area_flag return 1 //must succeed @@ -97,7 +99,8 @@ var/turf/destturf var/turf/curturf = get_turf(teleatom) - var/area/destarea = get_area(destination) + var/area/curarea = get_area(curturf) + if(precision) var/list/posturfs = list() var/center = get_turf(destination) @@ -109,6 +112,18 @@ else destturf = get_turf(destination) + if(!is_teleport_allowed(destturf.z)) + return 0 + // Only check the destination zlevel for is_teleport_allowed. Checking origin as well breaks ERT teleporters. + + var/area/destarea = get_area(destturf) + + if(!ignore_area_flag) + if(curarea.tele_proof) + return 0 + if(destarea.tele_proof) + return 0 + if(!destturf || !curturf) return 0 diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 952711f3063..628b6a583f0 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -1,16 +1,13 @@ -var/list/uplink_items = list() +GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /proc/get_uplink_items(var/job = null) - // If not already initialized.. + var/list/uplink_items = list() if(!uplink_items.len) - // Fill in the list and order it like this: - // A keyed list, acting as categories, which are lists to the datum. - var/list/last = list() - for(var/item in typesof(/datum/uplink_item)) + for(var/path in GLOB.uplink_items) - var/datum/uplink_item/I = new item() + var/datum/uplink_item/I = new path if(!I.item) continue if(I.gamemodes.len && ticker && !(ticker.mode.type in I.gamemodes)) @@ -55,6 +52,9 @@ var/list/uplink_items = list() var/list/job = null var/surplus = 100 //Chance of being included in the surplus crate (when pick() selects it) var/hijack_only = FALSE //can this item be purchased only during hijackings? + var/refundable = FALSE + var/refund_path = null // Alternative path for refunds, in case the item purchased isn't what is actually refunded (ie: holoparasites). + var/refund_amount // specified refund amount in case there needs to be a TC penalty for refunds. /datum/uplink_item/proc/spawn_item(var/turf/loc, var/obj/item/uplink/U) if(hijack_only) @@ -540,9 +540,11 @@ var/list/uplink_items = list() desc = "A cyborg designed and programmed for systematic extermination of non-Syndicate personnel." reference = "SC" item = /obj/item/antag_spawner/borg_tele + refund_path = /obj/item/antag_spawner/borg_tele cost = 50 gamemodes = list(/datum/game_mode/nuclear) surplus = 0 + refundable = TRUE /datum/uplink_item/dangerous/foamsmg name = "Toy Submachine Gun" @@ -571,19 +573,14 @@ var/list/uplink_items = list() gamemodes = list(/datum/game_mode/nuclear) surplus = 0 - -//for refunding the syndieborg teleporter -/datum/uplink_item/dangerous/syndieborg/spawn_item() - var/obj/item/antag_spawner/borg_tele/T = ..() - if(istype(T)) - T.TC_cost = cost - /datum/uplink_item/dangerous/guardian name = "Holoparasites" desc = "Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, they require an organic host as a home base and source of fuel." item = /obj/item/storage/box/syndie_kit/guardian excludefrom = list(/datum/game_mode/nuclear) cost = 12 + refund_path = /obj/item/guardiancreator/tech/choose + refundable = TRUE // Ammunition diff --git a/code/game/area/depot-areas.dm b/code/game/area/depot-areas.dm index 9de680da82e..69205c3c35f 100644 --- a/code/game/area/depot-areas.dm +++ b/code/game/area/depot-areas.dm @@ -57,22 +57,32 @@ /area/syndicate_depot/core/proc/reset_alert() if(used_self_destruct) - return + for(var/obj/effect/overload/O in src) + new /obj/structure/fusionreactor(O.loc) + qdel(O) + + if(on_peaceful) + peaceful_mode(FALSE, TRUE) local_alarm = FALSE called_backup = FALSE + unlock_computers() used_self_destruct = FALSE + + run_started = FALSE + run_finished = FALSE + + despawn_guards() + hostile_list = list() + dead_list = list() + peaceful_list = list() + something_looted = FALSE detected_mech = FALSE detected_pod = FALSE detected_double_agent = FALSE updateicon() - despawn_guards() - guard_list = list() - hostile_list = list() - dead_list = list() - peaceful_list = list() alert_log += "Alert level reset." @@ -97,6 +107,13 @@ if(on_peaceful) increase_alert("Thieves!") +/area/syndicate_depot/core/proc/armory_locker_looted() + if(!run_finished && !used_self_destruct) + if(shield_list.len) + activate_self_destruct("Armory compromised despite armory shield being online.", FALSE) + return + declare_finished() + /area/syndicate_depot/core/proc/turret_died() something_looted = TRUE if(on_peaceful) @@ -133,19 +150,12 @@ if(L.opened) L.close() if(!L.locked) - L.locked = 1 + L.locked = !L.locked L.req_access = list(access_syndicate_leader) L.update_icon() for(var/obj/machinery/computer/syndicate_depot/teleporter/P in src) if(!P.portal_enabled) P.toggle_portal() - for(var/obj/machinery/door/airlock/hatch/syndicate/vault/V in src) - if(!V.density) - V.close() - V.emergency = 0 - if(!V.locked) - V.locked = !V.locked - V.update_icon() else log_game("Depot visit: ended") alert_log += "Visitor mode ended." @@ -250,15 +260,17 @@ if(user) var/turf/T = get_turf(user) var/area/A = get_area(T) - var/log_msg = "[key_name(user)] has armed the depot self destruct device at [A.name] ([T.x],[T.y],[T.z])" + var/log_msg = "[key_name(user)] has triggered the depot self destruct at [A.name] ([T.x],[T.y],[T.z])" message_admins(log_msg) log_game(log_msg) playsound(user, 'sound/machines/Alarm.ogg', 100, 0, 0) else log_game("Depot self destruct activated.") if(reactor) - reactor.overload(containment_failure) + if(!reactor.has_overloaded) + reactor.overload(containment_failure) else + log_debug("Depot: [src] called activate_self_destruct with no reactor."); message_admins("Syndicate Depot lacks reactor to initiate self-destruct. Must be destroyed manually.") updateicon() @@ -269,13 +281,17 @@ for(var/obj/machinery/door/airlock/A in src) spawn(0) A.close() - if(A.density) + if(A.density && !A.locked) A.lock() /area/syndicate_depot/core/proc/lockout_computers() for(var/obj/machinery/computer/syndicate_depot/C in src) C.activate_security_lockout() +/area/syndicate_depot/core/proc/unlock_computers() + for(var/obj/machinery/computer/syndicate_depot/C in src) + C.security_lockout = FALSE + /area/syndicate_depot/core/proc/toggle_door_locks() for(var/obj/machinery/door/airlock/A in src) A.emergency = !A.emergency @@ -313,6 +329,12 @@ if(L.name == "syndi_depot_shield") var/obj/machinery/shieldwall/syndicate/S = new /obj/machinery/shieldwall/syndicate(L.loc) shield_list += S.UID() + for(var/obj/structure/closet/secure_closet/syndicate/depot/armory/L in src) + if(L.opened) + L.close() + if(!L.locked) + L.locked = !L.locked + L.update_icon() /area/syndicate_depot/core/proc/shields_key_check() if(!shield_list.len) @@ -327,6 +349,10 @@ if(S) qdel(S) shield_list = list() + for(var/obj/structure/closet/secure_closet/syndicate/depot/armory/L in src) + if(L.locked) + L.locked = !L.locked + L.update_icon() /area/syndicate_depot/core/proc/despawn_guards() for(var/mob/thismob in list_getmobs(guard_list)) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index ea3b9df4f54..3c541a308ff 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -305,6 +305,10 @@ /atom/proc/rpd_act() return +/atom/proc/rpd_blocksusage() + // Atoms that return TRUE prevent RPDs placing any kind of pipes on their turf. + return FALSE + /atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked) if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...). addtimer(CALLBACK(src, .proc/hitby_react, AM), 2) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 4e467e4eb18..50a578cc3b3 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -428,8 +428,11 @@ flick_overlay(I, viewing, 5) // 5 ticks/half a second // And animate the attack! - animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3) - - + var/t_color = "#ffffff" + if(ismob(src) && ismob(A) && (!used_item)) + var/mob/M = src + t_color = M.a_intent == INTENT_HARM ? "#ff0000" : "#ffffff" + animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3, color = t_color) + /atom/movable/proc/portal_destroyed(obj/effect/portal/P) return diff --git a/code/game/gamemodes/changeling/powers/fleshmend.dm b/code/game/gamemodes/changeling/powers/fleshmend.dm index 56417ac4335..8ab09fc781c 100644 --- a/code/game/gamemodes/changeling/powers/fleshmend.dm +++ b/code/game/gamemodes/changeling/powers/fleshmend.dm @@ -48,7 +48,7 @@ var/healpertick = -(total_healing / healing_ticks) user.heal_overall_damage((-healpertick/recent_uses), (-healpertick/recent_uses)) user.adjustOxyLoss(healpertick/recent_uses) - user.blood_volume += 30 + user.blood_volume = min(user.blood_volume + 30, BLOOD_VOLUME_NORMAL) user.updatehealth() else break diff --git a/code/game/gamemodes/miniantags/abduction/abduction.dm b/code/game/gamemodes/miniantags/abduction/abduction.dm index 5d5c3342010..4bfc8c9672d 100644 --- a/code/game/gamemodes/miniantags/abduction/abduction.dm +++ b/code/game/gamemodes/miniantags/abduction/abduction.dm @@ -197,17 +197,17 @@ /datum/game_mode/proc/auto_declare_completion_abduction() var/text = "" if(abductors.len) - text += "
The abductors were:" + text += "
The abductors were:
" for(var/datum/mind/abductor_mind in abductors) text += printplayer(abductor_mind) text += printobjectives(abductor_mind) - text += "
" + text += "
" if(abductees.len) - text += "
The abductees were:" + text += "
The abductees were:
" for(var/datum/mind/abductee_mind in abductees) text += printplayer(abductee_mind) text += printobjectives(abductee_mind) - text += "
" + text += "
" to_chat(world, text) //Landmarks diff --git a/code/game/gamemodes/miniantags/borer/borer.dm b/code/game/gamemodes/miniantags/borer/borer.dm index 9593ee6b792..45998cd4b30 100644 --- a/code/game/gamemodes/miniantags/borer/borer.dm +++ b/code/game/gamemodes/miniantags/borer/borer.dm @@ -363,7 +363,9 @@ if(M.has_brain_worms()) to_chat(src, "[M] is already infested!") return + host = M + add_attack_logs(src, host, "Infested as borer") M.borer = src forceMove(M) diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm index 68e8c16c5da..ab3af13e98d 100644 --- a/code/game/gamemodes/miniantags/guardian/guardian.dm +++ b/code/game/gamemodes/miniantags/guardian/guardian.dm @@ -415,6 +415,9 @@ failure_message = "...ERROR. BOOT SEQUENCE ABORTED. AI FAILED TO INTIALIZE. PLEASE CONTACT SUPPORT OR TRY AGAIN LATER." ling_failure = "The holoparasites recoil in horror. They want nothing to do with a creature like you." +/obj/item/guardiancreator/tech/check_uplink_validity() + return !used + /obj/item/guardiancreator/tech/choose random = FALSE diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index b7364970351..a0ba4773785 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -329,11 +329,17 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) - /datu explanation_text = "Destroy the station with a nuclear device." martyr_compatible = 1 - - /datum/objective/steal var/datum/theft_objective/steal_target martyr_compatible = 0 + var/theft_area + +/datum/objective/steal/proc/get_location() + if(steal_target.location_override) + return steal_target.location_override + var/obj/item/T = locate(steal_target.typepath) + theft_area = get_area(T.loc) + return "[theft_area]" /datum/objective/steal/find_target() var/loop=50 @@ -346,7 +352,9 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) - /datu if(O.flags & 2) continue steal_target=O - explanation_text = "Steal [O]." + explanation_text = "Steal [steal_target]. One was last seen in [get_location()]. " + if(islist(O.protected_jobs) && O.protected_jobs.len) + explanation_text += "It may also be in the possession of the [jointext(O.protected_jobs, ", ")]." return explanation_text = "Free Objective." diff --git a/code/game/gamemodes/steal_items.dm b/code/game/gamemodes/steal_items.dm index d3f29734815..3d20040f128 100644 --- a/code/game/gamemodes/steal_items.dm +++ b/code/game/gamemodes/steal_items.dm @@ -11,6 +11,7 @@ var/list/protected_jobs = list() var/list/altitems = list() var/flags = 0 + var/location_override /datum/theft_objective/proc/check_completion(var/datum/mind/owner) if(!owner.current) @@ -49,6 +50,7 @@ /datum/theft_objective/ai name = "a functional AI" typepath = /obj/item/aicard + location_override = "AI Satellite. An intellicard for transportation can be found in Tech Storage, Science Department or manufactured" datum/theft_objective/ai/check_special_completion(var/obj/item/aicard/C) if(..()) @@ -91,6 +93,7 @@ datum/theft_objective/ai/check_special_completion(var/obj/item/aicard/C) name = "a sample of unused slime extract" typepath = /obj/item/slime_extract protected_jobs = list("Research Director","Scientist") + location_override = "Xenobiology" /datum/theft_objective/slime_extract/check_special_completion(var/obj/item/slime_extract/E) if(..()) @@ -169,6 +172,7 @@ datum/theft_objective/ai/check_special_completion(var/obj/item/aicard/C) min=28 max=28 protected_jobs = list("Chief Engineer", "Station Engineer", "Scientist", "Research Director", "Life Support Specialist") + location_override = "Engineering or Toxin Mixing" /datum/theft_objective/number/plasma_gas/getAmountStolen(var/obj/item/I) return I:air_contents:toxins diff --git a/code/game/machinery/Beacon.dm b/code/game/machinery/Beacon.dm index 661453adfc3..79fd53e5083 100644 --- a/code/game/machinery/Beacon.dm +++ b/code/game/machinery/Beacon.dm @@ -9,6 +9,7 @@ use_power = 1 idle_power_usage = 0 var/syndicate = 0 + var/area_bypass = FALSE var/obj/item/radio/beacon/Beacon var/enabled = TRUE @@ -22,6 +23,7 @@ Beacon.invisibility = INVISIBILITY_MAXIMUM Beacon.loc = T Beacon.syndicate = syndicate + Beacon.area_bypass = area_bypass hide(T.intact) /obj/machinery/bluespace_beacon/proc/destroy_beacon() @@ -64,6 +66,7 @@ /obj/machinery/bluespace_beacon/syndicate syndicate = TRUE enabled = FALSE + area_bypass = TRUE // This enables teleports to this beacon to bypass the tele_proof flag of /area/s. Intended for depot syndi teleport computer. var/obj/machinery/computer/syndicate_depot/teleporter/mycomputer /obj/machinery/bluespace_beacon/syndicate/New() diff --git a/code/game/machinery/computer/depot.dm b/code/game/machinery/computer/depot.dm index 6bd5eadc822..78a8a8a69ab 100644 --- a/code/game/machinery/computer/depot.dm +++ b/code/game/machinery/computer/depot.dm @@ -138,6 +138,7 @@ if(depotarea) depotarea.toggle_door_locks(src) to_chat(user, "Door locks toggled.") + playsound(user, sound_yes, 50, 0) /obj/machinery/computer/syndicate_depot/doors/secondary(mob/user, subcommand) if(..()) @@ -145,6 +146,7 @@ if(depotarea) depotarea.toggle_falsewalls(src) to_chat(user, "False walls toggled.") + playsound(user, sound_yes, 50, 0) // Engineering AKA self destruct computer, no useful functions, just a trap for the people who can't resist pushing dangerous-sounding buttons. @@ -167,9 +169,9 @@ if(depotarea.used_self_destruct) playsound(user, sound_no, 50, 0) return - playsound(user, sound_click, 20, 1) if(depotarea) depotarea.activate_self_destruct("Fusion reactor containment field disengaged. All hands, evacuate. All hands, evacuate!", TRUE, user) + playsound(user, sound_click, 20, 1) // Shield computer, used to manipulate base shield, and armory shield @@ -285,6 +287,7 @@ to_chat(user, "[src] requires authentication with syndicate codewords, which you do not know.") raise_alert("Detected unauthorized access by [user] to [src]!") updateUsrDialog() + playsound(user, sound_yes, 50, 0) /obj/machinery/computer/syndicate_depot/syndiecomms/secondary(mob/user, subcommand) if(..()) @@ -319,6 +322,7 @@ else to_chat(user, "ERROR: [src] is unable to uplink to depot network.") updateUsrDialog() + playsound(user, sound_yes, 50, 0) /obj/machinery/computer/syndicate_depot/syndiecomms/proc/grant_syndie_faction(mob/user) user.faction += "syndicate" @@ -347,7 +351,7 @@ icon_screen = "telesci" icon_keyboard = "teleport_key" var/obj/machinery/bluespace_beacon/syndicate/mybeacon - var/obj/effect/portal/myportal + var/obj/effect/portal/redspace/myportal var/portal_enabled = FALSE var/portaldir = WEST @@ -401,10 +405,8 @@ if(!tele_target) return var/turf/portal_turf = get_step(src, portaldir) - var/obj/effect/portal/P = new(portal_turf, tele_target, src, 0) + var/obj/effect/portal/redspace/P = new(portal_turf, tele_target, src, 0) myportal = P - P.failchance = 0 - P.icon_state = "portal1" var/area/A = get_area(tele_target) P.name = "[A] portal" else if(!portal_enabled && myportal) @@ -432,6 +434,7 @@ var/bresult = mybeacon.toggle() to_chat(user, "Syndicate Teleporter Beacon: [bresult ? "ON" : "OFF"]") updateUsrDialog() + playsound(user, sound_yes, 50, 0) /obj/machinery/computer/syndicate_depot/teleporter/secondary(mob/user) if(..()) @@ -444,6 +447,7 @@ toggle_portal() to_chat(user, "Outgoing Teleport Portal: [portal_enabled ? "ON" : "OFF"]") updateUsrDialog() + playsound(user, sound_yes, 50, 0) /obj/machinery/computer/syndicate_depot/teleporter/proc/toggle_portal() portal_enabled = !portal_enabled @@ -507,6 +511,7 @@ if(depotarea) depotarea.reset_alert() to_chat(user, "Alert level reset.") + playsound(user, sound_yes, 50, 0) /obj/machinery/computer/syndicate_depot/aiterminal/secondary(mob/user) if(..()) @@ -516,4 +521,5 @@ new /obj/effect/portal(get_turf(B)) to_chat(user, "[B] has been recalled.") qdel(B) - raise_alert("Sentry bot removed via emergency recall.") \ No newline at end of file + raise_alert("Sentry bot removed via emergency recall.") + playsound(user, sound_yes, 50, 0) \ No newline at end of file diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index aef8de7c306..fcf8de24ca5 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -97,6 +97,7 @@ Class Procs: name = "machinery" icon = 'icons/obj/stationobjs.dmi' pressure_resistance = 10 + layer = BELOW_OBJ_LAYER var/stat = 0 var/emagged = 0 var/use_power = 1 diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index 270b2a99411..e84d0778ef3 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -140,6 +140,7 @@ //update the name and icon of the pipe item depending on the type /obj/item/pipe/rpd_act(mob/user, obj/item/rpd/our_rpd) + . = TRUE if(our_rpd.mode == RPD_ROTATE_MODE) rotate() else if(our_rpd.mode == RPD_FLIP_MODE) @@ -147,7 +148,7 @@ else if(our_rpd.mode == RPD_DELETE_MODE) our_rpd.delete_single_pipe(user, src) else - ..() + return ..() /obj/item/pipe/proc/update(var/obj/machinery/atmospherics/make_from) name = "[get_pipe_name(pipe_type, PIPETYPE_ATMOS)] fitting" diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index a148a3c40f5..9d44ac09231 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -1013,15 +1013,14 @@ var/list/turret_icons check_anomalies = 1 check_synth = 1 ailock = 1 + var/area/syndicate_depot/core/depotarea /obj/machinery/porta_turret/syndicate/die() . = ..() - var/area/syndicate_depot/core/depotarea = areaMaster if(istype(depotarea)) depotarea.turret_died() /obj/machinery/porta_turret/syndicate/shootAt(mob/living/target) - var/area/syndicate_depot/core/depotarea = areaMaster if(istype(depotarea)) depotarea.list_add(target, depotarea.hostile_list) depotarea.declare_started() diff --git a/code/game/machinery/quantum_pad.dm b/code/game/machinery/quantum_pad.dm index 29c43304b38..fe46d2746c8 100644 --- a/code/game/machinery/quantum_pad.dm +++ b/code/game/machinery/quantum_pad.dm @@ -132,6 +132,7 @@ playsound(get_turf(src), 'sound/weapons/emitter2.ogg', 25, 1, extrarange = 3, falloff = 5) flick("qpad-beam", linked_pad) playsound(get_turf(linked_pad), 'sound/weapons/emitter2.ogg', 25, 1, extrarange = 3, falloff = 5) + var/tele_success = TRUE for(var/atom/movable/ROI in get_turf(src)) // if is anchored, don't let through if(ROI.anchored) @@ -145,4 +146,6 @@ continue else if(!isobserver(ROI)) continue - do_teleport(ROI, get_turf(linked_pad)) + tele_success = do_teleport(ROI, get_turf(linked_pad)) + if(!tele_success) + to_chat(user, "Teleport failed due to bluespace interference.") diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 6d79a65dcbd..f1e27be33fa 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -541,6 +541,8 @@ /obj/machinery/shieldwall/attack_hand(mob/user as mob) return +/obj/machinery/shieldwall/rpd_blocksusage() + return TRUE /obj/machinery/shieldwall/process() if(needs_power) diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 46671a9f4fa..702d1eee8a2 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -11,6 +11,7 @@ var/calibrating var/turf/target //Used for one-time-use teleport cards (such as clown planet coordinates.) //Setting this to 1 will set src.locked to null after a player enters the portal and will not allow hand-teles to open portals to that location. + var/area_bypass = FALSE /obj/machinery/computer/teleporter/New() src.id = "[rand(1000, 9999)]" @@ -87,7 +88,7 @@ data["accurate"] = null data["regime"] = regime_set var/area/targetarea = get_area(target) - data["target"] = (!target) ? "None" : sanitize(targetarea.name) + data["target"] = (!target || !targetarea) ? "None" : sanitize(targetarea.name) data["calibrating"] = calibrating data["locked"] = locked return data @@ -172,6 +173,7 @@ locked = null /obj/machinery/computer/teleporter/proc/set_target(mob/user) + area_bypass = FALSE if(regime_set == "Teleporter") var/list/L = list() var/list/areaindex = list() @@ -211,7 +213,10 @@ var/desc = input("Please select a location to lock in.", "Locking Computer") in L target = L[desc] - + if(istype(target, /obj/item/radio/beacon)) + var/obj/item/radio/beacon/B = target + if(B.area_bypass) + area_bypass = TRUE else var/list/L = list() var/list/areaindex = list() @@ -335,7 +340,11 @@ to_chat(T, "[pick(TPError)]") return else - teleport(M) + if(!teleport(M) && isliving(M)) // the isliving(M) is needed to avoid triggering errors if a spark bumps the telehub + visible_message("[src] emits a loud buzz, as its teleport portal flickers and fails!") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + power_station.toggle() // turn off the portal. + use_power(5000) //--FalseIncarnate return @@ -353,6 +362,7 @@ return ..() /obj/machinery/teleport/hub/proc/teleport(atom/movable/M as mob|obj, turf/T) + . = TRUE var/obj/machinery/computer/teleporter/com = power_station.teleporter_console if(!com) return @@ -361,11 +371,10 @@ return if(istype(M, /atom/movable)) if(!calibrated && prob(25 - ((accurate) * 10))) //oh dear a problem - do_teleport(M, locate(rand((2*TRANSITIONEDGE), world.maxx - (2*TRANSITIONEDGE)), rand((2*TRANSITIONEDGE), world.maxy - (2*TRANSITIONEDGE)), 3), 2) + . = do_teleport(M, locate(rand((2*TRANSITIONEDGE), world.maxx - (2*TRANSITIONEDGE)), rand((2*TRANSITIONEDGE), world.maxy - (2*TRANSITIONEDGE)), 3), 2, bypass_area_flag = com.area_bypass) else - do_teleport(M, com.target) + . = do_teleport(M, com.target, bypass_area_flag = com.area_bypass) calibrated = 0 - return /obj/machinery/teleport/hub/update_icon() if(panel_open) @@ -574,8 +583,8 @@ visible_message("No target detected.") src.engaged = 0 teleporter_hub.update_icon() - src.add_fingerprint(user) - return + if(istype(user)) + add_fingerprint(user) /obj/machinery/teleport/station/power_change() ..() diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index e04667e237a..5347db5380f 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -907,8 +907,8 @@ /obj/machinery/vending/chinese name = "\improper Mr. Chang" desc = "A self-serving Chinese food machine, for all your Chinese food needs." - product_slogans = "Taste 5000 years of culture!" - icon_state = "snack" + product_slogans = "Taste 5000 years of culture!;Mr. Chang, approved for safe consumption in over 10 sectors!;Chinese food is great for a date night, or a lonely night!;You can't go wrong with Mr. Chang's authentic Chinese food!" + icon_state = "chang" products = list(/obj/item/reagent_containers/food/snacks/chinese/chowmein = 6, /obj/item/reagent_containers/food/snacks/chinese/tao = 6, /obj/item/reagent_containers/food/snacks/chinese/sweetsourchickenball = 6, /obj/item/reagent_containers/food/snacks/chinese/newdles = 6, /obj/item/reagent_containers/food/snacks/chinese/rice = 6) prices = list(/obj/item/reagent_containers/food/snacks/chinese/chowmein = 50, /obj/item/reagent_containers/food/snacks/chinese/tao = 50, /obj/item/reagent_containers/food/snacks/chinese/sweetsourchickenball = 50, /obj/item/reagent_containers/food/snacks/chinese/newdles = 50, diff --git a/code/game/objects/effects/decals/contraband.dm b/code/game/objects/effects/decals/contraband.dm index 1244f151be7..2feaea2a149 100644 --- a/code/game/objects/effects/decals/contraband.dm +++ b/code/game/objects/effects/decals/contraband.dm @@ -108,6 +108,9 @@ qdel(src) /obj/structure/sign/poster/proc/roll_and_drop(loc) + if(ruined) + qdel(src) + return pixel_x = 0 pixel_y = 0 var/obj/item/poster/P = new(loc, src) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index 18506a5c882..4c4cd42682b 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -14,14 +14,12 @@ /obj/effect/mine/Crossed(AM as mob|obj) if(!isliving(AM)) return - if(isanimal(AM)) - var/mob/living/simple_animal/SA = AM - if(faction && (faction in SA.faction)) - return - if(!SA.flying) - triggermine(SA) - else - triggermine(AM) + var/mob/living/M = AM + if(faction && (faction in M.faction)) + return + if(M.flying) + return + triggermine(M) /obj/effect/mine/proc/triggermine(mob/living/victim) if(triggered) @@ -34,6 +32,11 @@ triggered = 1 qdel(src) +/obj/effect/mine/ex_act(severity) + // Necessary because, as effects, they have infinite health, and wouldn't be destroyed otherwise. + // Also, they're pressure-sensitive mines, it makes sense that an explosion (wave of pressure) triggers/destroys them. + qdel(src) + /obj/effect/mine/explosive name = "explosive mine" var/range_devastation = 0 diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index 8692e65dc9d..a048ca1ebff 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -11,6 +11,7 @@ anchored = 1 var/precision = 1 // how close to the portal you will teleport. 0 = on the portal, 1 = adjacent var/can_multitool_to_remove = 0 + var/ignore_tele_proof_area_setting = FALSE /obj/effect/portal/Bumped(mob/M as mob|obj) teleport(M) @@ -42,12 +43,29 @@ qdel(src) return if(istype(M, /atom/movable)) - if(prob(failchance)) //oh dear a problem, put em in deep space + if(prob(failchance)) src.icon_state = "portal1" - do_teleport(M, locate(rand(5, world.maxx - 5), rand(5, world.maxy -5), 3), 0) + if(!do_teleport(M, locate(rand(5, world.maxx - 5), rand(5, world.maxy -5), 3), 0, bypass_area_flag = ignore_tele_proof_area_setting)) // Try to send them to deep space. + invalid_teleport() else - do_teleport(M, target, precision) ///You will appear adjacent to the beacon + if(!do_teleport(M, target, precision, bypass_area_flag = ignore_tele_proof_area_setting)) // Try to send them to a turf adjacent to target. + invalid_teleport() /obj/effect/portal/attackby(obj/item/A, mob/user) if(istype(A, /obj/item/multitool) && can_multitool_to_remove) - qdel(src) \ No newline at end of file + qdel(src) + +/obj/effect/portal/proc/invalid_teleport() + visible_message("[src] flickers and fails due to bluespace interference!") + var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() + spark_system.set_up(5, 0, loc) + spark_system.start() + qdel(src) + + +/obj/effect/portal/redspace + name = "redspace portal" + desc = "A portal capable of bypassing bluespace interference." + icon_state = "portal1" + failchance = 0 + ignore_tele_proof_area_setting = TRUE \ No newline at end of file diff --git a/code/game/objects/effects/spawners/random_spawners.dm b/code/game/objects/effects/spawners/random_spawners.dm index 668bb52b467..1619eba14c4 100644 --- a/code/game/objects/effects/spawners/random_spawners.dm +++ b/code/game/objects/effects/spawners/random_spawners.dm @@ -264,6 +264,7 @@ /obj/effect/spawner/random_spawners/syndicate/loot/level4 name = "armory loot" + spawn_inside = /obj/structure/closet/secure_closet/syndicate/depot/armory // Loot schema: high-power weapons (m90, esword, ebow, revolver), devices that negate depot challenges (thermal glasses, chameleon device), explosives result = list(/obj/item/gun/projectile/automatic/c20r = 1, /obj/item/gun/projectile/automatic/m90 = 1, @@ -299,10 +300,9 @@ /obj/structure/falsewall/reinforced = 1) /obj/effect/spawner/random_spawners/syndicate/layout/door/vault - name = "60pc vaultdoor 20pc falsewall 20pc wall" - result = list(/obj/machinery/door/airlock/hatch/syndicate/vault = 6, - /turf/simulated/wall/r_wall = 2, - /obj/structure/falsewall/reinforced = 2) + name = "80pc vaultdoor 20pc wall" + result = list(/obj/machinery/door/airlock/hatch/syndicate/vault = 4, + /turf/simulated/wall/r_wall = 1) /obj/effect/spawner/random_spawners/syndicate/layout/spacepod diff --git a/code/game/objects/items/devices/radio/beacon.dm b/code/game/objects/items/devices/radio/beacon.dm index ff7fd6504d1..19e26f06bf5 100644 --- a/code/game/objects/items/devices/radio/beacon.dm +++ b/code/game/objects/items/devices/radio/beacon.dm @@ -7,6 +7,7 @@ origin_tech = "bluespace=1" var/emagged = 0 var/syndicate = 0 + var/area_bypass = FALSE /obj/item/radio/beacon/New() ..() diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm index cc3320489f6..1c3124a74cb 100644 --- a/code/game/objects/items/devices/uplinks.dm +++ b/code/game/objects/items/devices/uplinks.dm @@ -12,7 +12,7 @@ var/list/world_uplinks = list() var/welcome // Welcoming menu message var/uses // Numbers of crystals var/hidden_crystals = 0 - var/list/ItemsCategory // List of categories with lists of items + var/list/uplink_items // List of categories with lists of items var/list/ItemsReference // List of references with an associated item var/list/nanoui_items // List of items for NanoUI use var/nanoui_menu = 0 // The current menu we are in @@ -32,7 +32,7 @@ var/list/world_uplinks = list() ..() welcome = ticker.mode.uplink_welcome uses = ticker.mode.uplink_uses - ItemsCategory = get_uplink_items() + uplink_items = get_uplink_items() world_uplinks += src @@ -57,14 +57,14 @@ var/list/world_uplinks = list() dat += "Each item costs a number of telecrystals as indicated by the number following its name.
" var/category_items = 1 - for(var/category in ItemsCategory) + for(var/category in uplink_items) if(category_items < 1) dat += "We apologize, as you could not afford anything from this category.
" dat += "
" dat += "[category]
" category_items = 0 - for(var/datum/uplink_item/I in ItemsCategory[category]) + for(var/datum/uplink_item/I in uplink_items[category]) if(I.cost > uses) continue if(I.job && I.job.len) @@ -87,9 +87,9 @@ var/list/world_uplinks = list() var/list/nano = new var/list/reference = new - for(var/category in ItemsCategory) + for(var/category in uplink_items) nano[++nano.len] = list("Category" = category, "items" = list()) - for(var/datum/uplink_item/I in ItemsCategory[category]) + for(var/datum/uplink_item/I in uplink_items[category]) if(I.job && I.job.len) if(!(I.job.Find(job))) continue @@ -117,6 +117,9 @@ var/list/world_uplinks = list() if(..()) return 1 + if(href_list["refund"]) + refund(usr) + if(href_list["buy_item"] == "random") var/datum/uplink_item/UI = chooseRandomItem() href_list["buy_item"] = UI.reference @@ -142,6 +145,22 @@ var/list/world_uplinks = list() return 1 +/obj/item/uplink/proc/refund(mob/user as mob) + var/obj/item/I = user.get_active_hand() + if(I) // Make sure there's actually something in the hand before even bothering to check + for(var/category in uplink_items) + for(var/item in uplink_items[category]) + var/datum/uplink_item/UI = item + var/path = UI.refund_path || UI.item + var/cost = UI.refund_amount || UI.cost + if(I.type == path && UI.refundable && I.check_uplink_validity()) + uses += cost + used_TC -= cost + to_chat(user, "[I] refunded.") + qdel(I) + return + ..() + // HIDDEN UPLINK - Can be stored in anything but the host item has to have a trigger for it. /* How to create an uplink in 3 easy steps! @@ -287,17 +306,6 @@ var/list/world_uplinks = list() return 1 return 0 -//Refund proc for the borg teleporter (later I'll make a general refund proc if there is demand for it) -/obj/item/radio/uplink/attackby(obj/item/W as obj, mob/user as mob, params) - if(istype(W, /obj/item/antag_spawner/borg_tele)) - var/obj/item/antag_spawner/borg_tele/S = W - if(!S.used && !S.checking) - hidden_uplink.uses += S.TC_cost - qdel(S) - to_chat(user, "Teleporter refunded.") - else - to_chat(user, "This teleporter is already used, or is currently being used.") - // PRESET UPLINKS // A collection of preset uplinks. // diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index b1fc3398af0..c37c1cce2c8 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -293,6 +293,10 @@ update_icon() return unwield(user) +/obj/item/twohanded/shockpaddles/on_mob_move(dir, mob/user) + if(defib && !(defib.Adjacent(user))) + defib.remove_paddles(user) + /obj/item/twohanded/shockpaddles/proc/check_defib_exists(mainunit, var/mob/living/carbon/human/M, var/obj/O) if(!mainunit || !istype(mainunit, /obj/item/defibrillator)) //To avoid weird issues from admin spawns M.unEquip(O) diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm index db8f9f549d5..ad53a49d084 100644 --- a/code/game/objects/items/weapons/implants/implantcase.dm +++ b/code/game/objects/items/weapons/implants/implantcase.dm @@ -16,7 +16,7 @@ if(imp) icon_state = "implantcase-[imp.item_color]" origin_tech = imp.origin_tech - flags = imp.flags + flags = imp.flags & ~DROPDEL reagents = imp.reagents else icon_state = "implantcase-0" diff --git a/code/game/objects/items/weapons/rpd.dm b/code/game/objects/items/weapons/rpd.dm index e130c3ed606..c139155b57c 100644 --- a/code/game/objects/items/weapons/rpd.dm +++ b/code/game/objects/items/weapons/rpd.dm @@ -192,7 +192,27 @@ var/list/pipemenu = list( return if(world.time < lastused + spawndelay) return - target.rpd_act(user, src) //Handle RPD effects in separate procs + + + var/turf/T = get_turf(target) + if(target != T) + // We only check the rpd_act of the target if it isn't the turf, because otherwise + // (A) blocked turfs can be acted on, and (B) unblocked turfs get acted on twice. + if(target.rpd_act(user, src) == TRUE) + // If the object we are clicking on has a valid RPD interaction for just that specific object, do that and nothing else. + // Example: clicking on a pipe with a RPD in rotate mode should rotate that pipe and ignore everything else on the tile. + return + + // If we get this far, we have to check every object in the tile, to make sure that none of them block RPD usage on this tile. + // This is done by calling rpd_blocksusage on every /obj in the tile. If any block usage, fail at this point. + + for(var/obj/O in T) + if(O.rpd_blocksusage() == TRUE) + to_chat(user, "[O] blocks the [src]!") + return + + // If we get here, then we're effectively acting on the turf, probably placing a pipe. + T.rpd_act(user, src) #undef RPD_COOLDOWN_TIME #undef RPD_WALLBUILD_TIME diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 43904d27359..08a6a3e168c 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -1,3 +1,5 @@ +#define HEALPERWELD 15 + /* Tools! * Note: Multitools are in devices * @@ -407,24 +409,47 @@ to_chat(user, "Turn on [src] before attempting repairs!") return 1 - if(S.brute_dam) - if(S.brute_dam < ROBOLIMB_SELF_REPAIR_CAP) - if(get_fuel() >= 1) - if(H == user) - if(!do_mob(user, H, 10)) - return 1 - if(remove_fuel(1,null)) - playsound(src.loc, usesound, 50, 1) - S.heal_damage(15,0,0,1) - user.visible_message("\The [user] patches some dents on \the [M]'s [S.name] with \the [src].") - else if(S.open != 2) - to_chat(user, "Need more welding fuel!") - return 1 - else - to_chat(user, "The damage is far too severe to patch over externally.") - return 1 - else if(S.open != 2) + if(S.brute_dam > ROBOLIMB_SELF_REPAIR_CAP) + to_chat(user, "The damage is far too severe to patch over externally.") + return + + if(!S.brute_dam) to_chat(user, "Nothing to fix!") + return + + if(get_fuel() >= 1) + if(H == user) + if(!do_mob(user, H, 10)) + return 1 + if(!remove_fuel(1,null)) + to_chat(user, "Need more welding fuel!") + var/rembrute = HEALPERWELD + var/nrembrute = 0 + var/childlist + if(!isnull(S.children)) + childlist = S.children.Copy() + var/parenthealed = FALSE + while(rembrute > 0) + var/obj/item/organ/external/E + if(S.brute_dam) + E = S + else if(LAZYLEN(childlist)) + E = pick_n_take(childlist) + if(!E.brute_dam || !E.is_robotic()) + continue + else if(S.parent && !parenthealed) + E = S.parent + parenthealed = TRUE + if(!E.brute_dam || !E.is_robotic()) + break + else + break + playsound(src.loc, usesound, 50, 1) + nrembrute = max(rembrute - E.brute_dam, 0) + E.heal_damage(rembrute,0,0,1) + rembrute = nrembrute + user.visible_message("\The [user] patches some dents on \the [M]'s [E.name] with \the [src].") + return 1 else return ..() diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index a7e57ce5a52..29d3f2663bc 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -71,10 +71,6 @@ SSnanoui.close_uis(src) return ..() -/obj/rpd_act(mob/user, obj/item/rpd/our_rpd) - var/turf/T = get_turf(src) //This preserves RPD behaviour on specific turfs - T.rpd_act(user, our_rpd) - /obj/proc/process() set waitfor = 0 processing_objects.Remove(src) @@ -307,3 +303,6 @@ a { .["Make speed process"] = "?_src_=vars;makespeedy=[UID()]" else .["Make normal process"] = "?_src_=vars;makenormalspeed=[UID()]" + +/obj/proc/check_uplink_validity() + return 1 diff --git a/code/game/objects/structures/crates_lockers/closets/secure/depot.dm b/code/game/objects/structures/crates_lockers/closets/secure/depot.dm index 1d52dbcdf1b..be67d79272f 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/depot.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/depot.dm @@ -6,6 +6,8 @@ anchored = 1 health = 200 req_access = list() + var/is_armory = FALSE + var/ignore_use = FALSE /obj/structure/closet/secure_closet/syndicate/depot/New() @@ -26,9 +28,12 @@ . = ..() /obj/structure/closet/secure_closet/syndicate/depot/proc/loot_pickup() - var/area/syndicate_depot/core/depotarea = areaMaster - if(depotarea) - depotarea.locker_looted() + if(!ignore_use) + var/area/syndicate_depot/core/depotarea = areaMaster + if(istype(depotarea)) + depotarea.locker_looted() + if(is_armory) + depotarea.armory_locker_looted() /obj/structure/closet/secure_closet/syndicate/depot/attack_animal(mob/M) if(isanimal(M) && "syndicate" in M.faction) @@ -36,10 +41,26 @@ return return ..(M) +/obj/structure/closet/secure_closet/syndicate/depot/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/rcs)) + to_chat(user, "Bluespace interference prevents the [W] from locking onto [src]!") + return + return ..() + /obj/structure/closet/secure_closet/syndicate/depot/emp_act(severity) return /obj/structure/closet/secure_closet/syndicate/depot/togglelock(mob/user) . = ..() if(!locked) - loot_pickup() \ No newline at end of file + loot_pickup() + +/obj/structure/closet/secure_closet/syndicate/depot/attack_ghost(mob/user) + if(user.can_advanced_admin_interact()) + ignore_use = TRUE + toggle(user) + ignore_use = FALSE + +/obj/structure/closet/secure_closet/syndicate/depot/armory + req_access = list(access_syndicate) + is_armory = TRUE \ No newline at end of file diff --git a/code/game/objects/structures/depot.dm b/code/game/objects/structures/depot.dm index 9dfe256ce38..b655d010aa7 100644 --- a/code/game/objects/structures/depot.dm +++ b/code/game/objects/structures/depot.dm @@ -7,15 +7,24 @@ anchored = 1 max_integrity = 50 var/area/syndicate_depot/core/depotarea + var/has_overloaded = FALSE /obj/structure/fusionreactor/Initialize() - . = ..() + ..() depotarea = areaMaster - if(depotarea) + if(istype(depotarea)) depotarea.reactor = src + return INITIALIZE_HINT_LATELOAD + +/obj/structure/fusionreactor/LateInitialize() + for(var/obj/machinery/porta_turret/syndicate/T in range(50, loc)) + if(!istype(T.depotarea)) + T.depotarea = depotarea /obj/structure/fusionreactor/Destroy() - if(depotarea) + if(istype(depotarea)) + if(!has_overloaded) + overload(TRUE, TRUE) depotarea.reactor = null ..() @@ -30,7 +39,7 @@ healthcheck() /obj/structure/fusionreactor/proc/healthcheck() - if(obj_integrity <= 0) + if(obj_integrity <= 0 && istype(depotarea)) overload(TRUE) /obj/structure/fusionreactor/attackby(obj/item/I, mob/user, params) @@ -47,13 +56,20 @@ else return ..() -/obj/structure/fusionreactor/proc/overload(containment_failure) +/obj/structure/fusionreactor/proc/overload(containment_failure = FALSE, skip_qdel = FALSE) + if(has_overloaded) + return + has_overloaded = TRUE + if(istype(depotarea) && !depotarea.used_self_destruct) + depotarea.activate_self_destruct("Fusion reactor cracked open. Core loose!", TRUE) var/obj/effect/overload/O = new /obj/effect/overload(get_turf(src)) if(containment_failure) playsound(loc, 'sound/machines/Alarm.ogg', 100, 0, 0) O.deliberate = TRUE O.max_cycles = 6 - qdel(src) + if(!skip_qdel) + qdel(src) + /obj/effect/overload icon = 'icons/obj/tesla_engine/energy_ball.dmi' diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 4ef1978cffb..cb7350f5b34 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -47,6 +47,11 @@ new /obj/item/stack/sheet/metal(get_turf(src)) qdel(src) +/obj/structure/girder/temperature_expose(datum/gas_mixture/air, exposed_temperature) + var/temp_check = exposed_temperature + if(temp_check >= GIRDER_MELTING_TEMP) + take_damage(10) + /obj/structure/girder/attackby(obj/item/W, mob/user, params) add_fingerprint(user) if(isscrewdriver(W)) diff --git a/code/modules/admin/tickets/adminticketsUI.dm b/code/modules/admin/tickets/adminticketsUI.dm index 750fa13e6cb..b063c5cb673 100644 --- a/code/modules/admin/tickets/adminticketsUI.dm +++ b/code/modules/admin/tickets/adminticketsUI.dm @@ -44,14 +44,14 @@ return dat -/datum/adminTicketHolder/proc/showUI(var/client/user, var/tab) +/datum/adminTicketHolder/proc/showUI(mob/user, var/tab) var/dat = null dat = returnUI(tab) var/datum/browser/popup = new(user, "admintickets", "Admin Tickets", 1400, 600) popup.set_content(dat) popup.open() -/datum/adminTicketHolder/proc/showDetailUI(var/client/user, var/ticketID) +/datum/adminTicketHolder/proc/showDetailUI(mob/user, var/ticketID) var/datum/admin_ticket/T = globAdminTicketHolder.allTickets[ticketID] var/status = "[T.state2text()]" @@ -91,9 +91,9 @@ popup.set_content(dat) popup.open() -/datum/adminTicketHolder/proc/userDetailUI(var/client/user) +/datum/adminTicketHolder/proc/userDetailUI(mob/user) //dat - var/tickets = checkForTicket(user) + var/tickets = checkForTicket(user.client) var/dat dat += "

Your open tickets

" dat += "" @@ -130,7 +130,7 @@ if(href_list["details"]) var/indexNum = text2num(href_list["details"]) - showDetailUI(usr.client, indexNum) + showDetailUI(usr, indexNum) return if(href_list["resolve"]) @@ -169,4 +169,4 @@ if(globAdminTicketHolder.assignAdminToTicket(usr.client, indexNum)) message_adminTicket("[usr.client] / ([usr]) has taken ticket number [indexNum]") to_chat(returnClient(indexNum), "Your ticket is being handled by [usr.client].") - showDetailUI(usr, indexNum) \ No newline at end of file + showDetailUI(usr, indexNum) diff --git a/code/modules/admin/tickets/adminticketsverbs.dm b/code/modules/admin/tickets/adminticketsverbs.dm index a0431cd8e23..0cf22c5d24c 100644 --- a/code/modules/admin/tickets/adminticketsverbs.dm +++ b/code/modules/admin/tickets/adminticketsverbs.dm @@ -48,4 +48,4 @@ if(!holder && !check_rights(R_ADMIN)) return - globAdminTicketHolder.userDetailUI(usr.client) + globAdminTicketHolder.userDetailUI(usr) diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index 82d73499eb5..e68c396818a 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -28,6 +28,7 @@ prayer_type = "CULTIST PRAYER" deity = ticker.cultdat.entity_name + log_say("(PRAYER) [msg]", usr) msg = "[bicon(cross)][prayer_type][deity ? " (to [deity])" : ""]:[key_name(src, 1)] ([ADMIN_QUE(src,"?")]) ([ADMIN_PP(src,"PP")]) ([ADMIN_VV(src,"VV")]) ([ADMIN_SM(src,"SM")]) ([admin_jump_link(src)]) (CA) ([ADMIN_SC(src,"SC")]) (BLESS) (SMITE): [msg]" for(var/client/X in admins) @@ -36,7 +37,6 @@ to_chat(usr, "Your prayers have been received by the gods.") feedback_add_details("admin_verb","PR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - //log_admin("HELP: [key_name(src)]: [msg]") /proc/Centcomm_announce(var/text , var/mob/Sender) var/msg = sanitize(copytext(text, 1, MAX_MESSAGE_LEN)) diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index c81f30efc83..ecf8c336118 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -45,7 +45,7 @@ spawn_antag(C, get_turf(src.loc), "syndieborg") else checking = FALSE - to_chat(user, "Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.") + to_chat(user, "Unable to connect to Syndicate command. Please wait and try again later or refund your teleporter through your uplink.") return /obj/item/antag_spawner/borg_tele/spawn_antag(client/C, turf/T, type = "") diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm index df7206a7914..8228e490a38 100644 --- a/code/modules/assembly/voice.dm +++ b/code/modules/assembly/voice.dm @@ -10,46 +10,67 @@ bomb_name = "voice-activated bomb" - describe() - if(recorded || listening) - return "A meter on [src] flickers with every nearby sound." - else - return "[src] is deactivated." +/obj/item/assembly/voice/describe() + if(recorded || listening) + return "A meter on [src] flickers with every nearby sound." + else + return "[src] is deactivated." - hear_talk(mob/living/M as mob, msg) - hear_input(M, msg, 0) +/obj/item/assembly/voice/hear_talk(mob/living/M as mob, msg) + hear_input(M, msg, 0) - hear_message(mob/living/M as mob, msg) +/obj/item/assembly/voice/hear_message(mob/living/M as mob, msg) hear_input(M, msg, 1) - proc/hear_input(mob/living/M as mob, msg, type) - if(!istype(M,/mob/living)) - return - if(listening) - recorded = msg - recorded_type = type - listening = 0 - var/turf/T = get_turf(src) //otherwise it won't work in hand - T.visible_message("[bicon(src)] beeps, \"Activation message is [type ? "the sound when one [recorded]" : "'[recorded]'."]\"") - else - if(findtext(msg, recorded) && type == recorded_type) - pulse(0) - var/turf/T = get_turf(src) //otherwise it won't work in hand - T.visible_message("[bicon(src)] beeps!") +/obj/item/assembly/voice/proc/hear_input(mob/living/M as mob, msg, type) + if(!istype(M,/mob/living)) + return + if(listening) + recorded = msg + recorded_type = type + listening = 0 + var/turf/T = get_turf(src) //otherwise it won't work in hand + T.visible_message("[bicon(src)] beeps, \"Activation message is [type ? "the sound when one [recorded]" : "'[recorded]'."]\"") + else if(findtext(msg, recorded) && type == recorded_type) + pulse(0) + var/turf/T = get_turf(src) //otherwise it won't work in hand + T.visible_message("[bicon(src)] beeps!") - activate() - return // previously this toggled listning when not in a holder, that's a little silly. It was only called in attack_self that way. +/obj/item/assembly/voice/activate() + return // previously this toggled listning when not in a holder, that's a little silly. It was only called in attack_self that way. - attack_self(mob/user) - if(!user || !secured) return 0 +/obj/item/assembly/voice/attack_self(mob/user) + if(!user || !secured) return 0 - listening = !listening - var/turf/T = get_turf(src) - T.visible_message("[bicon(src)] beeps, \"[listening ? "Now" : "No longer"] recording input.\"") - return 1 + listening = !listening + var/turf/T = get_turf(src) + T.visible_message("[bicon(src)] beeps, \"[listening ? "Now" : "No longer"] recording input.\"") + return 1 - toggle_secure() - . = ..() - listening = 0 \ No newline at end of file +/obj/item/assembly/voice/toggle_secure() + . = ..() + listening = 0 + +/obj/item/assembly/voice/noise + name = "noise sensor" + desc = "A simple noise sensor that triggers on vocalizations other then speech." + icon_state = "voice" + materials = list(MAT_METAL=100, MAT_GLASS=10) + origin_tech = "magnets=1;engineering=1" + bomb_name = "noise-activated bomb" + +/obj/item/assembly/voice/noise/attack_self(mob/user) + return + +/obj/item/assembly/voice/noise/describe() + return "[src] does not appear to have any controls." + +/obj/item/assembly/voice/noise/hear_talk(mob/living/M as mob, msg) + return + +/obj/item/assembly/voice/hear_message(mob/living/M as mob, msg) + pulse(0) + var/turf/T = get_turf(src) //otherwise it won't work in hand + T.visible_message("[bicon(src)] beeps!") \ No newline at end of file diff --git a/code/modules/awaymissions/maploader/swapmaps.dm b/code/modules/awaymissions/maploader/swapmaps.dm deleted file mode 100644 index bdb15581b61..00000000000 --- a/code/modules/awaymissions/maploader/swapmaps.dm +++ /dev/null @@ -1,677 +0,0 @@ -/* - SwapMaps library by Lummox JR - developed for digitalBYOND - http://www.digitalbyond.org - - Version 2.1 - - The purpose of this library is to make it easy for authors to swap maps - in and out of their game using savefiles. Swapped-out maps can be - transferred between worlds for an MMORPG, sent to the client, etc. - This is facilitated by the use of a special datum and a global list. - - Uses of swapmaps: - - - Temporary battle arenas - - House interiors - - Individual custom player houses - - Virtually unlimited terrain - - Sharing maps between servers running different instances of the same - game - - Loading and saving pieces of maps for reusable room templates - */ - -/* - User Interface: - - VARS: - - swapmaps_iconcache - An associative list of icon files with names, like - 'player.dmi' = "player" - swapmaps_mode - This must be set at runtime, like in world/New(). - - SWAPMAPS_SAV 0 (default) - Uses .sav files for raw /savefile output. - SWAPMAPS_TEXT 1 - Uses .txt files via ExportText() and ImportText(). These maps - are easily editable and appear to take up less space in the - current version of BYOND. - - PROCS: - - SwapMaps_Find(id) - Find a map by its id - SwapMaps_Load(id) - Load a map by its id - SwapMaps_Save(id) - Save a map by its id (calls swapmap.Save()) - SwapMaps_Unload(id) - Save and unload a map by its id (calls swapmap.Unload()) - SwapMaps_Save_All() - Save all maps - SwapMaps_DeleteFile(id) - Delete a map file - SwapMaps_CreateFromTemplate(id) - Create a new map by loading another map to use as a template. - This map has id==src and will not be saved. To make it savable, - change id with swapmap.SetID(newid). - SwapMaps_LoadChunk(id,turf/locorner) - Load a swapmap as a "chunk", at a specific place. A new datum is - created but it's not added to the list of maps to save or unload. - The new datum can be safely deleted without affecting the turfs - it loaded. The purpose of this is to load a map file onto part of - another swapmap or an existing part of the world. - locorner is the corner turf with the lowest x,y,z values. - SwapMaps_SaveChunk(id,turf/corner1,turf/corner2) - Save a piece of the world as a "chunk". A new datum is created - for the chunk, but it can be deleted without destroying any turfs. - The chunk file can be reloaded as a swapmap all its own, or loaded - via SwapMaps_LoadChunk() to become part of another map. - SwapMaps_GetSize(id) - Return a list corresponding to the x,y,z sizes of a map file, - without loading the map. - Returns null if the map is not found. - SwapMaps_AddIconToCache(name,icon) - Cache an icon file by name for space-saving storage - - swapmap.New(id,x,y,z) - Create a new map; specify id, width (x), height (y), and - depth (z) - Default size is world.maxx,world.maxy,1 - swapmap.New(id,turf1,turf2) - Create a new map; specify id and 2 corners - This becomes a /swapmap for one of the compiled-in maps, for - easy saving. - swapmap.New() - Create a new map datum, but does not allocate space or assign an - ID (used for loading). - swapmap.Del() - Deletes a map but does not save - swapmap.Save() - Saves to map_[id].sav - Maps with id==src are not saved. - swapmap.Unload() - Saves the map and then deletes it - Maps with id==src are not saved. - swapmap.SetID(id) - Change the map's id and make changes to the lookup list - swapmap.AllTurfs(z) - Returns a block of turfs encompassing the entire map, or on just - one z-level - z is in world coordinates; it is optional - swapmap.Contains(turf/T) - Returns nonzero if T is inside the map's boundaries. - Also works for objs and mobs, but the proc is not area-safe. - swapmap.InUse() - Returns nonzero if a mob with a key is within the map's - boundaries. - swapmap.LoCorner(z=z1) - Returns locate(x1,y1,z), where z=z1 if none is specified. - swapmap.HiCorner(z=z2) - Returns locate(x2,y2,z), where z=z2 if none is specified. - swapmap.BuildFilledRectangle(turf/corner1,turf/corner2,item) - Builds a filled rectangle of item from one corner turf to the - other, on multiple z-levels if necessary. The corners may be - specified in any order. - item is a type path like /turf/wall or /obj/barrel{full=1}. - swapmap.BuildRectangle(turf/corner1,turf/corner2,item) - Builds an unfilled rectangle of item from one corner turf to - the other, on multiple z-levels if necessary. - swapmap.BuildInTurfs(list/turfs,item) - Builds item on all of the turfs listed. The list need not - contain only turfs, or even only atoms. - */ - -swapmap - var/id // a string identifying this map uniquely - var/x1 // minimum x,y,z coords - var/y1 - var/z1 - var/x2 // maximum x,y,z coords (also used as width,height,depth until positioned) - var/y2 - var/z2 - var/tmp/locked // don't move anyone to this map; it's saving or loading - var/tmp/mode // save as text-mode - var/ischunk // tells the load routine to load to the specified location - - New(_id,x,y,z) - if(isnull(_id)) return - id=_id - mode=swapmaps_mode - if(isturf(x) && isturf(y)) - /* - Special format: Defines a map as an existing set of turfs; - this is useful for saving a compiled map in swapmap format. - Because this is a compiled-in map, its turfs are not deleted - when the datum is deleted. - */ - x1=min(x:x,y:x);x2=max(x:x,y:x) - y1=min(x:y,y:y);y2=max(x:y,y:y) - z1=min(x:z,y:z);z2=max(x:z,y:z) - InitializeSwapMaps() - if(z2>swapmaps_compiled_maxz ||\ - y2>swapmaps_compiled_maxy ||\ - x2>swapmaps_compiled_maxx) - qdel(src) - return - x2=x?(x):world.maxx - y2=y?(y):world.maxy - z2=z?(z):1 - AllocateSwapMap() - - Destroy() - // a temporary datum for a chunk can be deleted outright - // for others, some cleanup is necessary - if(!ischunk) - swapmaps_loaded-=src - swapmaps_byname-=id - if(z2>swapmaps_compiled_maxz ||\ - y2>swapmaps_compiled_maxy ||\ - x2>swapmaps_compiled_maxx) - var/list/areas=new - for(var/atom/A in block(locate(x1,y1,z1),locate(x2,y2,z2))) - for(var/obj/O in A) qdel(O) - for(var/mob/M in A) - if(!M.key) qdel(M) - else M.loc=null - areas[A.loc]=null - qdel(A) - // delete areas that belong only to this map - for(var/area/a in areas) - if(a && !a.contents.len) qdel(a) - if(x2>=world.maxx || y2>=world.maxy || z2>=world.maxz) CutXYZ() - qdel(areas) - ..() - return QDEL_HINT_HARDDEL_NOW - - /* - Savefile format: - map - id - x // size, not coords - y - z - areas // list of areas, not including default - [each z; 1 to depth] - [each y; 1 to height] - [each x; 1 to width] - type // of turf - AREA // if non-default; saved as a number (index into areas list) - vars // all other changed vars - */ - Write(savefile/S) - var/x - var/y - var/z - var/n - var/list/areas - var/area/defarea=locate(world.area) - if(!defarea) defarea=new world.area - areas=list() - for(var/turf/T in block(locate(x1,y1,z1),locate(x2,y2,z2))) - areas[T.loc]=null - for(n in areas) // quickly eliminate associations for smaller storage - areas-=n - areas+=n - areas-=defarea - InitializeSwapMaps() - locked=1 - S["id"] << id - S["z"] << z2-z1+1 - S["y"] << y2-y1+1 - S["x"] << x2-x1+1 - S["areas"] << areas - for(n in 1 to areas.len) areas[areas[n]]=n - var/oldcd=S.cd - for(z in z1 to z2) - S.cd="[z-z1+1]" - for(y in y1 to y2) - S.cd="[y-y1+1]" - for(x in x1 to x2) - S.cd="[x-x1+1]" - var/turf/T=locate(x,y,z) - S["type"] << T.type - if(T.loc!=defarea) S["AREA"] << areas[T.loc] - T.Write(S) - S.cd=".." - S.cd=".." - sleep() - S.cd=oldcd - locked=0 - qdel(areas) - - Read(savefile/S,_id,turf/locorner) - var/x - var/y - var/z - var/n - var/list/areas - var/area/defarea=locate(world.area) - id=_id - if(locorner) - ischunk=1 - x1=locorner.x - y1=locorner.y - z1=locorner.z - if(!defarea) defarea=new world.area - if(!_id) - S["id"] >> id - else - var/dummy - S["id"] >> dummy - S["z"] >> z2 // these are depth, - S["y"] >> y2 // height, - S["x"] >> x2 // width - S["areas"] >> areas - locked=1 - AllocateSwapMap() // adjust x1,y1,z1 - x2,y2,z2 coords - var/oldcd=S.cd - for(z in z1 to z2) - S.cd="[z-z1+1]" - for(y in y1 to y2) - S.cd="[y-y1+1]" - for(x in x1 to x2) - S.cd="[x-x1+1]" - var/tp - S["type"]>>tp - var/turf/T=locate(x,y,z) - T.loc.contents-=T - T=new tp(locate(x,y,z)) - if("AREA" in S.dir) - S["AREA"]>>n - var/area/A=areas[n] - A.contents+=T - else defarea.contents+=T - // clear the turf - for(var/obj/O in T) qdel(O) - for(var/mob/M in T) - if(!M.key) qdel(M) - else M.loc=null - // finish the read - T.Read(S) - S.cd=".." - S.cd=".." - sleep() - S.cd=oldcd - locked=0 - qdel(areas) - - /* - Find an empty block on the world map in which to load this map. - If no space is found, increase world.maxz as necessary. (If the - map is greater in x,y size than the current world, expand - world.maxx and world.maxy too.) - - Ignore certain operations if loading a map as a chunk. Use the - x1,y1,z1 position for it, and *don't* count it as a loaded map. - */ - proc/AllocateSwapMap() - InitializeSwapMaps() - world.maxx=max(x2,world.maxx) // stretch x/y if necessary - world.maxy=max(y2,world.maxy) - if(!ischunk) - if(world.maxz<=swapmaps_compiled_maxz) - z1=swapmaps_compiled_maxz+1 - x1=1;y1=1 - else - var/list/l=ConsiderRegion(1,1,world.maxx,world.maxy,swapmaps_compiled_maxz+1) - x1=l[1] - y1=l[2] - z1=l[3] - qdel(l) - x2+=x1-1 - y2+=y1-1 - z2+=z1-1 - space_manager.increase_max_zlevel_to(z2) // stretch z if necessary - if(!ischunk) - swapmaps_loaded[src]=null - swapmaps_byname[id]=src - - proc/ConsiderRegion(X1,Y1,X2,Y2,Z1,Z2) - while(1) - var/nextz=0 - var/swapmap/M - for(M in swapmaps_loaded) - if(M.z2Z2) || M.z1>=Z1+z2 ||\ - M.x1>X2 || M.x2=X1+x2 ||\ - M.y1>Y2 || M.y2=Y1+y2) continue - // look for sub-regions with a defined ceiling - var/nz2=Z2?(Z2):Z1+z2-1+M.z2-M.z1 - if(M.x1>=X1+x2) - .=ConsiderRegion(X1,Y1,M.x1-1,Y2,Z1,nz2) - if(.) return - else if(M.x2<=X2-x2) - .=ConsiderRegion(M.x2+1,Y1,X2,Y2,Z1,nz2) - if(.) return - if(M.y1>=Y1+y2) - .=ConsiderRegion(X1,Y1,X2,M.y1-1,Z1,nz2) - if(.) return - else if(M.y2<=Y2-y2) - .=ConsiderRegion(X1,M.y2+1,X2,Y2,Z1,nz2) - if(.) return - nextz=nextz?min(nextz,M.z2+1):(M.z2+1) - if(!M) - /* If nextz is not 0, then at some point there was an overlap that - could not be resolved by using an area to the side */ - if(nextz) Z1=nextz - if(!nextz || (Z2 && Z2-Z1+1=z2)?list(X1,Y1,Z1):null - X1=1;X2=world.maxx - Y1=1;Y2=world.maxy - - proc/CutXYZ() - var/mx=swapmaps_compiled_maxx - var/my=swapmaps_compiled_maxy - var/mz=swapmaps_compiled_maxz - for(var/swapmap/M in swapmaps_loaded) // may not include src - mx=max(mx,M.x2) - my=max(my,M.y2) - mz=max(mz,M.z2) - world.maxx=mx - world.maxy=my - space_manager.cut_levels_downto(mz) - - // save and delete - proc/Unload() - Save() - qdel(src) - - proc/Save() - if(id==src) return 0 - var/savefile/S=mode?(new):new("map_[id].sav") - S << src - while(locked) sleep(1) - if(mode) - fdel("map_[id].txt") - S.ExportText("/","map_[id].txt") - return 1 - - // this will not delete existing savefiles for this map - proc/SetID(newid) - swapmaps_byname-=id - id=newid - swapmaps_byname[id]=src - - proc/AllTurfs(z) - if(isnum(z) && (zz2)) return null - return block(LoCorner(z),HiCorner(z)) - - // this could be safely called for an obj or mob as well, but - // probably not an area - proc/Contains(turf/T) - return (T && T.x>=x1 && T.x<=x2\ - && T.y>=y1 && T.y<=y2\ - && T.z>=z1 && T.z<=z2) - - proc/InUse() - for(var/turf/T in AllTurfs()) - for(var/mob/M in T) if(M.key) return 1 - - proc/LoCorner(z=z1) - return locate(x1,y1,z) - proc/HiCorner(z=z2) - return locate(x2,y2,z) - - /* - Build procs: Take 2 turfs as corners, plus an item type. - An item may be like: - - /turf/wall - /obj/fence{icon_state="iron"} - */ - proc/BuildFilledRectangle(turf/T1,turf/T2,item) - if(!Contains(T1) || !Contains(T2)) return - var/turf/T=T1 - // pick new corners in a block()-friendly form - T1=locate(min(T1.x,T2.x),min(T1.y,T2.y),min(T1.z,T2.z)) - T2=locate(max(T.x,T2.x),max(T.y,T2.y),max(T.z,T2.z)) - for(T in block(T1,T2)) new item(T) - - proc/BuildRectangle(turf/T1,turf/T2,item) - if(!Contains(T1) || !Contains(T2)) return - var/turf/T=T1 - // pick new corners in a block()-friendly form - T1=locate(min(T1.x,T2.x),min(T1.y,T2.y),min(T1.z,T2.z)) - T2=locate(max(T.x,T2.x),max(T.y,T2.y),max(T.z,T2.z)) - if(T2.x-T1.x<2 || T2.y-T1.y<2) BuildFilledRectangle(T1,T2,item) - else - //for(T in block(T1,T2)-block(locate(T1.x+1,T1.y+1,T1.z),locate(T2.x-1,T2.y-1,T2.z))) - for(T in block(T1,locate(T2.x,T1.y,T2.z))) new item(T) - for(T in block(locate(T1.x,T2.y,T1.z),T2)) new item(T) - for(T in block(locate(T1.x,T1.y+1,T1.z),locate(T1.x,T2.y-1,T2.z))) new item(T) - for(T in block(locate(T2.x,T1.y+1,T1.z),locate(T2.x,T2.y-1,T2.z))) new item(T) - - /* - Supplementary build proc: Takes a list of turfs, plus an item - type. Actually the list doesn't have to be just turfs. - */ - proc/BuildInTurfs(list/turfs,item) - for(var/T in turfs) new item(T) - -atom - Write(savefile/S) - for(var/V in vars-"x"-"y"-"z"-"contents"-"icon"-"overlays"-"underlays") - if(issaved(vars[V])) - if(vars[V]!=initial(vars[V])) S[V]<>ic - if(istext(ic)) icon=swapmaps_iconcache[ic] - if(l && contents!=l) - contents+=l - qdel(l) - - -// set this up (at runtime) as follows: -// list(\ -// 'player.dmi'="player",\ -// 'monster.dmi'="monster",\ -// ... -// 'item.dmi'="item") -var/list/swapmaps_iconcache - -// preferred mode; sav or text -var/const/SWAPMAPS_SAV=0 -var/const/SWAPMAPS_TEXT=1 -var/swapmaps_mode=SWAPMAPS_SAV - -var/swapmaps_compiled_maxx -var/swapmaps_compiled_maxy -var/swapmaps_compiled_maxz -var/swapmaps_initialized -var/swapmaps_loaded -var/swapmaps_byname - -proc/InitializeSwapMaps() - if(swapmaps_initialized) return - swapmaps_initialized=1 - swapmaps_compiled_maxx=world.maxx - swapmaps_compiled_maxy=world.maxy - swapmaps_compiled_maxz=world.maxz - swapmaps_loaded=list() - swapmaps_byname=list() - if(swapmaps_iconcache) - for(var/V in swapmaps_iconcache) - // reverse-associate everything - // so you can look up an icon file by name or vice-versa - swapmaps_iconcache[swapmaps_iconcache[V]]=V - -proc/SwapMaps_AddIconToCache(name,icon) - if(!swapmaps_iconcache) swapmaps_iconcache=list() - swapmaps_iconcache[name]=icon - swapmaps_iconcache[icon]=name - -proc/SwapMaps_Find(id) - InitializeSwapMaps() - return swapmaps_byname[id] - -proc/SwapMaps_Load(id) - InitializeSwapMaps() - var/swapmap/M=swapmaps_byname[id] - if(!M) - var/savefile/S - var/text=0 - if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[id].txt")) - text=1 - else if(fexists("map_[id].sav")) - S=new("map_[id].sav") - else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[id].txt")) - text=1 - else return // no file found - if(text) - S=new - S.ImportText("/",file("map_[id].txt")) - S >> M - while(M.locked) sleep(1) - M.mode=text - return M - -proc/SwapMaps_Save(id) - InitializeSwapMaps() - var/swapmap/M=swapmaps_byname[id] - if(M) M.Save() - return M - -proc/SwapMaps_Save_All() - InitializeSwapMaps() - for(var/swapmap/M in swapmaps_loaded) - if(M) M.Save() - -proc/SwapMaps_Unload(id) - InitializeSwapMaps() - var/swapmap/M=swapmaps_byname[id] - if(!M) return // return silently from an error - M.Unload() - return 1 - -proc/SwapMaps_DeleteFile(id) - fdel("map_[id].sav") - fdel("map_[id].txt") - -proc/SwapMaps_CreateFromTemplate(template_id) - var/swapmap/M=new - var/savefile/S - var/text=0 - if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[template_id].txt")) - text=1 - else if(fexists("map_[template_id].sav")) - S=new("map_[template_id].sav") - else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[template_id].txt")) - text=1 - else - log_world("SwapMaps error in SwapMaps_CreateFromTemplate(): map_[template_id] file not found.") - return - if(text) - S=new - S.ImportText("/",file("map_[template_id].txt")) - /* - This hacky workaround is needed because S >> M will create a brand new - M to fill with data. There's no way to control the Read() process - properly otherwise. The //.0 path should always match the map, however. - */ - S.cd="//.0" - M.Read(S,M) - M.mode=text - while(M.locked) sleep(1) - return M - -proc/SwapMaps_LoadChunk(chunk_id,turf/locorner) - var/swapmap/M=new - var/savefile/S - var/text=0 - if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[chunk_id].txt")) - text=1 - else if(fexists("map_[chunk_id].sav")) - S=new("map_[chunk_id].sav") - else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[chunk_id].txt")) - text=1 - else - log_world("SwapMaps error in SwapMaps_LoadChunk(): map_[chunk_id] file not found.") - return - if(text) - S=new - S.ImportText("/",file("map_[chunk_id].txt")) - /* - This hacky workaround is needed because S >> M will create a brand new - M to fill with data. There's no way to control the Read() process - properly otherwise. The //.0 path should always match the map, however. - */ - S.cd="//.0" - M.Read(S,M,locorner) - while(M.locked) sleep(1) - qdel(M) - return 1 - -proc/SwapMaps_SaveChunk(chunk_id,turf/corner1,turf/corner2) - if(!corner1 || !corner2) - log_world("SwapMaps error in SwapMaps_SaveChunk():") - if(!corner1) log_world(" corner1 turf is null") - if(!corner2) log_world(" corner2 turf is null") - return - var/swapmap/M=new - M.id=chunk_id - M.ischunk=1 // this is a chunk - M.x1=min(corner1.x,corner2.x) - M.y1=min(corner1.y,corner2.y) - M.z1=min(corner1.z,corner2.z) - M.x2=max(corner1.x,corner2.x) - M.y2=max(corner1.y,corner2.y) - M.z2=max(corner1.z,corner2.z) - M.mode=swapmaps_mode - M.Save() - while(M.locked) sleep(1) - qdel(M) - return 1 - -proc/SwapMaps_GetSize(id) - var/savefile/S - var/text=0 - if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[id].txt")) - text=1 - else if(fexists("map_[id].sav")) - S=new("map_[id].sav") - else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[id].txt")) - text=1 - else - log_world("SwapMaps error in SwapMaps_GetSize(): map_[id] file not found.") - return - if(text) - S=new - S.ImportText("/",file("map_[id].txt")) - /* - The //.0 path should always be the map. There's no other way to - read this data. - */ - S.cd="//.0" - var/x - var/y - var/z - S["x"] >> x - S["y"] >> y - S["z"] >> z - return list(x,y,z) diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index 22f293aedfc..fba251f71f8 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -120,6 +120,78 @@ mute = MUZZLE_MUTE_NONE security_lock = TRUE locked = FALSE + materials = list(MAT_METAL=500, MAT_GLASS=50) + +/obj/item/clothing/mask/muzzle/safety/shock + name = "shock muzzle" + desc = "A muzzle designed to prevent biting. This one is fitted with a behavior correction system." + var/obj/item/assembly/trigger = null + origin_tech = "materials=1;engineering=1" + materials = list(MAT_METAL=500, MAT_GLASS=50) + +/obj/item/clothing/mask/muzzle/safety/shock/attackby(obj/item/W, mob/user, params) + if(isscrewdriver(W) && trigger) + to_chat(user, "You disassemble [src].") + trigger.forceMove(get_turf(user)) + trigger.master = null + trigger.holder = null + trigger = null + return TRUE + else if(istype(W, /obj/item/assembly/signaler) || istype(W, /obj/item/assembly/voice)) + if(istype(trigger, /obj/item/assembly/signaler) || istype(trigger, /obj/item/assembly/voice)) + to_chat(user, "Something is already attached to [src].") + return FALSE + if(!user.drop_item()) + to_chat(user, "You are unable to insert [W] into [src].") + return FALSE + trigger = W + trigger.forceMove(src) + trigger.master = src + trigger.holder = src + to_chat(user, "You attach the [W] to [src].") + return TRUE + else if(istype(W, /obj/item/assembly)) + to_chat(user, "That won't fit in [src]. Perhaps a signaler or voice analyzer would?") + return FALSE + + return ..() + + +/obj/item/clothing/mask/muzzle/safety/shock/proc/can_shock(obj/item/clothing/C) + if(istype(C)) + if(isliving(C.loc)) + return C.loc + else if(isliving(loc)) + return loc + return FALSE + +/obj/item/clothing/mask/muzzle/safety/shock/proc/process_activation(var/obj/D, var/normal = 1, var/special = 1) + visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*") + var/mob/M = can_shock(loc) + if(M) + to_chat(M, "You feel a sharp shock!") + var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread + s.set_up(3, 1, M) + s.start() + + M.Weaken(5) + M.Stuttering(1) + M.Jitter(20) + return + +/obj/item/clothing/mask/muzzle/safety/shock/HasProximity(atom/movable/AM as mob|obj) + if(trigger) + trigger.HasProximity(AM) + + +/obj/item/clothing/mask/muzzle/safety/shock/hear_talk(mob/living/M as mob, msg) + if(trigger) + trigger.hear_talk(M, msg) + +/obj/item/clothing/mask/muzzle/safety/shock/hear_message(mob/living/M as mob, msg) + if(trigger) + trigger.hear_message(M, msg) + /obj/item/clothing/mask/surgical diff --git a/code/modules/events/grid_check.dm b/code/modules/events/grid_check.dm index 9ca4e878050..c0b16ab43a6 100644 --- a/code/modules/events/grid_check.dm +++ b/code/modules/events/grid_check.dm @@ -17,12 +17,12 @@ if(announce) event_announcement.Announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", new_sound = 'sound/AI/poweroff.ogg') - var/list/skipped_areas = list(/area/turret_protected/ai, /area/syndicate_depot) - var/list/skipped_areas_apc = list(/area/engine/engineering, /area/syndicate_depot) + var/list/skipped_areas = list(/area/turret_protected/ai) + var/list/skipped_areas_apc = list(/area/engine/engineering) for(var/obj/machinery/power/smes/S in machines) var/area/current_area = get_area(S) - if(current_area.type in skipped_areas || !is_station_level(S.z)) + if((current_area.type in skipped_areas) || !is_station_level(S.z)) continue S.last_charge = S.charge S.last_output_attempt = S.output_attempt @@ -35,26 +35,26 @@ for(var/obj/machinery/power/apc/C in apcs) var/area/current_area = get_area(C) - if(current_area.type in skipped_areas_apc || !is_station_level(C.z)) + if((current_area.type in skipped_areas_apc) || !is_station_level(C.z)) continue if(C.cell) C.cell.charge = 0 /proc/power_restore(var/announce = 1) - var/list/skipped_areas = list(/area/turret_protected/ai, /area/syndicate_depot) - var/list/skipped_areas_apc = list(/area/engine/engineering, /area/syndicate_depot) + var/list/skipped_areas = list(/area/turret_protected/ai) + var/list/skipped_areas_apc = list(/area/engine/engineering) if(announce) event_announcement.Announce("Power has been restored to [station_name()]. We apologize for the inconvenience.", "Power Systems Nominal", new_sound = 'sound/AI/poweron.ogg') for(var/obj/machinery/power/apc/C in apcs) var/area/current_area = get_area(C) - if(current_area.type in skipped_areas_apc || !is_station_level(C.z)) + if((current_area.type in skipped_areas_apc) || !is_station_level(C.z)) continue if(C.cell) C.cell.charge = C.cell.maxcharge for(var/obj/machinery/power/smes/S in machines) var/area/current_area = get_area(S) - if(current_area.type in skipped_areas || !is_station_level(S.z)) + if((current_area.type in skipped_areas) || !is_station_level(S.z)) continue S.charge = S.last_charge S.output_attempt = S.last_output_attempt diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm index e14aaa09ba7..7efb6460b75 100644 --- a/code/modules/games/cards.dm +++ b/code/modules/games/cards.dm @@ -221,6 +221,8 @@ return if(over_object == M) + if(!remove_item_from_storage(M)) + M.unEquip(src) M.put_in_hands(src) else if(istype(over_object, /obj/screen)) @@ -374,10 +376,11 @@ H.parentdeck = parentdeck H.concealed = concealed H.update_icon() - update_icon() if(!cards.len) qdel(src) + return + update_icon() /obj/item/cardhand/verb/discard(var/mob/user as mob) @@ -410,7 +413,7 @@ if(cards.len) update_icon() if(H.cards.len) - usr.visible_message("The [user] plays the [discarding].", "You play the [discarding].") + usr.visible_message("The [usr] plays the [discarding].", "You play the [discarding].") H.loc = get_step(usr,usr.dir) if(!cards.len) @@ -419,7 +422,6 @@ /obj/item/cardhand/update_icon(var/direction = 0) if(!cards.len) - qdel(src) return else if(cards.len > 1) name = "hand of cards" diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm index 5b4a35262d7..84db02cb89c 100644 --- a/code/modules/hydroponics/plant_genes.dm +++ b/code/modules/hydroponics/plant_genes.dm @@ -315,12 +315,16 @@ /datum/plant_gene/trait/teleport/on_slip(obj/item/reagent_containers/food/snacks/grown/G, mob/living/carbon/C) var/teleport_radius = max(round(G.seed.potency / 10), 1) var/turf/T = get_turf(C) - to_chat(C, "You slip through spacetime!") - do_teleport(C, T, teleport_radius) - if(prob(50)) - do_teleport(G, T, teleport_radius) + if(do_teleport(C, T, teleport_radius)) + to_chat(C, "You slip through spacetime!") + if(prob(50)) + do_teleport(G, T, teleport_radius) + else + new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect... + qdel(G) else - new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect... + to_chat(C, "[src] sparks, and burns up!") + new /obj/effect/decal/cleanable/molten_object(T) qdel(G) diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm index bf9c5a67783..852bcd3edf3 100644 --- a/code/modules/mining/equipment_locker.dm +++ b/code/modules/mining/equipment_locker.dm @@ -664,6 +664,9 @@ var/turf/T = get_turf(H) T.add_vomit_floor(H) playsound(H, 'sound/effects/splat.ogg', 50, 1) + else + visible_message("[src] flickers and fails, due to bluespace interference!") + qdel(src) /**********************Resonator**********************/ diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index 623f5b6b353..fffda3a2158 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -24,15 +24,20 @@ return target // All mobs should have custom emote, really.. -/mob/proc/custom_emote(var/m_type=1,var/message = null) +/mob/proc/custom_emote(var/m_type=EMOTE_VISUAL,var/message = null) if(stat || !use_me && usr == src) if(usr) to_chat(usr, "You are unable to emote.") return - var/muzzled = istype(src.wear_mask, /obj/item/clothing/mask/muzzle) - if(m_type == 2 && muzzled) return + var/muzzled = is_muzzled() + if(muzzled) + var/obj/item/clothing/mask/muzzle/M = wear_mask + if(m_type == EMOTE_SOUND && M.mute >= MUZZLE_MUTE_MUFFLE) + return //Not all muzzles block sound + if(!can_speak()) + return var/input if(!message) @@ -63,7 +68,7 @@ // Type 1 (Visual) emotes are sent to anyone in view of the item - if(m_type & 1) + if(m_type & EMOTE_VISUAL) var/list/can_see = get_mobs_in_view(1,src) //Allows silicon & mmi mobs carried around to see the emotes of the person carrying them around. can_see |= viewers(src,null) for(var/mob/O in can_see) @@ -80,7 +85,7 @@ // Type 2 (Audible) emotes are sent to anyone in hear range // of the *LOCATION* -- this is important for pAIs to be heard - else if(m_type & 2) + else if(m_type & EMOTE_SOUND) for(var/mob/O in get_mobs_in_view(7,src)) if(O.status_flags & PASSEMOTES) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 069dc76b3b7..dcdbf67204e 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -10,6 +10,10 @@ act = copytext(act, 1, t1) var/muzzled = is_muzzled() + if(muzzled) + var/obj/item/clothing/mask/muzzle/M = wear_mask + if(M.mute == MUZZLE_MUTE_NONE) + muzzled = 0 //Not all muzzles block sound if(!can_speak()) muzzled = 1 //var/m_type = 1 diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 3f36b8b6d55..bce245addc0 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1328,7 +1328,7 @@ dna.species.create_organs(src) for(var/thing in kept_items) - equip_to_slot_or_del(thing, kept_items[thing]) + equip_to_slot_if_possible(thing, kept_items[thing], redraw_mob = 0) //Handle default hair/head accessories for created mobs. var/obj/item/organ/external/head/H = get_organ("head") diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index 0a3ed47b933..3e0317be509 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -6,6 +6,7 @@ /mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) if(..()) return 1 + used_radios += radio if(message_mode) if(!is_component_functioning("radio")) to_chat(src, "Your radio isn't functional at this time.") @@ -17,6 +18,7 @@ /mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) if(..()) return 1 + used_radios += aiRadio if(message_mode == "department") return holopad_talk(message, verb, speaking) else if(message_mode) @@ -36,6 +38,7 @@ else if(message_mode) if(message_mode == "general") message_mode = null + used_radios += radio return radio.talk_into(src,message,message_mode,verb,speaking) /mob/living/silicon/say_quote(var/text) diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm index 894c039b3f4..88e1e2aa1e5 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -51,7 +51,10 @@ var/damage = O.force if(O.damtype == STAMINA) damage = 0 - health -= damage + if(force_threshold && damage < force_threshold) + visible_message("[src] is unharmed by [O]!") + return + adjustHealth(damage) visible_message("[src] has been attacked with the [O] by [user]. ") playsound(loc, O.hitsound, 25, 1, -1) else @@ -125,6 +128,9 @@ seen_revived_enemy = TRUE raise_alert("[name] reports intruder [target] has returned from death!") depotarea.list_remove(target, depotarea.dead_list) + if(!atoms_share_level(src, target) && prob(20)) + // This prevents someone from aggroing a depot mob, then hiding in a locker, perfectly safe, while the mob stands there getting killed by their friends. + LoseTarget() /mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/handle_automated_action() if(seen_enemy) @@ -134,6 +140,14 @@ if(scan_cycles >= 15 && istype(depotarea)) scan_cycles = 0 if(!atoms_share_level(src, spawn_turf)) + if(istype(loc, /obj/structure/closet)) + var/obj/structure/closet/O = loc + forceMove(get_turf(src)) + visible_message("[src] smashes their way out of [O]!") + qdel(O) + raise_alert("[src] reported being trapped in a locker.") + raised_alert = FALSE + return if(alert_on_spacing) raise_alert("[src] lost in space.") death() @@ -196,12 +210,6 @@ alert_on_timeout = TRUE alert_on_shield_breach = TRUE -/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/armory/death() - if(depotarea) - depotarea.declare_finished() - return ..() - - /mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/armory/Initialize() . = ..() if(istype(depotarea)) diff --git a/code/modules/mob/living/update_status.dm b/code/modules/mob/living/update_status.dm index f7498392c02..c7f9bdd0d96 100644 --- a/code/modules/mob/living/update_status.dm +++ b/code/modules/mob/living/update_status.dm @@ -49,7 +49,14 @@ // Whether the mob is capable of talking /mob/living/can_speak() - return !(silent || (disabilities & MUTE) || is_muzzled()) + if(!(silent || (disabilities & MUTE))) + if(is_muzzled()) + var/obj/item/clothing/mask/muzzle/M = wear_mask + if(M.mute >= MUZZLE_MUTE_MUFFLE) + return FALSE + return TRUE + else + return FALSE // Whether the mob is capable of standing or not /mob/living/proc/can_stand() diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index 83bb2ae1322..2eb7e883425 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -1292,6 +1292,11 @@ name = "Rough-Cropped Mane" icon_state = "rough" +/datum/sprite_accessory/hair/vulpkanin/vulp_hair_raine + name = "Raine" + icon_state = "vulp_hair_raine" + gender = FEMALE + /datum/sprite_accessory/hair/vox species_allowed = list("Vox") glasses_over = 1 diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index 831b496bab7..586138f1845 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -32,6 +32,8 @@ return if(over_object == M) + if(!remove_item_from_storage(M)) + M.unEquip(src) M.put_in_hands(src) else if(istype(over_object, /obj/screen)) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index ae64d5d4d6e..e9190835b35 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -1,3 +1,5 @@ +#define HEALPERCABLE 3 +#define MAXCABLEPERHEAL 8 /////////////////////////////// //CABLE STRUCTURE /////////////////////////////// @@ -531,23 +533,44 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list( if(!S.is_robotic() || user.a_intent != INTENT_HELP || S.open == 2) return ..() - if(S.burn_dam) - if(S.burn_dam < ROBOLIMB_SELF_REPAIR_CAP) - if(H == user) - if(!do_mob(user, H, 10)) - return 1 - var/cable_to_use = 0 - for(cable_to_use in 1 to 5) - if(cable_to_use == amount || (cable_to_use * 3) >= S.burn_dam) - break - use(cable_to_use) - S.heal_damage(0, (cable_to_use * 3), 0, 1) - user.visible_message("\The [user] repairs some burn damage on \the [M]'s [S.name] with \the [src].") - else if(S.open != 2) - to_chat(user, "The damage is far too severe to patch over externally.") - return 1 - else if(S.open != 2) + if(S.burn_dam > ROBOLIMB_SELF_REPAIR_CAP) + to_chat(user, "The damage is far too severe to patch over externally.") + return + + if(!S.burn_dam) to_chat(user, "Nothing to fix!") + return + + if(H == user) + if(!do_mob(user, H, 10)) + return 0 + var/cable_used = 0 + var/childlist + if(!isnull(S.children)) + childlist = S.children.Copy() + var/parenthealed = FALSE + while(cable_used <= MAXCABLEPERHEAL && amount >= 1) + var/obj/item/organ/external/E + if(S.burn_dam) + E = S + else if(LAZYLEN(childlist)) + E = pick_n_take(childlist) + if(!E.burn_dam || !E.is_robotic()) + continue + else if(S.parent && !parenthealed) + E = S.parent + parenthealed = TRUE + if(!E.burn_dam || !E.is_robotic()) + break + else + break + while(cable_used <= MAXCABLEPERHEAL && E.burn_dam && amount >= 1) + use(1) + cable_used += 1 + E.heal_damage(0, HEALPERCABLE, 0, 1) + user.visible_message("\The [user] repairs some burn damage on \the [M]'s [E.name] with \the [src].") + return 1 + else return ..() @@ -820,3 +843,6 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list( var/cablecolor = input(user,"Pick a cable color.","Cable Color") in list("red","yellow","green","blue","pink","orange","cyan","white") color = cablecolor update_icon() + +#undef MAXCABLEPERHEAL +#undef HEALPERCABLE diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index a154691d0a8..0cd3a2ce0b2 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -172,7 +172,6 @@ damage_type = BRUTE flag = "bomb" range = 3 - log_override = TRUE var/pressure_decrease = 0.25 var/turf_aoe = FALSE @@ -218,7 +217,9 @@ for(var/mob/living/L in range(1, target_turf) - firer - target) var/armor = L.run_armor_check(def_zone, flag, "", "", armour_penetration) L.apply_damage(damage*mob_aoe, damage_type, def_zone, armor) - to_chat(L, "You're struck by a [name]!") + L.visible_message("[L] is hit by \a [src]!", + "You are hit by \a [src]!") + add_attack_logs(firer, L, "Shot with a [type]") //Modkits diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index a4578d9c1e3..90f9ed47eec 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -202,6 +202,9 @@ return name = reject_bad_text(name) while(count--) + if(reagents.total_volume <= 0) + to_chat(usr, "Not enough reagents to create these pills!") + return var/obj/item/reagent_containers/food/pill/P = new/obj/item/reagent_containers/food/pill(loc) if(!name) name = reagents.get_master_reagent_name() P.name = "[name] pill" diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 771d627b421..771214661b4 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -69,8 +69,8 @@ /obj/item/reagent_containers/hypospray/safety name = "medical hypospray" - desc = "A modified hypospray for quickly injecting safe medicinal chemicals." - icon_state = "combat_hypo" + desc = "A general use medical hypospray for quick injection of chemicals. There is a safety button by the trigger." + icon_state = "medivend_hypo" safety_hypo = TRUE /obj/item/reagent_containers/hypospray/CMO diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm index c7e276cae17..3bb3c237d07 100644 --- a/code/modules/recycling/disposal-construction.dm +++ b/code/modules/recycling/disposal-construction.dm @@ -258,6 +258,7 @@ return /obj/structure/disposalconstruct/rpd_act(mob/user, obj/item/rpd/our_rpd) + . = TRUE if(our_rpd.mode == RPD_ROTATE_MODE) rotate() else if(our_rpd.mode == RPD_FLIP_MODE) @@ -265,4 +266,4 @@ else if(our_rpd.mode == RPD_DELETE_MODE) our_rpd.delete_single_pipe(user, src) else - ..() + return ..() diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index bba85a5ff00..79dd9fb53f9 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -551,6 +551,14 @@ build_path = /obj/item/assembly/voice category = list("initial", "Miscellaneous") +/datum/design/noise_analyser + name = "Noise Analyser" + id = "Noise_analyser" + build_type = AUTOLATHE + materials = list(MAT_METAL = 100, MAT_GLASS = 10) + build_path = /obj/item/assembly/voice/noise + category = list("initial", "Miscellaneous") + /datum/design/light_tube name = "Light Tube" id = "light_tube" diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index 8bdf6771df1..1036bb6e188 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -60,3 +60,23 @@ materials = list(MAT_METAL = 500, MAT_GLASS = 300) build_path = /obj/item/camera/digital category = list("Miscellaneous") + +/datum/design/safety_muzzle + name = "Safety Muzzle" + desc = "Produce a lockable muzzle keyed to security ID cards" + id = "safetymuzzle" + req_tech = list("materials" = 1) + build_type = PROTOLATHE + materials = list(MAT_METAL=500, MAT_GLASS=50) + build_path = /obj/item/clothing/mask/muzzle/safety + category = list("Miscellaneous") + +/datum/design/shock_muzzle + name = "Shock Muzzle" + desc = "Produce a modified safety muzzle that includes an electric shock pack and a slot for a trigger assembly." + id = "shockmuzzle" + req_tech = list("materials" = 1, "engineering" = 1) + build_type = PROTOLATHE + materials = list(MAT_METAL=500, MAT_GLASS=50) + build_path = /obj/item/clothing/mask/muzzle/safety/shock + category = list("Miscellaneous") diff --git a/code/modules/telesci/telesci_computer.dm b/code/modules/telesci/telesci_computer.dm index b7cf78e5ed2..f0f1654ac30 100644 --- a/code/modules/telesci/telesci_computer.dm +++ b/code/modules/telesci/telesci_computer.dm @@ -311,7 +311,10 @@ return if(teles_left > 0) - doteleport(user) + if(!doteleport(user)) + telefail() + temp_msg = "ERROR! Target destination unreachable due to interference." + return else telefail() temp_msg = "ERROR!
Calibration required." diff --git a/html/changelog.html b/html/changelog.html index 28b7dfa242d..14c7c4af61b 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,6 +56,95 @@ -->
+

28 August 2018

+

Alffd updated:

+
    +
  • Fixes emote code to preform mute checking in the same manner as say code.
  • +
  • Adds a new type of muzzle that will shock its wearer when pulsed by an assembly.
  • +
  • Adds a new type of voice trigger assembly that is activated by audible emotes.
  • +
+

Birdtalon updated:

+
    +
  • Fixes torn down posters dropping hypothetical poster when their wall is deconstructed.
  • +
+

Ty-Omaha updated:

+
    +
  • Harm intent attack animations are red instead of white
  • +
+

taukausanake updated:

+
    +
  • Corrects formatting for the abductor objective messages
  • +
+

variableundefined updated:

+
    +
  • Logging for prayer.
  • +
+ +

26 August 2018

+

Agameofscones updated:

+
    +
  • Mr. Chang vendor sprite (icon_state: chang).
  • +
  • Three new Mr. Chang vendor slogans.
  • +
+ +

23 August 2018

+

Aurorablade updated:

+
    +
  • Changes to air Subsystem to make it load faster taken from TG by SpaceManiac.
  • +
  • Attemps to cap dogs you can cough up to 10..then you cough up a plush fox. Totally normal.
  • +
+

Birdtalon updated:

+
    +
  • Fixes unexpected item deletion upon changing species.
  • +
+

Kyep updated:

+
    +
  • Fixed a few bugs (notably, grid check event raising alert level) in the depot.
  • +
  • Fixed hand_tele, bluespace tomatoes, etc not respecting the tele_proof flag of areas.
  • +
+

alex-gh updated:

+
    +
  • Changeling fleshmend no longer overfills their blood.
  • +
+

variableundefined updated:

+
    +
  • Admin logging for kinetic accelerator.
  • +
  • Implantcase no longer disappears when dropped or placed in bag.
  • +
  • Logging to borer infestation.
  • +
  • A runtime with admin ticket.
  • +
  • Defibrillator paddles snap away if you walk away from the defibrillator.
  • +
  • Fixes the discard action not displaying who discarded a card from a hand of card
  • +
  • Fixes deck of card not being removed properly from your pocket when you drag it over your sprite.
  • +
+ +

18 August 2018

+

Crazylemon64 updated:

+
    +
  • makes AA's map fix not annihilate every map PR in existence
  • +
+ +

16 August 2018

+

AffectedArc07 updated:

+
    +
  • Half the scrubbers actually work now
  • +
+

Birdtalon updated:

+
    +
  • All obj/machinery is now below obj layer.
  • +
  • Prevents creation of 0u pills with Chem Master
  • +
+ +

15 August 2018

+

tlc2013 updated:

+
    +
  • The AutoDrobe now carries a Transylvanian Coat, imported straight from /vg/station for all your Dracula-cosplaying needs. Much like the false Wizard robes, it does nothing for the actual antagonist.
  • +
+

variableundefined updated:

+
    +
  • Banangarang's medical fluff cyborg's hair colour inconsistency.
  • +
  • Comfrey now actually works for healing brute damage.
  • +
+

09 August 2018

variableundefined updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index e3a5c43a874..09b665f8e09 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -6767,3 +6767,64 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. 2018-08-09: variableundefined: - rscadd: banangarang's maid bot fluff sprites +2018-08-15: + tlc2013: + - rscadd: The AutoDrobe now carries a Transylvanian Coat, imported straight from + /vg/station for all your Dracula-cosplaying needs. Much like the false Wizard + robes, it does nothing for the actual antagonist. + variableundefined: + - bugfix: Banangarang's medical fluff cyborg's hair colour inconsistency. + - bugfix: Comfrey now actually works for healing brute damage. +2018-08-16: + AffectedArc07: + - bugfix: Half the scrubbers actually work now + Birdtalon: + - tweak: All obj/machinery is now below obj layer. + - bugfix: Prevents creation of 0u pills with Chem Master +2018-08-18: + Crazylemon64: + - bugfix: makes AA's map fix not annihilate every map PR in existence +2018-08-23: + Aurorablade: + - tweak: Changes to air Subsystem to make it load faster taken from TG by SpaceManiac. + - tweak: Attemps to cap dogs you can cough up to 10..then you cough up a plush fox. + Totally normal. + Birdtalon: + - bugfix: Fixes unexpected item deletion upon changing species. + Kyep: + - bugfix: Fixed a few bugs (notably, grid check event raising alert level) in the + depot. + - bugfix: Fixed hand_tele, bluespace tomatoes, etc not respecting the tele_proof + flag of areas. + alex-gh: + - bugfix: Changeling fleshmend no longer overfills their blood. + variableundefined: + - rscadd: Admin logging for kinetic accelerator. + - bugfix: Implantcase no longer disappears when dropped or placed in bag. + - rscadd: Logging to borer infestation. + - bugfix: A runtime with admin ticket. + - tweak: Defibrillator paddles snap away if you walk away from the defibrillator. + - bugfix: Fixes the discard action not displaying who discarded a card from a hand + of card + - bugfix: Fixes deck of card not being removed properly from your pocket when you + drag it over your sprite. +2018-08-26: + Agameofscones: + - rscadd: 'Mr. Chang vendor sprite (icon_state: chang).' + - rscadd: Three new Mr. Chang vendor slogans. +2018-08-28: + Alffd: + - bugfix: Fixes emote code to preform mute checking in the same manner as say code. + - rscadd: Adds a new type of muzzle that will shock its wearer when pulsed by an + assembly. + - rscadd: Adds a new type of voice trigger assembly that is activated by audible + emotes. + Birdtalon: + - bugfix: Fixes torn down posters dropping hypothetical poster when their wall is + deconstructed. + Ty-Omaha: + - tweak: Harm intent attack animations are red instead of white + taukausanake: + - bugfix: Corrects formatting for the abductor objective messages + variableundefined: + - rscadd: Logging for prayer. diff --git a/html/changelogs/AutoChangeLog-pr-9350.yml b/html/changelogs/AutoChangeLog-pr-9350.yml deleted file mode 100644 index f1c9767a190..00000000000 --- a/html/changelogs/AutoChangeLog-pr-9350.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "tlc2013" -delete-after: True -changes: - - rscadd: "The AutoDrobe now carries a Transylvanian Coat, imported straight from /vg/station for all your Dracula-cosplaying needs. Much like the false Wizard robes, it does nothing for the actual antagonist." diff --git a/html/changelogs/AutoChangeLog-pr-9351.yml b/html/changelogs/AutoChangeLog-pr-9351.yml deleted file mode 100644 index 21fad584c09..00000000000 --- a/html/changelogs/AutoChangeLog-pr-9351.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "variableundefined" -delete-after: True -changes: - - bugfix: "Comfrey now actually works for healing brute damage." diff --git a/html/changelogs/AutoChangeLog-pr-9362.yml b/html/changelogs/AutoChangeLog-pr-9362.yml deleted file mode 100644 index d8a3179130b..00000000000 --- a/html/changelogs/AutoChangeLog-pr-9362.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "variableundefined" -delete-after: True -changes: - - bugfix: "Banangarang's medical fluff cyborg's hair colour inconsistency." diff --git a/html/changelogs/AutoChangeLog-pr-9420.yml b/html/changelogs/AutoChangeLog-pr-9420.yml new file mode 100644 index 00000000000..47aef7b1b23 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9420.yml @@ -0,0 +1,4 @@ +author: "variableundefined" +delete-after: True +changes: + - bugfix: "Silicons no longer broadcast their radio message to everyone in hearing range (Only those next to them). Yes, that's a bug, not a feature." diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index 80131245d13..8d6408a70a4 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ diff --git a/icons/obj/hypo.dmi b/icons/obj/hypo.dmi index a6df9972275..a51a981251d 100644 Binary files a/icons/obj/hypo.dmi and b/icons/obj/hypo.dmi differ diff --git a/icons/obj/vending.dmi b/icons/obj/vending.dmi index 11e59ff352b..66dbdc88c10 100755 Binary files a/icons/obj/vending.dmi and b/icons/obj/vending.dmi differ diff --git a/nano/templates/uplink.tmpl b/nano/templates/uplink.tmpl index d6dcec8d05f..6177ab016a7 100644 --- a/nano/templates/uplink.tmpl +++ b/nano/templates/uplink.tmpl @@ -1,5 +1,5 @@ - @@ -40,7 +40,7 @@ Used In File(s): \code\game\objects\items\devices\uplinks.dm
    {{:helper.link( itemValue.Name, 'gear', {'buy_item' : itemValue.obj_path, 'cost' : itemValue.Cost}, itemValue.Cost > data.crystals ? 'disabled' : null, null)}} - {{:itemValue.Cost}}
    - + {{if itemValue.Cost <= data.crystals && data.descriptions}}
    {{:itemValue.Description}} @@ -53,7 +53,11 @@ Used In File(s): \code\game\objects\items\devices\uplinks.dm
    {{:helper.link('Buy Random (??)' , 'gear', {'buy_item' : 'random'}, data.crystals <= 0 ? 'disabled' : null, null)}}
    - + +
    + {{:helper.link('Refund item in active hand' , 'gear', {refund : 1}, null, null)}} +
    + {{else data.menu == 1}}

    Information Record List:


    @@ -66,7 +70,7 @@ Used In File(s): \code\game\objects\items\devices\uplinks.dm {{:helper.link(value.Name, 'gear', {'menu' : 11, 'id' : value.id}, null, null)}}
    {{/for}} - + {{else data.menu == 11}}

    Information Record:


    diff --git a/paradise.dme b/paradise.dme index 70eaa50867a..7c4deb70dd2 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1193,7 +1193,6 @@ #include "code\modules\awaymissions\zvis.dm" #include "code\modules\awaymissions\maploader\dmm_suite.dm" #include "code\modules\awaymissions\maploader\reader.dm" -#include "code\modules\awaymissions\maploader\swapmaps.dm" #include "code\modules\awaymissions\maploader\writer.dm" #include "code\modules\awaymissions\mission_code\academy.dm" #include "code\modules\awaymissions\mission_code\beach.dm"