diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 9bfc6fa90b0..0b450df9848 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -274,6 +274,7 @@ CREATE TABLE `player` ( `nanoui_fancy` smallint(4) DEFAULT '1', `show_ghostitem_attack` smallint(4) DEFAULT '1', `lastchangelog` varchar(32) NOT NULL DEFAULT '0', + `exp` mediumtext, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index c0cc8c86d6b..2489e6cb325 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -273,6 +273,7 @@ CREATE TABLE `SS13_player` ( `nanoui_fancy` smallint(4) DEFAULT '1', `show_ghostitem_attack` smallint(4) DEFAULT '1', `lastchangelog` varchar(32) NOT NULL DEFAULT '0', + `exp` mediumtext, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm index 15a969e7a47..89a73aceaaf 100644 --- a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm +++ b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm @@ -1072,7 +1072,7 @@ "auF" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/floor/plating{tag = "icon-panelscorched"; icon_state = "panelscorched"},/area/maintenance/fpmaint2{name = "Port Maintenance"}) "auG" = (/obj/structure/closet/crate,/obj/item/clothing/gloves/color/fyellow,/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) "auH" = (/obj/structure/table,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/syndicatebomb/training,/turf/simulated/floor/plasteel,/area/security/main) -"auI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating{icon_plating = "warnplate"; icon_state = "warnplate"},/area/maintenance/fpmaint2{name = "Port Maintenance"}) +"auI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating{icon_plating = "warnplate"; icon_state = "warnplate"},/area/maintenance/fore) "auJ" = (/obj/structure/reagent_dispensers/watertank,/obj/item/weapon/extinguisher,/turf/simulated/floor/plating,/area/maintenance/fore) "auK" = (/obj/structure/closet/crate,/obj/item/weapon/restraints/handcuffs,/obj/item/bodybag,/obj/item/device/radio,/obj/effect/spawner/lootdrop/maintenance{lootcount = 3; name = "3maintenance loot spawner"},/turf/simulated/floor/plating,/area/maintenance/fore) "auL" = (/obj/effect/decal/cleanable/blood,/obj/structure/stool/bed/chair,/obj/item/weapon/restraints/handcuffs,/obj/effect/decal/remains/human,/obj/item/clothing/under/soviet,/turf/simulated/floor/plating,/area/maintenance/fore) @@ -1156,7 +1156,7 @@ "awl" = (/obj/machinery/newscaster/security_unit{pixel_x = 0; pixel_y = -30},/obj/structure/table,/obj/item/weapon/folder/red,/obj/item/weapon/folder/red,/obj/item/weapon/book/manual/security_space_law{pixel_x = -3; pixel_y = 5},/turf/simulated/floor/plasteel{icon_state = "showroomfloor"},/area/security/warden) "awm" = (/obj/structure/disposalpipe/segment,/obj/structure/filingcabinet/chestdrawer{pixel_y = 3},/turf/simulated/floor/plasteel{icon_state = "showroomfloor"},/area/security/warden) "awn" = (/obj/structure/table,/obj/machinery/door_control{id = "Prison Gate"; name = "Prison Wing Lockdown"; pixel_x = 0; pixel_y = 7; req_access_txt = "2"},/obj/machinery/door_control{id = "Secure Gate"; name = "Cell Window Control"; normaldoorcontrol = 0; pixel_x = -5; pixel_y = -3; req_access_txt = "0"; specialfunctions = 4},/obj/machinery/door_control{id = "briglockdown"; name = "Brig Lockdown Control"; pixel_x = 5; pixel_y = -3; req_access_txt = "0"},/turf/simulated/floor/plasteel{icon_state = "showroomfloor"},/area/security/warden) -"awo" = (/obj/effect/spawner/window/reinforced,/obj/structure/grille,/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) +"awo" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) "awp" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/table/reinforced,/obj/item/weapon/paper,/obj/machinery/door/window/brigdoor{dir = 1; name = "Brig Control Desk"; req_access_txt = "3"},/obj/machinery/door/window/westleft{base_state = "right"; dir = 2; icon_state = "right"; name = "Reception Window"; req_access_txt = "0"},/turf/simulated/floor/plasteel{icon_state = "delivery"},/area/security/warden) "awq" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass_security{name = "Brig Control"; req_access_txt = "3"},/turf/simulated/floor/plasteel{icon_state = "delivery"},/area/security/warden) "awr" = (/obj/effect/spawner/window/reinforced,/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/security/warden) @@ -1277,10 +1277,10 @@ "ayC" = (/turf/simulated/floor/plating{tag = "icon-platingdmg1"; icon_state = "platingdmg1"},/area/maintenance/fpmaint2{name = "Port Maintenance"}) "ayD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) "ayE" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) -"ayF" = (/obj/structure/grille,/obj/structure/window/reinforced/tinted{dir = 5; health = 120; icon_state = "twindow"; reinf = 0},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) -"ayG" = (/obj/structure/disposalpipe/junction{tag = "icon-pipe-j2 (NORTH)"; icon_state = "pipe-j2"; dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) -"ayH" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) -"ayI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating{tag = "icon-platingdmg3"; icon_state = "platingdmg3"},/area/maintenance/fpmaint2{name = "Port Maintenance"}) +"ayF" = (/obj/structure/grille,/obj/structure/window/reinforced/tinted{dir = 5; health = 120; icon_state = "twindow"; reinf = 0},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fore) +"ayG" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/maintenance/fore) +"ayH" = (/obj/structure/disposalpipe/junction{tag = "icon-pipe-j2 (NORTH)"; icon_state = "pipe-j2"; dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/maintenance/fore) +"ayI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating{tag = "icon-platingdmg3"; icon_state = "platingdmg3"},/area/maintenance/fore) "ayJ" = (/obj/effect/spawner/window/reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) "ayK" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/quartermaster/miningdock{name = "\improper Mining Office"}) "ayL" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/security/brig) @@ -1339,9 +1339,9 @@ "azM" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating{tag = "icon-panelscorched"; icon_state = "panelscorched"},/area/maintenance/fpmaint2{name = "Port Maintenance"}) "azN" = (/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) "azO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 4},/area/maintenance/fpmaint2{name = "Port Maintenance"}) -"azP" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock/maintenance{req_access_txt = "0"; req_one_access_txt = "12;50"},/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) -"azQ" = (/obj/structure/disposalpipe/sortjunction{dir = 1; icon_state = "pipe-j2s"; sortType = 1},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 8},/area/maintenance/fpmaint2{name = "Port Maintenance"}) -"azR" = (/obj/structure/disposalpipe/segment,/mob/living/simple_animal/mouse,/turf/simulated/floor/plating{tag = "icon-platingdmg2"; icon_state = "platingdmg2"},/area/maintenance/fpmaint2{name = "Port Maintenance"}) +"azP" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock/maintenance{req_access_txt = "0"; req_one_access_txt = "12;50"},/turf/simulated/floor/plating,/area/maintenance/fore) +"azQ" = (/obj/structure/disposalpipe/segment,/mob/living/simple_animal/mouse,/turf/simulated/floor/plating{tag = "icon-platingdmg2"; icon_state = "platingdmg2"},/area/maintenance/fore) +"azR" = (/obj/structure/disposalpipe/sortjunction{dir = 1; icon_state = "pipe-j2s"; sortType = 1},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 8},/area/maintenance/fore) "azS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) "azT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/door/airlock/mining{name = "Mining Office"; req_access_txt = "48"},/turf/simulated/floor/plasteel,/area/quartermaster/miningdock{name = "\improper Mining Office"}) "azU" = (/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/siberia) @@ -1400,8 +1400,8 @@ "aAV" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating{dir = 2; icon_state = "warnplate"},/area/maintenance/fpmaint2{name = "Port Maintenance"}) "aAW" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) "aAX" = (/obj/structure/closet/crate,/obj/item/weapon/coin/silver,/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) -"aAY" = (/obj/structure/disposalpipe/segment,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating{dir = 2; icon_state = "warnplate"},/area/maintenance/fpmaint2{name = "Port Maintenance"}) -"aAZ" = (/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) +"aAY" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/maintenance/fore) +"aAZ" = (/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/turf/simulated/floor/plating,/area/maintenance/fore) "aBa" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/maintenance/fore) "aBb" = (/turf/simulated/wall/r_wall,/area/security/nuke_storage) "aBc" = (/obj/machinery/door/airlock/shuttle{name = "Labor Shuttle Airlock"; req_access_txt = "2"},/turf/simulated/shuttle/floor{icon = 'icons/turf/floors.dmi'; icon_state = "dark"},/area/shuttle/siberia) @@ -1439,10 +1439,10 @@ "aBI" = (/turf/simulated/wall,/area/crew_quarters/locker/locker_toilet{name = "\improper Restrooms"}) "aBJ" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) "aBK" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/security/podbay) -"aBL" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) -"aBM" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock/glass{name = "Fore Primary Hallway"},/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) -"aBN" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{dir = 1; icon_state = "neutralcorner"},/area/crew_quarters/sleep) -"aBO" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4; initialize_directions = 11},/turf/simulated/floor/plasteel,/area/crew_quarters/sleep) +"aBL" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) +"aBM" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plasteel{dir = 1; icon_state = "neutralcorner"},/area/crew_quarters/sleep) +"aBN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock/glass{name = "Fore Primary Hallway"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) +"aBO" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4; initialize_directions = 11},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plasteel,/area/crew_quarters/sleep) "aBP" = (/obj/machinery/door/airlock{id_tag = "Cabin5"; name = "Cabin 3"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/crew_quarters/sleep) "aBQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/crew_quarters/sleep) "aBR" = (/obj/effect/landmark{name = "xeno_spawn"; pixel_x = -1},/obj/machinery/atmospherics/unary/vent_pump{dir = 8; on = 1},/obj/machinery/light/small,/turf/simulated/floor/wood,/area/crew_quarters/sleep) @@ -1484,7 +1484,7 @@ "aCB" = (/obj/structure/filingcabinet,/obj/item/weapon/folder/documents,/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 8},/area/security/nuke_storage) "aCC" = (/turf/simulated/shuttle/floor,/area/shuttle/siberia) "aCD" = (/obj/machinery/mineral/labor_claim_console{machinedir = 1; pixel_x = 30; pixel_y = 0},/turf/simulated/shuttle/floor,/area/shuttle/siberia) -"aCE" = (/turf/simulated/wall,/area/prison/solitary{name = "Prisoner Education Chamber"}) +"aCE" = (/obj/structure/disposalpipe/segment,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating{dir = 2; icon_state = "warnplate"},/area/maintenance/fore) "aCF" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable/yellow,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/machinery/door/poddoor/preopen{id_tag = "Secure Gate"; name = "brig shutters"},/turf/simulated/floor/plating,/area/security/brig) "aCG" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/door/window/brigdoor{dir = 1; id = "Cell 1"; name = "Cell 1"; req_access_txt = "2"},/turf/simulated/floor/plasteel{icon_state = "red"},/area/security/brig) "aCH" = (/obj/effect/spawner/window/reinforced,/obj/machinery/door/poddoor/preopen{id_tag = "Secure Gate"; name = "brig shutters"},/turf/simulated/floor/plating,/area/security/brig) @@ -2108,7 +2108,7 @@ "aOB" = (/obj/effect/spawner/window/reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/poddoor/preopen{id_tag = "lawyer_blast"; name = "privacy shutters"},/turf/simulated/floor/plating,/area/lawoffice) "aOC" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass{icon = 'icons/obj/doors/Doorminingglass.dmi'; name = "Primary Tool Storage"},/turf/simulated/floor/plasteel{dir = 2; icon_state = "brown"},/area/storage/primary) "aOD" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass{icon = 'icons/obj/doors/Doorminingglass.dmi'; name = "Primary Tool Storage"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{dir = 2; icon_state = "brown"},/area/storage/primary) -"aOE" = (/obj/structure/grille,/turf/simulated/floor/plating,/area/storage/primary) +"aOE" = (/mob/living/carbon/slime,/turf/simulated/floor/plasteel,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "aOF" = (/turf/simulated/wall/r_wall,/area/storage/primary) "aOG" = (/turf/simulated/wall/r_wall,/area/turret_protected/ai_upload) "aOH" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11},/turf/simulated/floor/plasteel{dir = 8; icon_state = "redcorner"},/area/hallway/primary/fore) @@ -2409,7 +2409,7 @@ "aUq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{req_access_txt = 1},/obj/machinery/firealarm{dir = 4; pixel_x = 24},/obj/machinery/camera{c_tag = "Fore Primary Hallway Aft"; dir = 8; network = list("SS13")},/turf/simulated/floor/plasteel{dir = 2; icon_state = "redcorner"},/area/hallway/primary/fore) "aUr" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/hallway/primary/central) "aUs" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass{name = "Courtroom"; req_access_txt = "42"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/crew_quarters/courtroom) -"aUt" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/hallway/secondary/entry) +"aUt" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{icon_state = "delivery"},/area/security/checkpoint2{name = "Customs"}) "aUu" = (/obj/structure/disposalpipe/segment,/obj/effect/spawner/window,/turf/simulated/floor/plating,/area/storage/primary) "aUv" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock{name = "Law Office"; req_access_txt = "38"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/wood,/area/lawoffice) "aUw" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/engine/chiefs_office) @@ -3284,7 +3284,7 @@ "blh" = (/obj/structure/sign/directions/security{dir = 4; pixel_y = 8},/obj/structure/sign/directions/engineering{dir = 4},/turf/simulated/wall,/area/janitor) "bli" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/engine/mechanic_workshop) "blj" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass{icon = 'icons/obj/doors/Doorengglass.dmi'; name = "Auxiliary Tool Storage"; req_access_txt = "12"},/turf/simulated/floor/plasteel,/area/storage/tools) -"blk" = (/obj/effect/spawner/window/reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/security/checkpoint2) +"blk" = (/obj/effect/spawner/window/reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/security/checkpoint2{name = "Customs"}) "bll" = (/obj/structure/closet/emcloset,/obj/structure/sign/double/map/left{icon_state = "map-left-MS"; pixel_y = 32},/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/hallway/primary/starboard) "blm" = (/obj/structure/sign/double/map/right{desc = "A framed picture of the station. Clockwise from security in red at the top, you see engineering in yellow, science in purple, escape in checkered red-and-white, medbay in green, arrivals in checkered red-and-blue, and then cargo in brown."; icon_state = "map-right-MS"; pixel_y = 32},/obj/structure/closet/firecloset,/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/hallway/primary/starboard) "bln" = (/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/maintenance/starboard) @@ -3432,7 +3432,7 @@ "bnZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/wall,/area/security/checkpoint2{name = "Customs"}) "boa" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/door/airlock/security{name = "Customs Desk"; req_access = null; req_access_txt = "1"},/turf/simulated/floor/plasteel,/area/security/checkpoint2{name = "Customs"}) "bob" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/door/poddoor/preopen{id_tag = "hop"; name = "privacy shutters"},/turf/simulated/floor/plating,/area/crew_quarters/heads) -"boc" = (/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{icon_state = "delivery"},/area/hallway/primary/port) +"boc" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating{tag = "icon-warnplate (WEST)"; icon_state = "warnplate"; dir = 8},/area/maintenance/starboard) "bod" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/door/airlock/maintenance{req_access_txt = "0"; req_one_access_txt = "12;48;50;1"},/turf/simulated/floor/plating,/area/maintenance/fpmaint2{name = "Port Maintenance"}) "boe" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/wall,/area/maintenance/fpmaint2{name = "Port Maintenance"}) "bof" = (/obj/machinery/door/window/eastleft{base_state = "right"; icon_state = "right"; name = "Deliveries"; req_access_txt = "50"},/turf/simulated/floor/plasteel{icon_state = "delivery"},/area/quartermaster/office{name = "\improper Cargo Office"}) @@ -5703,7 +5703,7 @@ "cfI" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/effect/spawner/lootdrop{loot = list(/obj/structure/grille,/obj/structure/grille,/obj/structure/grille,/obj/structure/grille,/obj/structure/grille,/obj/item/weapon/cigbutt,/obj/item/trash/cheesie,/obj/item/trash/candy,/obj/item/trash/chips,/obj/item/trash/pistachios,/obj/item/trash/plate,/obj/item/trash/popcorn,/obj/item/trash/raisins,/obj/item/trash/sosjerky,/obj/item/trash/syndi_cakes); name = "maint grille or trash spawner"},/turf/simulated/floor/plating,/area/maintenance/starboard) "cfJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/plating,/area/maintenance/starboard) "cfK" = (/turf/simulated/wall,/area/maintenance/incinerator) -"cfL" = (/obj/machinery/door/airlock/maintenance{name = "Incinerator Access"; req_access_txt = "12"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/maintenance/incinerator) +"cfL" = (/obj/machinery/door/airlock/maintenance{name = "Incinerator Access"; req_access_txt = "12;24"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/maintenance/incinerator) "cfM" = (/obj/machinery/light{dir = 8},/obj/machinery/alarm{dir = 4; pixel_x = -23; pixel_y = 0},/obj/machinery/camera{c_tag = "Atmospherics - Port-Aft"; dir = 4; network = list("SS13")},/obj/machinery/atmospherics/pipe/simple/visible/purple,/turf/simulated/floor/plasteel{dir = 8; icon_state = "caution"},/area/atmos) "cfN" = (/obj/machinery/atmospherics/unary/portables_connector{dir = 4},/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/plasteel,/area/atmos) "cfO" = (/obj/machinery/atmospherics/trinary/filter{dir = 8},/turf/simulated/floor/plasteel,/area/atmos) @@ -5995,8 +5995,8 @@ "clo" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/obj/effect/spawner/lootdrop{loot = list(/obj/structure/grille,/obj/structure/grille,/obj/structure/grille,/obj/structure/grille,/obj/structure/grille,/obj/item/weapon/cigbutt,/obj/item/trash/cheesie,/obj/item/trash/candy,/obj/item/trash/chips,/obj/item/trash/pistachios,/obj/item/trash/plate,/obj/item/trash/popcorn,/obj/item/trash/raisins,/obj/item/trash/sosjerky,/obj/item/trash/syndi_cakes); name = "maint grille or trash spawner"},/turf/simulated/floor/plating,/area/maintenance/aft{name = "Aft Maintenance"}) "clp" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating{tag = "icon-panelscorched"; icon_state = "panelscorched"},/area/maintenance/aft{name = "Aft Maintenance"}) "clq" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 4},/area/maintenance/aft{name = "Aft Maintenance"}) -"clr" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/aft{name = "Aft Maintenance"}) -"cls" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating{tag = "icon-warnplate (WEST)"; icon_state = "warnplate"; dir = 8},/area/maintenance/aft{name = "Aft Maintenance"}) +"clr" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/starboard) +"cls" = (/obj/machinery/space_heater,/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 1},/area/maintenance/starboard) "clt" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 2},/turf/simulated/floor/plating,/area/maintenance/starboard) "clu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 4},/area/maintenance/starboard) "clv" = (/obj/machinery/door/airlock/maintenance{name = "Storage Room"; req_access_txt = "12"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/maintenance/starboard) @@ -6267,11 +6267,11 @@ "cqA" = (/obj/structure/closet,/obj/item/weapon/storage/box/donkpockets,/obj/effect/spawner/lootdrop/maintenance{lootcount = 3; name = "3maintenance loot spawner"},/turf/simulated/floor/plating{icon_state = "warnplate"},/area/maintenance/aft{name = "Aft Maintenance"}) "cqB" = (/obj/structure/closet/crate,/obj/machinery/atmospherics/unary/vent_pump{dir = 2; on = 1},/obj/item/device/assembly/infra,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating{icon_state = "warnplate"},/area/maintenance/aft{name = "Aft Maintenance"}) "cqC" = (/obj/structure/table,/obj/effect/decal/cleanable/cobweb,/obj/item/weapon/shard,/turf/simulated/floor/plating,/area/maintenance/aft{name = "Aft Maintenance"}) -"cqD" = (/obj/structure/table,/obj/structure/sign/greencross{pixel_y = 32},/obj/item/weapon/reagent_containers/glass/beaker/large,/turf/simulated/floor/plating,/area/maintenance/starboard) -"cqE" = (/obj/structure/sink/kitchen{desc = "A sink used for washing one's hands and face. It looks rusty and home-made"; name = "old sink"; pixel_y = 28},/obj/effect/decal/cleanable/blood,/obj/effect/decal/cleanable/blood/gibs/limb,/turf/simulated/floor/plating,/area/maintenance/starboard) -"cqF" = (/obj/structure/table,/obj/item/weapon/storage/toolbox/emergency,/turf/simulated/floor/plating,/area/maintenance/starboard) -"cqG" = (/obj/structure/table,/obj/item/weapon/reagent_containers/food/drinks/drinkingglass{pixel_x = 4; pixel_y = 5},/obj/item/weapon/reagent_containers/food/drinks/drinkingglass{pixel_x = 6; pixel_y = -1},/obj/item/weapon/reagent_containers/food/drinks/drinkingglass{pixel_x = -4; pixel_y = 6},/obj/item/weapon/reagent_containers/dropper,/obj/item/weapon/reagent_containers/dropper,/obj/item/weapon/reagent_containers/syringe,/obj/item/weapon/reagent_containers/syringe,/turf/simulated/floor/plating,/area/maintenance/starboard) -"cqH" = (/obj/item/weapon/reagent_containers/glass/bottle/toxin{pixel_x = 4; pixel_y = 2},/obj/structure/table,/obj/effect/decal/cleanable/cobweb2,/obj/machinery/reagentgrinder{pixel_y = 4},/turf/simulated/floor/plating,/area/maintenance/starboard) +"cqD" = (/obj/structure/table,/obj/structure/sign/greencross{pixel_y = 32},/obj/item/weapon/reagent_containers/glass/beaker/large,/turf/simulated/floor/plating,/area/maintenance/aft{name = "Aft Maintenance"}) +"cqE" = (/obj/structure/table,/obj/item/weapon/storage/toolbox/emergency,/turf/simulated/floor/plating,/area/maintenance/aft{name = "Aft Maintenance"}) +"cqF" = (/obj/structure/sink/kitchen{desc = "A sink used for washing one's hands and face. It looks rusty and home-made"; name = "old sink"; pixel_y = 28},/obj/effect/decal/cleanable/blood,/obj/effect/decal/cleanable/blood/gibs/limb,/turf/simulated/floor/plating,/area/maintenance/aft{name = "Aft Maintenance"}) +"cqG" = (/obj/item/weapon/reagent_containers/glass/bottle/toxin{pixel_x = 4; pixel_y = 2},/obj/structure/table,/obj/effect/decal/cleanable/cobweb2,/obj/machinery/reagentgrinder{pixel_y = 4},/turf/simulated/floor/plating,/area/maintenance/aft{name = "Aft Maintenance"}) +"cqH" = (/obj/structure/table,/obj/item/weapon/reagent_containers/food/drinks/drinkingglass{pixel_x = 4; pixel_y = 5},/obj/item/weapon/reagent_containers/food/drinks/drinkingglass{pixel_x = 6; pixel_y = -1},/obj/item/weapon/reagent_containers/food/drinks/drinkingglass{pixel_x = -4; pixel_y = 6},/obj/item/weapon/reagent_containers/dropper,/obj/item/weapon/reagent_containers/dropper,/obj/item/weapon/reagent_containers/syringe,/obj/item/weapon/reagent_containers/syringe,/turf/simulated/floor/plating,/area/maintenance/aft{name = "Aft Maintenance"}) "cqI" = (/obj/machinery/atmospherics/binary/pump{dir = 1; on = 1},/obj/machinery/access_button{command = "cycle_interior"; master_tag = "turbine_control"; name = "Gas Turbine Airlock Control"; pixel_x = -8; pixel_y = 24},/obj/machinery/light/small{dir = 4},/obj/structure/sign/fire{pixel_x = 32},/turf/simulated/floor/engine,/area/maintenance/incinerator) "cqJ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/engine,/area/maintenance/incinerator) "cqK" = (/turf/simulated/floor/engine{name = "n2 floor"; nitrogen = 100000; oxygen = 0},/area/atmos) @@ -7938,15 +7938,15 @@ "cWH" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/stool/bed/chair/comfy/beige{dir = 4},/obj/machinery/firealarm{dir = 2; pixel_y = 24},/obj/effect/landmark/start{name = "Psychiatrist"},/turf/simulated/floor/wood,/area/medical/psych) "cWI" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light_switch{pixel_x = 0; pixel_y = 24},/turf/simulated/floor/wood,/area/medical/psych) "cWJ" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating{dir = 2; icon_state = "warnplate"},/area/maintenance/starboardsolar) -"cWK" = (/turf/space,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plating/airless/catwalk,/area/space) -"cWL" = (/turf/space,/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/turf/simulated/floor/plating/airless/catwalk,/area/space) +"cWK" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/space,/turf/simulated/floor/plating/airless/catwalk,/area/solar/starboard) +"cWL" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/turf/space,/turf/simulated/floor/plating/airless/catwalk,/area/solar/starboard) "cWM" = (/obj/machinery/door/window/eastleft{dir = 4; name = "Coffin Storage"; req_access_txt = "22"},/turf/simulated/floor/plating,/area/chapel/main) "cWN" = (/obj/structure/stool/bed/chair{pixel_y = -2},/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/chapel/main) "cWO" = (/obj/structure/stool/bed/chair{pixel_y = -2},/obj/effect/landmark/start{name = "Chaplain"},/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/chapel/main) "cWP" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "cWQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) -"cWR" = (/turf/space,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating/airless/catwalk,/area/space) -"cWS" = (/turf/space,/area/solar/starboard) +"cWR" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/space,/turf/simulated/floor/plating/airless/catwalk,/area/solar/starboard) +"cWS" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f6"; dir = 2},/area/shuttle/research) "cWT" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitebluecorner"},/area/medical/research{name = "Research Division"}) "cWU" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/plasteel{dir = 4; icon_state = "chapel"},/area/chapel/main) "cWV" = (/obj/structure/table/woodentable,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) @@ -7968,7 +7968,7 @@ "cXl" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/light{dir = 1},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitebluecorner"},/area/medical/research{name = "Research Division"}) "cXm" = (/obj/item/device/flashlight/lantern{pixel_y = 7},/obj/structure/table/woodentable,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "cXn" = (/obj/effect/landmark/start{name = "Chaplain"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) -"cXo" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f6"; dir = 2},/area/medical/research{name = "Research Division"}) +"cXo" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f10"; dir = 2},/area/shuttle/research) "cXp" = (/obj/machinery/door/airlock/external{id_tag = "emergency_home"; name = "Departure Lounge Airlock"},/turf/simulated/floor/plasteel{icon_state = "delivery"},/area/hallway/secondary/exit{name = "\improper Departure Lounge"}) "cXq" = (/obj/structure/table/glass,/obj/item/weapon/storage/box/beakers{pixel_x = 2; pixel_y = 7},/obj/item/weapon/storage/box/syringes{pixel_y = 5},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitepurplefull"; tag = "icon-whitehall (WEST)"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cXr" = (/obj/machinery/alarm{frequency = 1439; pixel_y = 23},/obj/structure/table/glass,/obj/item/stack/sheet/mineral/plasma{layer = 2.9; pixel_y = 4},/obj/item/stack/sheet/mineral/plasma{layer = 2.9; pixel_y = 4},/obj/item/stack/sheet/mineral/plasma{layer = 2.9; pixel_y = 4},/obj/item/stack/sheet/mineral/plasma{layer = 2.9; pixel_y = 4},/obj/item/weapon/reagent_containers/glass/beaker{pixel_x = 8; pixel_y = 2},/obj/item/weapon/reagent_containers/glass/beaker/large{pixel_x = -3; pixel_y = 3},/obj/item/weapon/reagent_containers/dropper,/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitepurplefull"; tag = "icon-whitehall (WEST)"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) @@ -7983,11 +7983,11 @@ "cXA" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/medical/research{name = "Research Division"}) "cXB" = (/turf/simulated/shuttle/wall{icon_state = "swall12"; dir = 2},/area/shuttle/research) "cXC" = (/obj/structure/grille,/obj/structure/window/full/shuttle,/turf/simulated/shuttle/plating,/area/shuttle/research) -"cXD" = (/obj/structure/grille,/obj/structure/window/full/shuttle,/turf/simulated/shuttle/plating,/area/space) +"cXD" = (/obj/structure/closet/crate,/turf/simulated/shuttle/floor,/area/shuttle/research) "cXE" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "cXF" = (/obj/machinery/door/window{dir = 4; name = "Mass Driver"; req_access_txt = "22"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "cXG" = (/obj/machinery/mass_driver{dir = 2; id_tag = "chapelgun"},/obj/structure/sign/securearea{desc = "A warning sign which reads 'EXTERNAL AIRLOCK'"; icon_state = "space"; layer = 4; name = "EXTERNAL AIRLOCK"; pixel_x = 0; pixel_y = 32},/obj/machinery/light/small{dir = 1},/obj/item/device/gps,/turf/simulated/floor/plating{tag = "icon-warnplate (NORTH)"; icon_state = "warnplate"; dir = 1},/area/chapel/main) -"cXH" = (/turf/simulated/shuttle/wall{icon_state = "swall12"; dir = 2},/area/space) +"cXH" = (/obj/machinery/light{dir = 1},/turf/simulated/shuttle/floor,/area/shuttle/research) "cXI" = (/obj/machinery/light/small,/turf/simulated/floor/plasteel{dir = 4; icon_state = "chapel"},/area/chapel/main) "cXJ" = (/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/chapel/main) "cXK" = (/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/chapel/main) @@ -8006,7 +8006,7 @@ "cXX" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitepurple"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cXY" = (/turf/simulated/floor/plasteel{dir = 5; icon_state = "whitepurple"; tag = "icon-whitehall (WEST)"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cXZ" = (/turf/simulated/shuttle/wall{icon_state = "swall3"; dir = 2},/area/shuttle/research) -"cYa" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f10"; dir = 2},/area/space) +"cYa" = (/obj/structure/shuttle/engine/propulsion/burst{dir = 4},/turf/space,/area/shuttle/research) "cYb" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor,/area/shuttle/research) "cYc" = (/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitebluecorner"},/area/medical/research{name = "Research Division"}) "cYd" = (/turf/simulated/shuttle/floor,/area/shuttle/research) @@ -8029,18 +8029,18 @@ "cYu" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cYv" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 0; scrub_Toxins = 0},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cYw" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitepurple"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) -"cYx" = (/turf/simulated/shuttle/wall{icon_state = "swall3"; dir = 2},/area/medical/research{name = "Research Division"}) +"cYx" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/shuttle/engine/heater{dir = 8},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/simulated/floor/plating/airless,/area/shuttle/research) "cYy" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/medical/research{name = "Research Division"}) -"cYz" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor,/area/space) +"cYz" = (/obj/machinery/computer/shuttle/science,/turf/simulated/shuttle/floor,/area/shuttle/research) "cYA" = (/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/power/solar{id = "aftstarboard"; name = "Aft-Starboard Solar Array"},/turf/simulated/floor/plating/airless{icon_state = "solarpanel"},/area/solar/starboard) "cYB" = (/turf/simulated/floor/plating/airless/catwalk,/area/solar/starboard) "cYC" = (/obj/machinery/door/poddoor{id_tag = "chapelgun"; name = "Chapel Launcher Door"; protected = 0},/turf/simulated/floor/plating,/area/chapel/main) "cYD" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_f6"; icon_state = "swall_f6"; dir = 2},/area/shuttle/escape) "cYE" = (/turf/simulated/shuttle/wall{tag = "icon-swall12"; icon_state = "swall12"; dir = 2},/area/shuttle/escape) "cYF" = (/obj/structure/grille,/obj/structure/shuttle/window,/turf/simulated/shuttle/plating,/area/shuttle/escape) -"cYG" = (/obj/structure/closet/crate,/turf/simulated/shuttle/floor,/area/space) +"cYG" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f5"; dir = 2},/area/shuttle/research) "cYH" = (/turf/simulated/shuttle/wall{tag = "icon-swall14"; icon_state = "swall14"; dir = 2},/area/shuttle/escape) -"cYI" = (/turf/simulated/shuttle/floor,/area/space) +"cYI" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_closed"; id_tag = "research_dock_outer"; locked = 0; name = "Shuttle Airlock"; req_access_txt = "13"},/turf/simulated/floor/plating,/area/medical/research{name = "Research Division"}) "cYJ" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_f10"; icon_state = "swall_f10"; dir = 2},/area/shuttle/escape) "cYK" = (/obj/machinery/atmospherics/unary/portables_connector{dir = 1; name = "xenobiology air connector port"},/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/plasteel{tag = "icon-whitepurple (SOUTHWEST)"; icon_state = "whitepurple"; dir = 10},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cYL" = (/obj/structure/reagent_dispensers/watertank,/obj/item/weapon/extinguisher{pixel_x = 4; pixel_y = 3},/obj/item/weapon/extinguisher,/turf/simulated/floor/plasteel{dir = 2; icon_state = "whitepurple"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) @@ -8063,17 +8063,15 @@ "cZc" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plating/airless/catwalk,/area/solar/starboard) "cZd" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/turf/simulated/floor/plating/airless/catwalk,/area/solar/starboard) "cZe" = (/turf/simulated/shuttle/wall{tag = "icon-swall3"; icon_state = "swall3"; dir = 2},/area/shuttle/escape) -"cZf" = (/obj/machinery/light{dir = 1},/turf/simulated/shuttle/floor,/area/space) +"cZf" = (/turf/simulated/floor/plasteel{dir = 9; icon_state = "warning"},/area/medical/research{name = "Research Division"}) "cZg" = (/obj/structure/dispenser/oxygen{layer = 2.7; pixel_x = -1; pixel_y = 2},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) -"cZh" = (/turf/simulated/shuttle/wall{icon_state = "swall3"; dir = 2},/area/space) -"cZi" = (/obj/structure/table,/turf/simulated/shuttle/floor,/area/space) +"cZh" = (/turf/simulated/floor/plasteel{dir = 5; icon_state = "warning"},/area/medical/research{name = "Research Division"}) +"cZi" = (/turf/simulated/floor/plasteel{dir = 10; icon_state = "warning"},/area/medical/research{name = "Research Division"}) "cZj" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor/plating/airless/catwalk,/area/solar/starboard) "cZk" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall,/area/chapel/main) "cZl" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 2; initialize_directions = 11},/obj/item/weapon/twohanded/required/kirbyplants{icon_state = "plant-24"; layer = 4.1; tag = "icon-plant-24"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "cZm" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/stool/bed/chair/comfy/black{dir = 4},/turf/simulated/floor/plasteel{dir = 1; icon_state = "chapel"},/area/chapel/main) -"cZn" = (/obj/structure/shuttle/engine/propulsion/burst{dir = 4},/turf/space,/area/medical/research{name = "Research Division"}) -"cZo" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/shuttle/engine/heater{dir = 8},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/simulated/floor/plating/airless,/area/space) -"cZp" = (/obj/machinery/computer/shuttle/science,/turf/simulated/shuttle/floor,/area/space) +"cZn" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plasteel{dir = 6; icon_state = "warning"},/area/medical/research{name = "Research Division"}) "cZq" = (/obj/structure/table,/obj/item/weapon/clipboard,/obj/item/weapon/folder/yellow,/obj/item/weapon/pen,/turf/simulated/shuttle/plating{icon_state = "bot"},/area/shuttle/escape) "cZr" = (/turf/simulated/wall,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cZs" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/firedoor,/turf/simulated/floor/plasteel{icon_state = "delivery"; name = "floor"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) @@ -8089,7 +8087,6 @@ "cZC" = (/obj/item/device/radio/intercom{frequency = 1459; name = "Station Intercom (General)"; pixel_x = 29},/turf/simulated/floor/plasteel{icon_state = "chapel"},/area/chapel/main) "cZD" = (/turf/simulated/shuttle/plating{dir = 1; icon_state = "delivery"},/area/shuttle/escape) "cZE" = (/turf/simulated/shuttle/plating{icon_state = "floorgrime"},/area/shuttle/escape) -"cZF" = (/turf/space,/area/shuttle/research) "cZG" = (/obj/structure/disposalpipe/trunk{dir = 4},/obj/structure/disposaloutlet,/turf/simulated/floor/plasteel,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cZH" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cZI" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable/yellow,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/door/poddoor/preopen{id_tag = "xenobio2"; name = "containment blast door"},/turf/simulated/floor/plating,/area/toxins/xenobiology{name = "\improper Secure Lab"}) @@ -8102,10 +8099,8 @@ "cZP" = (/turf/simulated/floor/plasteel,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cZQ" = (/obj/structure/bookcase{name = "Holy Bookcase"},/turf/simulated/floor/plasteel{dir = 4; icon_state = "chapel"},/area/chapel/main) "cZR" = (/obj/structure/stool/bed/chair/comfy/black{dir = 8},/turf/simulated/floor/plasteel{dir = 4; icon_state = "chapel"},/area/chapel/main) -"cZS" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f5"; dir = 2},/area/medical/research{name = "Research Division"}) "cZT" = (/obj/structure/lattice,/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/hallway/secondary/exit{name = "\improper Departure Lounge"}) "cZU" = (/obj/structure/lattice,/obj/machinery/door/airlock/external{id_tag = "emergency_home"; name = "Departure Lounge Airlock"},/turf/simulated/floor/plasteel{icon_state = "delivery"},/area/hallway/secondary/exit{name = "\improper Departure Lounge"}) -"cZV" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/shuttle/research) "cZW" = (/obj/structure/closet/crate/medical{name = "medical crate"},/obj/item/weapon/storage/firstaid/regular,/obj/item/weapon/storage/firstaid/o2{pixel_x = 3; pixel_y = 3},/obj/item/weapon/storage/firstaid/toxin{pixel_x = -4; pixel_y = 3},/obj/item/device/healthanalyzer{pixel_x = 3; pixel_y = 3},/obj/item/weapon/lazarus_injector,/mob/living/simple_animal/bot/medbot{name = "\improper emergency medibot"; pixel_x = -3; pixel_y = 2},/turf/simulated/shuttle/plating{icon_state = "bot"},/area/shuttle/escape) "cZX" = (/obj/machinery/door/window/northleft{base_state = "right"; dir = 8; icon_state = "right"; name = "Containment Pen #1"; req_access_txt = "55"},/obj/machinery/door/poddoor/preopen{id_tag = "xenobio3"; name = "containment blast door"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plasteel,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "cZY" = (/obj/machinery/door/window/northleft{dir = 4; name = "Containment Pen #1"; req_access_txt = "55"},/turf/simulated/floor/plasteel{dir = 4; icon_state = "warning"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) @@ -8114,16 +8109,13 @@ "dab" = (/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "dac" = (/obj/machinery/door/window/northleft{base_state = "right"; dir = 8; icon_state = "right"; name = "Containment Pen #2"; req_access_txt = "55"},/turf/simulated/floor/plasteel{dir = 8; icon_state = "warning"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "dad" = (/obj/machinery/door/window/northleft{dir = 4; name = "Containment Pen #2"; req_access_txt = "55"},/obj/machinery/door/poddoor/preopen{id_tag = "xenobio8"; name = "containment blast door"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plasteel,/area/toxins/xenobiology{name = "\improper Secure Lab"}) -"dae" = (/turf/simulated/wall,/area/shuttle/research) "daf" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitebluecorner"},/area/medical/research{name = "Research Division"}) -"dag" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_closed"; id_tag = "research_dock_outer"; locked = 0; name = "Shuttle Airlock"; req_access_txt = "13"},/turf/simulated/floor/plating,/area/shuttle/research) "dah" = (/turf/simulated/shuttle/wall{icon_state = "swallc2"; dir = 2},/area/shuttle/escape) "dai" = (/turf/simulated/shuttle/wall{icon_state = "swall0"; dir = 2},/area/shuttle/escape) "daj" = (/obj/structure/sign/nosmoking_2,/turf/simulated/shuttle/wall{icon_state = "swall0"; dir = 2},/area/shuttle/escape) "dak" = (/obj/docking_port/mobile/emergency{dir = 2; dwidth = 5; height = 14; width = 25},/obj/docking_port/stationary{dir = 2; dwidth = 5; height = 14; id = "emergency_home"; name = "emergency evac bay"; width = 25},/obj/machinery/door/airlock/shuttle{id_tag = "s_docking_airlock"; name = "Emergency Shuttle Airlock"; req_access_txt = "2"},/turf/simulated/shuttle/floor,/area/shuttle/escape) "dal" = (/turf/simulated/shuttle/wall{icon_state = "swall4"; dir = 2},/area/shuttle/escape) "dam" = (/obj/structure/closet/crate{name = "emergency supplies crate"},/obj/item/weapon/storage/toolbox/emergency,/obj/item/weapon/storage/toolbox/emergency,/obj/item/device/flashlight/flare{pixel_x = 3; pixel_y = 3},/obj/item/device/flashlight/flare{pixel_x = -6; pixel_y = -2},/obj/item/weapon/crowbar,/obj/item/weapon/wrench,/obj/item/device/radio,/turf/simulated/shuttle/plating{icon_state = "bot"},/area/shuttle/escape) -"dan" = (/mob/living/simple_animal/slime,/turf/simulated/floor/plasteel,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "dao" = (/obj/effect/spawner/window/reinforced,/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/door/poddoor/preopen{id_tag = "xenobio1"; name = "containment blast door"},/turf/simulated/floor/plating,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "dap" = (/obj/structure/table/reinforced,/obj/machinery/door_control{id = "xenobio3"; name = "Containment Blast Doors"; pixel_x = 0; pixel_y = 4; req_access_txt = "55"},/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plasteel{dir = 5; icon_state = "warning"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "daq" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{dir = 1; icon_state = "warnwhitecorner"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) @@ -8133,8 +8125,6 @@ "dau" = (/obj/effect/spawner/window/reinforced,/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/obj/machinery/door/poddoor/preopen{id_tag = "xenobio6"; name = "containment blast door"},/turf/simulated/floor/plating,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "dav" = (/obj/structure/disposalpipe/trunk{dir = 8},/obj/structure/disposaloutlet{dir = 1},/turf/simulated/floor/plasteel,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "daw" = (/obj/machinery/computer/shuttle/science,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/research{name = "Research Division"}) -"dax" = (/turf/simulated/floor/plasteel{dir = 9; icon_state = "warning"},/area/shuttle/research) -"day" = (/turf/simulated/floor/plasteel{dir = 5; icon_state = "warning"},/area/shuttle/research) "daz" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_f6"; icon_state = "swall_f6"; dir = 2},/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/escape) "daA" = (/obj/structure/table,/obj/item/weapon/phone{pixel_x = -3; pixel_y = 3},/obj/item/weapon/cigbutt/cigarbutt{pixel_x = 5; pixel_y = -1},/turf/simulated/shuttle/floor,/area/shuttle/escape) "daB" = (/obj/structure/table,/obj/item/weapon/storage/firstaid/regular,/turf/simulated/shuttle/floor,/area/shuttle/escape) @@ -8149,9 +8139,7 @@ "daK" = (/obj/structure/closet/crate{name = "lifejackets"},/obj/item/clothing/suit/storage/hazardvest,/obj/item/clothing/suit/storage/hazardvest,/obj/item/clothing/suit/storage/hazardvest,/obj/item/clothing/suit/storage/hazardvest,/obj/item/clothing/suit/storage/hazardvest,/obj/item/weapon/tank/emergency_oxygen/engi,/obj/item/weapon/tank/emergency_oxygen/engi,/obj/item/weapon/tank/emergency_oxygen/engi,/obj/item/weapon/tank/emergency_oxygen/engi,/obj/item/weapon/tank/emergency_oxygen/engi,/obj/item/clothing/mask/breath{pixel_x = -5; pixel_y = -2},/obj/item/clothing/mask/breath{pixel_x = -5; pixel_y = -2},/obj/item/clothing/mask/breath{pixel_x = -5; pixel_y = -2},/obj/item/clothing/mask/breath{pixel_x = -5; pixel_y = -2},/obj/item/clothing/mask/breath{pixel_x = -5; pixel_y = -2},/obj/item/clothing/head/hardhat,/obj/item/clothing/head/hardhat,/obj/item/clothing/head/hardhat,/obj/item/clothing/head/hardhat,/obj/item/clothing/head/hardhat,/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "daL" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = -32; pixel_y = 0},/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitebluecorner"},/area/medical/research{name = "Research Division"}) "daM" = (/obj/structure/closet/emcloset,/obj/item/clothing/mask/breath,/obj/item/clothing/mask/breath,/obj/item/weapon/tank/emergency_oxygen,/obj/item/weapon/tank/emergency_oxygen,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/research{name = "Research Division"}) -"daN" = (/turf/simulated/floor/plasteel{dir = 10; icon_state = "warning"},/area/shuttle/research) "daO" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_closed"; id_tag = "research_dock_inner"; locked = 0; name = "Shuttle Airlock"; req_access_txt = "13"},/turf/simulated/floor/plating,/area/medical/research{name = "Research Division"}) -"daP" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plasteel{dir = 6; icon_state = "warning"},/area/shuttle/research) "daQ" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/structure/cable/yellow,/obj/machinery/door/poddoor/preopen{id_tag = "xenobio1"; name = "containment blast door"},/turf/simulated/floor/plating,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "daR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{dir = 4; icon_state = "warnwhitecorner"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "daS" = (/turf/simulated/floor/plasteel{tag = "icon-warnwhitecorner (WEST)"; icon_state = "warnwhitecorner"; dir = 8},/area/toxins/xenobiology{name = "\improper Secure Lab"}) @@ -8194,7 +8182,6 @@ "dbD" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/turf/simulated/floor/plasteel,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "dbE" = (/obj/docking_port/stationary{dheight = 9; dir = 2; dwidth = 5; height = 22; id = "syndicate_se"; name = "southeast of station"; width = 18},/turf/space,/area/space) "dbF" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/research{name = "Research Division"}) -"dbG" = (/turf/space,/area/medical/research{name = "Research Division"}) "dbH" = (/obj/machinery/door/window/northleft{base_state = "right"; dir = 8; icon_state = "right"; name = "Containment Pen #5"; req_access_txt = "55"},/obj/machinery/door/poddoor/preopen{id_tag = "xenobio1"; name = "containment blast door"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plasteel,/area/toxins/xenobiology{name = "\improper Secure Lab"}) "dbI" = (/obj/machinery/door/window/northleft{dir = 4; name = "Containment Pen #5"; req_access_txt = "55"},/turf/simulated/floor/plasteel{dir = 4; icon_state = "warning"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) "dbJ" = (/obj/structure/disposalpipe/segment,/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/landmark/start{name = "Scientist"},/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology{name = "\improper Secure Lab"}) @@ -8564,27 +8551,27 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqaktaktakIakIakIakIakIajBakvakwakxajBabqabqabqabqabqaaaaaaacgacgaiNacgacgacgaiNacgacgakAakBakCakDakEakFakGakHakHakHagBagBagBakOakJakKakLakMakNakRagBabqagCakPakQakTakSalAakUakVagCdeOdeNajdakdajfaheakWajgakXakYakZalaafbalbakhakialcaldaldaldaleakmalfalgalhairairairairairalialjalkaeNaaaabqabqabqabqabqabqabfabqabqabqabqabqaaaaaaadFaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaflallallafgaaaaaaaehalmaeGaeGaeGalnaehaaaaaaaflallallafgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaloalpakIalqalralsaltajBalualvalwajBakyalLakyakyabqabqaaaaaaaaaabqaaaaaaaaaabqabqalMalBalCalBalDalEalFalGakHalHalIalJagBagBagBalKalNagBagBalOagBagBalPagCagCalQamualRamzamwagCagCatzdePalTalUalVaheajgajgalWalWalXalYafbalZakhamaambamcamcamdameamfamgamhaeNairairairairairaeNamiamjaeNaaaabqaaaabqaaaamkamkamkamkamkamkamkabqabqabqadFabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaehamlaeGaeGaeGalnaehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqaktammaktamnamoampamqajBajBamramsajBalxalyalzakyakyabqabqabqabqabqabqabqabqaaaaaaamxakDakDakDakDamyamEamAakHamBamCamDagBamFamIamGamHamKamJanYanFagBamMamNamOamPamQamRamSamTamOamUdeRdePamWamXamYaheamZalWalWanaanLajgafbanbancandaneanfanfangameamjanhamhaeNairairairairairaeNanianjaeNabqabqabqabqabqamkankanlanmannankamkabqaaaanoanpanoansaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaehantanuaglantanuaehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaakIanvanwanxanyanzanAanBanCanDanEakyamtanGamvanIakyabqaaaaaaabqaaaaaaaaaajgakDakDamxaouanKanSanManNanOanPakHanQamCanRagBanTanWanUanVanZanXanYaonaoaaobaocaodaoeaofaogaohaoiaojaokdeUaoHaoLaooaopaheaoqaoraosapiapQajgapRaowakhaoxambaoyamcaozameaoAamgaoBaoCairairairairairaoDaoEaoFaoGapeaoGaaaabqaaaamkaoIaoJankaoJaoKamkabqaaaapgaoMapgasTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaehaoOaoPaeGaoQaoRaehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaktaoSaktaoTaoUaoVaoWaktaoXaoYaoZapaapbapcapdaphakyabqapfapfalLapfapfaaaajgapSapSamxaqaaqHapjapkaplapmapnapoappapqappaprapsapsaptapuapvapwapxapxapyapzapAapBapCapDapEapFapGapHapIdeYdeXapLapMapNaheapOapPalWarMarOajgaipaowakhajpapTapUapVapWapXapYamgapZaqDairairairairairaqbafbaqcaoGaqdaqeaefaefabqamkaqfaqgaqhaqiaqjamkabqanoapgaqkapgansaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaehaqmaqnaeGaqoaqpaehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqaktaqqaqraqraqraqsaqtaktaquaqvaqwakyaqxaqyaqzaqAakyapfapfaqBaqCanEapfajgajgaqFaqEamxaqGarSaqTaqIaqJaqKaqLakHaqMaqNaqOagBaqPaqQaqRaxfaqYaqUaqVaqWakHaqXdfnaqZapCaraarbarcardarearfargalSalSarhaheaheajgariajgarjajgajgafbarkarlajpajparmarnaroarparparqapZaqDairairairairairaqbarrarsaoGaqeaoGaoGapeaoGamkartaruankarvarwamkabqapgapgaoMapgansaoGaoGaoGafdacJaaaaaaaaaaaaaaaaaaaaaaaaaaaaflaeFarxaryarzaeFafgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarAarBaaaaaaarAaaaarAaaaaaaabqabqabqaaaaaaaaaaaaaaaabqaaaabqaaaabqaaaaktarCarDarEarFarGarHaktanHaqvapdapfarIapdapdapdarJapfarKarUarTarNapfatAarWarParRaumazcaCTarVaCVarXarYarZagBamKasaamKagBagBamKascamKagBarQaseasfasdashdfnasiapCapCaslasmasnasoarfaspasqasrassastasuastasvaswasxasyaszaszasAasBasCasCasDasEasFasGasGasGasHaqDairairairairairaqbasIasJaoGarsasKasLasMasNamkasjasgasQasOasPamkabqansasUasVasWaoGauodgCblyavNavNblzaaaaaaaaaaaaaaaaaaaaaaaaaaaaflaeFaeFaeFafgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarAarAabqabqarAarAarAabqaaaarAarAataarAarAaaaabqapfapfalLapfabqaaaabqabqabqabqabqapfalLaktaktatbatcatdaktaktaktaoXateaoZatfapbatgathapdatiapfaoXaElaEjapfapfatlatmatnatoamxamxamxakDakDatpatqatrasSasRatuatsatvattatwazxatxagBatHanYatJakHatBdfnatCatDatEatFatGauHatIarfauOatKatKamOamOamOamOatLafbaeNatMaeNafbatNatOatPatQatRatSatTatUatVatWatXatYatZatZatZatZatZauaaubayuaoGasJasJasJasJaudamkaueaufaugauhavFamkabqansaujaukaulaoGdgCdgCbnGblAbvublBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarBaupabqarAabqaupabqarAarAabqarAarAarAarAarAaaaaaaaaaapfauqaurapfautausausausausausauuapfarKauvapfauwauxaoXauyauzapfauAauBauCapfarIatjauDauEauFapfauGaNEaFEapfauIatmakeauJauKajgauLamxauMauNaqJatqapnauQauPauTauRauSauSauUauVauWauXaqUauYamLakHdfsdfravcauZaveavfaveavhaveaviavjavkavlavlavmavnamOatLafbavoavpavqavravravravravravsavtavuavvavvavvavvavvavwaoGavxavyavzaoGaoGasJaoGavAawMavCasJavDavEavHavGawZavIavJamkapeansavKavLavMaoGdgCdgCbnFavNavNbnHaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaakIanvanwanxanyanzanAanBanCanDanEakyamtanGamvanIakyabqaaaaaaabqaaaaaaaaaakDakDakDamxaouanKanSanManNanOanPakHanQamCanRagBanTanWanUanVanZanXanYaonaoaaobaocaodaoeaofaogaohaoiaojaokdeUaoHaoLaooaopaheaoqaoraosapiapQajgapRaowakhaoxambaoyamcaozameaoAamgaoBaoCairairairairairaoDaoEaoFaoGapeaoGaaaabqaaaamkaoIaoJankaoJaoKamkabqaaaapgaoMapgasTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaehaoOaoPaeGaoQaoRaehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaktaoSaktaoTaoUaoVaoWaktaoXaoYaoZapaapbapcapdaphakyabqapfapfalLapfapfaaaakDapSapSamxaqaaqHapjapkaplapmapnapoappapqappaprapsapsaptapuapvapwapxapxapyapzapAapBapCapDapEapFapGapHapIdeYdeXapLapMapNaheapOapPalWarMarOajgaipaowakhajpapTapUapVapWapXapYamgapZaqDairairairairairaqbafbaqcaoGaqdaqeaefaefabqamkaqfaqgaqhaqiaqjamkabqanoapgaqkapgansaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaehaqmaqnaeGaqoaqpaehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqaktaqqaqraqraqraqsaqtaktaquaqvaqwakyaqxaqyaqzaqAakyapfapfaqBaqCanEajgajgakDaqFaqEamxaqGarSaqTaqIaqJaqKaqLakHaqMaqNaqOagBaqPaqQaqRaxfaqYaqUaqVaqWakHaqXdfnaqZapCaraarbarcardarearfargalSalSarhaheaheajgariajgarjajgajgafbarkarlajpajparmarnaroarparparqapZaqDairairairairairaqbarrarsaoGaqeaoGaoGapeaoGamkartaruankarvarwamkabqapgapgaoMapgansaoGaoGaoGafdacJaaaaaaaaaaaaaaaaaaaaaaaaaaaaflaeFarxaryarzaeFafgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarAarBaaaaaaarAaaaarAaaaaaaabqabqabqaaaaaaaaaaaaaaaabqaaaabqaaaabqaaaaktarCarDarEarFarGarHaktanHaqvapdapfarIapdapdapdarJapfarKarUarTarNajgatAarWarParRaumazcaCTarVaCVarXarYarZagBamKasaamKagBagBamKascamKagBarQaseasfasdashdfnasiapCapCaslasmasnasoarfaspasqasrassastasuastasvaswasxasyaszaszasAasBasCasCasDasEasFasGasGasGasHaqDairairairairairaqbasIasJaoGarsasKasLasMasNamkasjasgasQasOasPamkabqansasUasVasWaoGauodgCblyavNavNblzaaaaaaaaaaaaaaaaaaaaaaaaaaaaflaeFaeFaeFafgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarAarAabqabqarAarAarAabqaaaarAarAataarAarAaaaabqapfapfalLapfabqaaaabqabqabqabqabqapfalLaktaktatbatcatdaktaktaktaoXateaoZatfapbatgathapdatiapfaoXaElaEjajgajgatlatmatnatoamxamxamxakDakDatpatqatrasSasRatuatsatvattatwazxatxagBatHanYatJakHatBdfnatCatDatEatFatGauHatIarfauOatKatKamOamOamOamOatLafbaeNatMaeNafbatNatOatPatQatRatSatTatUatVatWatXatYatZatZatZatZatZauaaubayuaoGasJasJasJasJaudamkaueaufaugauhavFamkabqansaujaukaulaoGdgCdgCbnGblAbvublBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarBaupabqarAabqaupabqarAarAabqarAarAarAarAarAaaaaaaaaaapfauqaurapfautausausausausausauuapfarKauvapfauwauxaoXauyauzapfauAauBauCapfarIatjauDauEauFapfauGaNEaFEajgauIatmakeauJauKajgauLamxauMauNaqJatqapnauQauPauTauRauSauSauUauVauWauXaqUauYamLakHdfsdfravcauZaveavfaveavhaveaviavjavkavlavlavmavnamOatLafbavoavpavqavravravravravravsavtavuavvavvavvavvavvavwaoGavxavyavzaoGaoGasJaoGavAawMavCasJavDavEavHavGawZavIavJamkapeansavKavLavMaoGdgCdgCbnFavNavNbnHaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarAabqarAabqarAarAarAataabqabqabqarAarAabqaaaabqabqalLavQavRavSavTavUavUavUavUavUavVavWavXavYavZawaawbavUawcbflavUaweawfajgajgajgajgajgajgajgajgajgajgawgajgawhajgajgajgajgajgajgamxawiawjaqJatqatrasSavdawdavgawlawkawmaqUawnaqYawsawtawuasdawvdfvdfwawyawzawAawBawCawDawEawFatKawGawHawGawIamOawJawKawLaxjavqavrawNawOawPawoawRawSawTavvawUawVawWavvaoGaoGasJaubavBasIaoGayvaoGavzasJawXasJaoGawYayqamkamkaxaaxbamkayxansansaxdaxeaoGaoGbnIaxhbnJbplaaaaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarAarAarAarAarAabqarAarAabqauparAarAabqabqabqabqapfapfaxiapfapfaxlaxkaxkaxkaxkaxkaxZapfapfapfapfaxmaxnaxoaxoaxoaxoaxpaxqajgaxraxsaxtaxuaxvaxwaxxaxyaxzaxAaxBaxCajgaxDaxEaxEaxEaxFamEaxGaxHaqJaxIaxJaxKaqYawpagBagBagBawrawqasdagBaxPawQakHakHamOaxLaxRaxSaxLamOaxNaxMamOaxOatKatKaxWaxWaxWamOamOaxXafbdeeaAAdefavrayaaybayaawoaycaydayeayfaygayhayiavvayjaoGaykaylaymaynaoGasMaoGaoGaoGayoaoGaoGaypbppayramkamkamkamkazrasIazGazFbTiaoGdfCdgCdfEaoGaoGaoGabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarBabqarAarAarAarAarAarAarAarAarAarAarAayyarAabqaupapfapfapfayzayAapfabqabqabqabqabqabqabqabqabqabqabqapfaqBayBapdaoXayCaoXayDayEayFayGayHayIajgajgajgaxTaxQaxQaxQaxUajgajgayMayNayOayPayMamEamEakDayQayRapnaySaySayTayUaySaySayVayUaySayWaySayVayXayYayZayUazaazbaySaySaySayUaySaOPamxazdazeazeazeazeakDatLafbaxYaWvavqavrazfazgazhavraziazjazkazlazmavvavvavvaznaoGasIazoawXasJaoGayvaoGazpaoGazqdfFazsbpmdfobpobqVbpqbqXbqWbqWbqWbqWdeSdgCdeVdgCdgCdgCaxgazHaxgaWwaWwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaupabqarAataarAarAarAarAazIabqarAarAarAarAarAarAazJazKazJazLazMapfapfabqaaaaaaaaaaaaaaaaaaaaaaaaabqapfapfapfathaoXapdaoXazNazOazPazQazRazSajgaaaabqaaaaaaaaaaaaaaaabqaaaaxEazUazVazWazXazYazeazZaAaaAbaAcaAdaAdaAeaAcaAdaAdaxVaAcaAhaAiaAdaAjaAkaAlaAdaAmaAnaAoaApaApaAqaAraAsaAtaAuaAvaAwaAxaAyaAzakDatLafbaxYaWxavqavraABaACaADayJaAFaAGaAHavvaAIaAJaAKavvaALaoGaoGaoGayoaoGaoGasJaoGaucaoGaAMaxhaxhawYaANamkaxhaxhaxhaxhaxhaxhaxhaxhaxhayxaxhaxhaxhaxhaxhaAOaxhabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarAarAarAarAarAarAarAarAarAarAarAabqarAarAarAabqapfapfapfaAPazSapdapfaaaaAQaARaASaARaATabqabqabqabqapfaAUapfaAVavUavUavUaAWaAXapfaAYaAZaBaajgaaaaBbaBbaBbaBbaBbaBbaBbaaaayMaBcaBdaBeayMamEamEakDaBfaBgaBhaBiaBjaBkaBhaBlaBjaBgaBmaBnaBoaBpaBqaBraBsaBtaBuaBvaBwaBxaByaBwaBzaBAaBBaBCaBDaBEaBFaBGaBHakDatLaBIaBIaBIaBIavraBJaPWaBLaBMaBNaBOayeaBPaBQaBRaBSavvaBTaBUaBVaBWaBXaBWaBYaBWaBZaBWdgEaCaaCbaCcaCdaCeaCfaCgaChaCgaCiaCjaCkaCjaClaxhaxhaxhaCiaCjaClaCmaCmaCgabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqabqabqarAarAarAarAarAarAarAaCnarAabqabqabqabqapfaoXazSarIalLaaaaCoaCpaCqaCpaCoayKayKayKaCsaCsaCsaCsaCtaCsaCsaCuaCuaCuaCuaCvaCuaCwajgabqaBbaCxaCyaCzaCAaCBaBbaaaayMaCCaCCaCDayMaaaaaaaCEayLaCGazwakDayLaCIazwakDayLaCJazwakDaCKamEaCLakDamEazzaCNamEamEaCOaCOaCPaCQaCRaCOaCOaCSakDakDakDakDakDatLaBIaQdaCUaQvavravravravravraCWaCXaCYazlazmavvavvavvaoGaCZasIarrasJasIaDadgIaxhaxhaxhaxhaxhaDbaDcaDdaDeaDfaWyaDfaDhaDiaDjaWzaDkaCjaDlaCjaDmaWzaDjaDiaCmaDnaDoabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarBabqabqabqarAarAarAarAataarAarAarAaDparAarAarAarAabqaaaabqalLayBazSaqwapfaaaaASaDqaDraDqaASayKaDsaDtaCsaDuaDvaDwaDxaDyaCsaDzaDAaDBaDCaDDaCuaCwajgaaaaBbaDEaDFaDGaDHaDIaBbaaaaxEaDJaCCaDKayMaAfaAfacAaDMaDNaDOakDaDPaDNaDOakDaDQaDNaDOakDaDRaDSaDTakDaDUaDVaDWaDXaDYaCOaDZaEaaEbaEcaEdaEeaCSaEfaEgaEgaEhaEgaEiaBIaRtaEkaRyaBIaEmaEnaEmavvaEoaEpaEqaEraEsaEtaEuaEvaBWaEwaxhaxhaxhaxhaxhaxhaxhaExaExaEyaEzaEAaEBaECaEDaCgaCgaCgabqabqaEEaEFaDiaDiaDiaDiaDiaEGaEEaDiaEHaCgaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqarAarAarAarAarAarAarAabqarAabqabqarAarAabqabqapfapfauyazSapfapfaaaaCobxFaDqaDqaEIaEJaEKaEKaELaEMaENaEOaEPaEQaERaESaETaEUaEVaEWaCuaCwajgaaaaBbaEXaEYaEZaFaaFbaBbaaaayMaFcaCCaCCaFdaFeaFfacAaFgaDNaFhakDaFgaDNaFiakDaFgaDNaFjakDaFkaFlaFmakDaFnaFoaFpaFqaFraCOaFsaFtaFuaFvaFwaFxaCSaFyaFzaFzaFzaFAaFBaBIaTeaFDaThaBIaFFaFGaFGaFHaFIaFJaFKavvavvavvavvavvaoGaFLaxhaFMaFNaFOaFPaFQaFRaFSaFTaFTaFTaFTaFUaFVaFWaFXaFYaCgaFZabqabqaaaaaaaaaabqabqaaaaaaabqaaaaaaaWAaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaaaarAarAarAarAarAabqabqabqarAarAarAabeaaaabqabqabqapfaAgaoXaoXaGbalLaaaaaaaASaDraDraDraASayKaGcaGdaGeaEMaEKaGfaGgaGhaCsaGiaGjaGkaGlaGmaCuaCwajgabqaBbaGnaGoaGpaGqaGraBbaaaayMaGsaGsaGsayMaAfaGtacAaAEaCFaCramxaAEaCFaCramxaAEaCFaCramxaGxaCHaGzamxamxazzaGAamxaGBaCOaGCaGDaGEaGFaGGaGHaCSaGIajgajgajgaGJajgaBIaGKaGLaBIaBIaGMaGNaGOaGPaGQaGRaGSazlaGTaGUawWavvaGVaGWaxhaGXaGYaGZaGZaHaaCMaDcaHcaHdaHeaHeaHeaHfaHgaHhaHiaDLarAaMKaMJaOhaMJaMJaOhaMJaMJaOhaMJaMJaPwabqaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarBabqarAarAarAarAarAarAarAarAarAarAarAayyarAabqaupapfapfapfayzayAapfabqabqabqabqabqabqabqabqabqabqabqapfaqBayBapdaoXayCaoXayDayEayFayHayGayIajgajgajgaxTaxQaxQaxQaxUajgajgayMayNayOayPayMamEamEakDayQayRapnaySaySayTayUaySaySayVayUaySayWaySayVayXayYayZayUazaazbaySaySaySayUaySaOPamxazdazeazeazeazeakDatLafbaxYaWvavqavrazfazgazhavraziazjazkazlazmavvavvavvaznaoGasIazoawXasJaoGayvaoGazpaoGazqdfFazsbpmdfobpobqVbpqbqXbqWbqWbqWbqWdeSdgCdeVdgCdgCdgCaxgazHaxgaWwaWwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaupabqarAataarAarAarAarAazIabqarAarAarAarAarAarAazJazKazJazLazMapfapfabqaaaaaaaaaaaaaaaaaaaaaaaaabqapfapfapfathaoXapdaoXazNazOazPazRazQaAYajgaaaabqaaaaaaaaaaaaaaaabqaaaaxEazUazVazWazXazYazeazZaAaaAbaAcaAdaAdaAeaAcaAdaAdaxVaAcaAhaAiaAdaAjaAkaAlaAdaAmaAnaAoaApaApaAqaAraAsaAtaAuaAvaAwaAxaAyaAzakDatLafbaxYaWxavqavraABaACaADayJaAFaAGaAHavvaAIaAJaAKavvaALaoGaoGaoGayoaoGaoGasJaoGaucaoGaAMaxhaxhawYaANamkaxhaxhaxhaxhaxhaxhaxhaxhaxhayxaxhaxhaxhaxhaxhaAOaxhabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarAarAarAarAarAarAarAarAarAarAarAabqarAarAarAabqapfapfapfaAPazSapdapfaaaaAQaARaASaARaATabqabqabqabqapfaAUapfaAVavUavUavUaAWaAXajgaCEaAZaBaajgaaaaBbaBbaBbaBbaBbaBbaBbaaaayMaBcaBdaBeayMamEamEakDaBfaBgaBhaBiaBjaBkaBhaBlaBjaBgaBmaBnaBoaBpaBqaBraBsaBtaBuaBvaBwaBxaByaBwaBzaBAaBBaBCaBDaBEaBFaBGaBHakDatLaBIaBIaBIaBIavraBJaPWaBLaBNaBMaBOayeaBPaBQaBRaBSavvaBTaBUaBVaBWaBXaBWaBYaBWaBZaBWdgEaCaaCbaCcaCdaCeaCfaCgaChaCgaCiaCjaCkaCjaClaxhaxhaxhaCiaCjaClaCmaCmaCgabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqabqabqarAarAarAarAarAarAarAaCnarAabqabqabqabqapfaoXazSarIalLaaaaCoaCpaCqaCpaCoayKayKayKaCsaCsaCsaCsaCtaCsaCsaCuaCuaCuaCuaCvaCuaCwajgabqaBbaCxaCyaCzaCAaCBaBbaaaayMaCCaCCaCDayMaaaaaaakDayLaCGazwakDayLaCIazwakDayLaCJazwakDaCKamEaCLakDamEazzaCNamEamEaCOaCOaCPaCQaCRaCOaCOaCSakDakDakDakDakDatLaBIaQdaCUaQvavravravravravraCWaCXaCYazlazmavvavvavvaoGaCZasIarrasJasIaDadgIaxhaxhaxhaxhaxhaDbaDcaDdaDeaDfaWyaDfaDhaDiaDjaWzaDkaCjaDlaCjaDmaWzaDjaDiaCmaDnaDoabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarBabqabqabqarAarAarAarAataarAarAarAaDparAarAarAarAabqaaaabqalLayBazSaqwapfaaaaASaDqaDraDqaASayKaDsaDtaCsaDuaDvaDwaDxaDyaCsaDzaDAaDBaDCaDDaCuaCwajgaaaaBbaDEaDFaDGaDHaDIaBbaaaaxEaDJaCCaDKayMaAfaAfamxaDMaDNaDOakDaDPaDNaDOakDaDQaDNaDOakDaDRaDSaDTakDaDUaDVaDWaDXaDYaCOaDZaEaaEbaEcaEdaEeaCSaEfaEgaEgaEhaEgaEiaBIaRtaEkaRyaBIaEmaEnaEmavvaEoaEpaEqaEraEsaEtaEuaEvaBWaEwaxhaxhaxhaxhaxhaxhaxhaExaExaEyaEzaEAaEBaECaEDaCgaCgaCgabqabqaEEaEFaDiaDiaDiaDiaDiaEGaEEaDiaEHaCgaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqarAarAarAarAarAarAarAabqarAabqabqarAarAabqabqapfapfauyazSapfapfaaaaCobxFaDqaDqaEIaEJaEKaEKaELaEMaENaEOaEPaEQaERaESaETaEUaEVaEWaCuaCwajgaaaaBbaEXaEYaEZaFaaFbaBbaaaayMaFcaCCaCCaFdaFeaFfamxaFgaDNaFhakDaFgaDNaFiakDaFgaDNaFjakDaFkaFlaFmakDaFnaFoaFpaFqaFraCOaFsaFtaFuaFvaFwaFxaCSaFyaFzaFzaFzaFAaFBaBIaTeaFDaThaBIaFFaFGaFGaFHaFIaFJaFKavvavvavvavvavvaoGaFLaxhaFMaFNaFOaFPaFQaFRaFSaFTaFTaFTaFTaFUaFVaFWaFXaFYaCgaFZabqabqaaaaaaaaaabqabqaaaaaaabqaaaaaaaWAaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaaaarAarAarAarAarAabqabqabqarAarAarAabeaaaabqabqabqapfaAgaoXaoXaGbalLaaaaaaaASaDraDraDraASayKaGcaGdaGeaEMaEKaGfaGgaGhaCsaGiaGjaGkaGlaGmaCuaCwajgabqaBbaGnaGoaGpaGqaGraBbaaaayMaGsaGsaGsayMaAfaGtamxaAEaCFaCramxaAEaCFaCramxaAEaCFaCramxaGxaCHaGzamxamxazzaGAamxaGBaCOaGCaGDaGEaGFaGGaGHaCSaGIajgajgajgaGJajgaBIaGKaGLaBIaBIaGMaGNaGOaGPaGQaGRaGSazlaGTaGUawWavvaGVaGWaxhaGXaGYaGZaGZaHaaCMaDcaHcaHdaHeaHeaHeaHfaHgaHhaHiaDLarAaMKaMJaOhaMJaMJaOhaMJaMJaOhaMJaMJaPwabqaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqabqabqabqabqabqabqabqabqabqabqabqaHkaHlaHkabfaaaabqaaaabqapfaHmaHnanEazSapfapfaaaaCoaHoaHpaHqaCoayKayKayKaCsaHraEKaHsaGgaHtaCsaHuaHvaHwaHxaHyaCuaCwajgaaaaBbaHzaHAaHBaHCaBbaBbaaaaHDaHEaHEaHEaHFaHGaHHaHGaHIaHJaHIaHKaHIaHJaHIaHLaHIaHJaHMaHNaHOaHPaHQaFCaHSaHTaHUamxazeaCSaHVaHWaHXaHYaHZaIaaCSaIbaBIaIcaIdaIeaIfaIfaIgaIhaIiaIjaIkaIlaImaInaIoaIpayeaIqaIraIsaItavvaucaGWaxhaIuaIvaIwaIxaIyaIzaIAaIBaICaIDaIDaIDaIEaIFaHhaHiaDLaMIaPxarAaPyarAarAaPyarAarAaPyarAarAaPxaMIaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaabqaaaaaaabqabqaaaaHkaIGaHkabqabqabqabqabqapfaIHapdapdaIIaIJapfaaaaIKaARaILaARaIMabqabqabqayKaINaIOaIPaIQaIRaCsaISaITaIUaIVaIWaCuaCwajgaaaabqaaaaGaaIYaGuaaaabqaaaaHGaAfaAfaAfaHGaHGaJaaJbaJcaJdaJeaJfaJgaJhaJhaJiaJhaJjaJgaJkaJlaJmaJnaJoaJpaJqaJramxazeaCSaCSaJsaJtaCSaJuaCSaCSaGIaBIaBIaBIaJvaJwaJxaJyaJzaJAaJBaJCaJDaJEaJFaJFaJGaJHavvavvavvavvavvaubaGWaxhaJIaJJaJKaJLaJMaGvaJOaJPaJQaJRaJSaJTaJUaJVaHhaHiaDLaDLaPxaJWaaaaaaaaaaaaaJWaaaaaaaJWarAaPxabqaCgaJXabqabqabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaabqaaaaaaaaaabqaaaaHkaHlaHkaHkaGwaGwaGwaHkaHkaHkaHkaHkaJZaKaapfaaaaaaaaaaaaaaaaaaaaaaaaabqayKaKbaKcaKdaKeaKfaCsaKgaKhaCuaCuaCuaCuaKiajgaKjaGyaHjaHbaKnaHRaIZaIXaKjaHGaKraKsaKsaKtaKuaKvaKwaKxaKyaKzaKAaKBaTiaKDaKEaKCaKFaKGaKHaKIaKJaKKaJNaKMaKNaKOamxazeaKPaCSaKQaKRaCSaKSaKTaKUaKVaBIaKWaKXaKYaKZaBIaLaaLbaLcaBIaLdaLeaLfaLgaLfaLhaLiaLjaLkaLlaLmavvasJaGWaxhaLnaLoaLpaLqaLraFRaLsaLtaJQaLuaCgaCgaLvaLwaCgaDLaDLaDLaPxaaaaaaaaaaaaaaaaLxaaaaaaaaaaTMaRgabqaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaaaaaaaaaabqaHkaHkaLyaLzaLAaLBaLBaLCaLDaLEaLFaLGaHkaHkazSapfaaaaLHaLIaLIaLIaLIaLIaLJabqaCsaCsaCsaJYazTaCsaCsaLMaLNaLOaLPaLQaLRaLSaLTaLUaLVaLWaLXaLYaLWaLZaMaaMbaHGaMcaMdaMeaMfaMfaKkaMfaMfaMfaMfaMfaMfaMfaMfaKkaMfaMhaMiaMjaMkaMkaMkaMlaMlaMlaMlaMlaMkaMmaMkaMnaMnaMnaMnaMoaMnaGIaBIaBIaBIaMpaMqaBIaMraBIaMsaBIaMtaMuaMvazlaMwaMxaMyazlaMzaMAaMBavvaMCaMDaxhaCgaCgaCgaCgaCgaFRaMEaMFaJQaMGaCgaMHaXGaWubssaWuddkaDLaPxaaaaaaabqabqabqabqabqaaaaaaarAaPxarAaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdabdabdabdabdabdabdabdabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqaaaaaaaaaaaaaaaaHkaMLaMLaMLaLBaLBaLBaLBaLBaLBaMLaMLaMMaHkazSalLaaaaMNaMOaMOaMOaMOaMOaMNabqabqaKlaMQaMRaMSaMTaMUaMVaMWaMXaMYaMZaNaaNbaNcaLRaNdaNeaNfaNgaNhaNiaNjaNkaNlaNmaNnaNoaKmaaaaaaaaaabqaaaaaaaaaabqaaaaaaaaaaKoaNraNsaNtaMkaNuaNvaNwaNxaNyaNzaNAaNBaNCaMkaNDaUfaNFaNGaNHaMnaNIaBIaNJaNKaJwaMqaBIaNLaBIaNMaBIaNNaNOaNPaNQaNQaNQaNQaNQaNQaNQaNQaNQaoGaNRaxhaNSaNTaNUaNVaCgaNWaIvaMFaNXaNYaNZaOaaObaOcaOdaOeddRaDLaPxaJWabqabqaOgddSaOiabqaOjaaaarAaPxataaCgaDoabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdaaaaUUaUUaUUaUUaUUaaaabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaaaaaaaaaaaaaaaaaaabqaaaaaaaaaaaaaaaaaaaHkaOkaLBaLBaLBaLBaLBaLBaLBaLBaMLaMLaMLaOlaOmapfaaaaMNaOnaMOaMOaMOaMOaMNaKpaKlaKlaOpaOqaOraOraOsaOtaOuaOvaOwaOxapfaOyapfapfapfapfaOzaOAaKqaOCaODaOEaOAaOAaOAaOAaOFaaaaaaaOGaOGaOGaOGaOGaOGaOGaaaaaaaMfaOHaOIaOJaOKaOLaNAaOMaONaOOaVsaOQaORaOSaMkaOTaOUaOVaOWaOXaMnaOYaBIaBIaBIaOZaOZaBIaBIaBIaBIaBIaPaaPbaPcaNQaPdaPeaPfaPgaPhaPiaPjaNQaPkaGWaxhaNTaNTaPlaOdaPmaGYaPnaPoaPpaPqaCgaPraPsaPtaPuaPvddUaKLddVaaaaaaabqddWcspaPzabqaaaaaaaTMaRgaMIaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqaaaaaaaaaaaaaaaabdabdabdabdabdabdabdaXHaXIaWBaXJaWBaXKaXOabdabdabdabdabdabdabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaaaaaaaaaaaaaaaaaaabqaaaaaaaaaaaaaaaaaaaHkaOkaLBaLBaLBaLBaLBaLBaLBaLBaMLaMLaMLaOlaOmapfaaaaMNaOnaMOaMOaMOaMOaMNaKpaKlaKlaOpaOqaOraOraOsaOtaOuaOvaOwaOxapfaOyapfapfapfapfaOzaOAaKqaOCaODaKqaOAaOAaOAaOAaOFaaaaaaaOGaOGaOGaOGaOGaOGaOGaaaaaaaMfaOHaOIaOJaOKaOLaNAaOMaONaOOaVsaOQaORaOSaMkaOTaOUaOVaOWaOXaMnaOYaBIaBIaBIaOZaOZaBIaBIaBIaBIaBIaPaaPbaPcaNQaPdaPeaPfaPgaPhaPiaPjaNQaPkaGWaxhaNTaNTaPlaOdaPmaGYaPnaPoaPpaPqaCgaPraPsaPtaPuaPvddUaKLddVaaaaaaabqddWcspaPzabqaaaaaaaTMaRgaMIaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqaaaaaaaaaaaaaaaabdabdabdabdabdabdabdaXHaXIaWBaXJaWBaXKaXOabdabdabdabdabdabdabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaaaaaaaaaabqaHkaPAaLBaLBaLBaLBaPBaLBaPCaLBaLBaMLaPDaHkaGbapfaaaaMNaMOaMOaMOaMOaMOaPEaPFaPGaPFaPHaPIaPJaPKaPLaPMaPNaPOaPPaPQaPRaPSaPTaPTaPUaPTaPVaOAaYOaPXaPYaPZaQaaQbaQcbeBaQeaQfaQgaQgaQhaQiaQjaQkaQlaQmaQmaQnaQoaQpaKGaNtaMkaQqaNAaQraNAaQsaNAaQtaNAaNAaMkaQubeLaOVaQwaQxaMnaQyaQzaQAaQBaQCaQDaQEaQFaQGaQHaQIaQJaQKaQLaNQaQMaQNaQNaQNaQOaQPaQQaNQaQRaGWaxhaQSaQSaQTaOdaPmaJJaQUaQVaQWaQXaQYaQZaRaaRbaRcaRdaOfaDLaPxaaaaReabqaRfddXaRhabqabqaJWarAaPxabqaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdaaaaUUaUUaUUaUUaUVaXNbbXbbWbbYbbWbbZbgUaUVaUUaUUaUUaUUaaaabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaGwaLBaLBaLBaLBaLBaLBaLBaLBaLBaLBaRiaHkaHkaRjapfabqaMNaMOaMOaMOaMOaMOaRkaRlaRmaRlaRnaPIaRoaRoaRpaRoaOuaRqaRraRsapfapfapfapfapfapfazSaOAbgkaRuaRvaRwaRxaRxaRxbgyaOFaaaaOGaRzaRAaRAaRAaRAaRAaRBaOGaaaaMfaRCaMiaMjaMkaRDaREaRFaNAaRGaNAaRHaRIaNAaRJaRKaRLaRMaRNaROaMnaRPaRQaRRaRRaRRaRSaRTaRTaRUaRUaRVaRWaRXaRYaRZaSaaSbaSbaSbaScaSdaSeaNQaSfaGWaxhaQSaSgaShaSiaCgaSjaIvaSkaJQaSlaCgaSmaSnaSoaSoaSoaSpaDLaPxaaaaaaabqabqabqabqabqaaaaaaarAaPxabqaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdaXHbcbbcabcabcabcabcabzhbzhbdJbzhbzhbcabcabcabcabcaaXKaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaSqaSraSsaaaaGwaLBaLBaLBaLBaLyaLBaStaSuaSuaSvaSwaHkaqBazSapfabqaMNaMOaMOaMOaMOaSxaMNaKpaKlaKlaSyaPIaSzaSAaSBaSCaSDaSEaSFaSGaLKaSIaSJaSKaSLapfaSMaOAaSNaRuaSOaSPaSQaSQaSRaSSaOFaaaaMgaSUaRAaSVaSWaSXaRAaSYaMgaaaaMfaMhaMiaMjaMkaSZaTaaTbaTcaTdaTcbjbaTfaTgaMkbmIbkZaTjaTkaTlaMnaTmaTnaToaTpaTqaTraTsaTtaTuaTvaTwaTxaTyaTzaTAaTBaTCaTDaTEaTFaTGaTHaNQasIaGWaxhaCgaCgaCgaCgaCgaFRaTIaTJaTKaTLaCgaCgaLvaLwaCgaDLaDLaDLaPxaaaaaaaaaabqaaaaaaaaaaaaaaaaTMaRgabqaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdaXHbdMbdKbdNbdNbdNbdNbdNbdNbdObdNbdNbdNbdNbdNbdNbdPbdMaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -8593,7 +8580,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqaWDaWEaWFaWGaWDaHkaLCaMLaWHaWIaWJaLBaLBaLBaLBaUYaWKaHkazSapdalLaaaaMNaOnaMOaMOaMOaMOaMNaKpaKlaKlaWLaPIaRoaRoaRpaRoaOuaVjaWMaWNaVlaWOaWPaWQaWRapfazMaOAaWSaWTaWTaWUaWVaRuaUgaWWaOFabqaOGaOGaOGaWXaWYaWZaOGaOGaOGabqaMfaOHaXaaMjaXbaXcaVEaVEaVEaXdaVEaVEaXeaNCaXbaQCaXfaXgaXhaToaUiaToaTnaTpaToaXjaToaXkaTpaTqaToaTqaTpaXlaXmaNQaXnaXoaXpaXqaXraPiaQQaNQaXsaGWaxhaXtaXuaXvaXwaXxaXyaXzaXAaXBaXCaXDaXDaXEaXFaHhaHiaDLarAdeaaMJdebaMJaMJdebaMJaMJdebaMJaMJdecabqaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaaaaaaaaaabdaaabgMbdMbeWbeXbeXaXLaXLaXLaXLbfabpvaXLaXLaXLbeXbeXbeYbdMbMnaaaabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaWDaXPaXQaXRaXSaHkaXTaMLaXUaXVaXWaMLaMLaMLaXXaXYaXZaHkaYaaYbapfabqaYcaYdaMOaMOaMOaYeaYfabqabqaKlaWLaYgaPJaPKaYhaYiaYjaYkaYlaYmaYnaYnaYnaYnaYnapfaYoaYpaYqaYraYraYsaYtaYuaYvaYwaUoaaaaaaaaaaOGaOGaYyaOGaOGaaaaaaaaaaKoaNraYzaMjaYAaYBaYCaYDaYEaNCaNCaYFaYGaNCaYAaQCaYHaYIaYJaYKaYLaYKaYMaYNbmLaYPaYKaYKaYKaYKaYKaYKaYQaYRaYSaNQaNQaNQaNQaYTaNQaNQaNQaNQaoGaGWaxhaYVaYUaYUaSTaYWaYXaYYaYZaZaaZbaZcaZdaZeaZfaFXaZgaCgaaaabqabqaaaaaaaaaaaaabqaaaaaaabqabqarAaDiaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdclHbcbbfcbfbbgNaXLaXLbdIbdIbdIbgPbgObdIbdIaXLaXLbgNbgQbgSbgRaWCabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaWDaWDaZiaZjaWDaWDaWDaZkaWDaWDaZlaZmaWDaWDaWDaZnaWDaWDaZoapfapfabqaZpaZqaZraZraZraZqaZsabqabqaZtaZuaPIaRoaRoaRpaRoaOuaZvaOuaZwaYnaZxaZyaZzaZAapfazSaOAaZBaZCaZDaZEaZFaZGaZHaZIaOFaZJaUraZJaZLaZMaZNaZOaZLaZJaUraZJaMfaZPaZQaZRaZSaMkaMkaMkaMkaZTaZUaZVaNCaZWaMkaQCaZXaTraZYaZZaZZaZZaZZaoGaoGaoGbaababbacbadbaebafaZZbagbagaoGbahazAazybaiazybajazybakazybalaxhbambambambambanbaobapbaqbarbasbataIvbaubavaCgaCgaCgabqabqbawbaxaDiaDiaDiaDiaDiaDibawaDibayaCgaCgaDoabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaaaaaaaaaaaaabdaXHbgTbicbeXbeXaXLbdIbidbifbiebihbigbiibidbdIaXLbeXbeXbijbgTaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaUtbaAbaBbaCbaDbaEbaBbaFbaGbaHbaGbaIbaJbaGbaKbaLbaMbaNbaOapfaaaaaabaPbaQbaQbaQbaRaaaabqaZtbaSaWLaPIaRoaRobaTbaUaOubaVbaWbaXbaYbaZbbabbbbbcapfazSaOAaOAaOAaKqaKqaUuaOFbbebbfaOFbbgbbhbbiaZLbbjbbkbblaZLbbmbbnbbobbpbbqbbrbbsbbtbbubbvbbwaMkaMkaYAaLLaYAaMkaMkaUibbybbzaUibbAbbBbbCbbDbbEbbFaoGaoGaoGaoGbbGaoGaoGaoGaoGaoGaoGaGWasIasJbbHbbHbbHbbHbbHbbHbbHbambbIbbJbbKbamaUwbbMbambbNbbOaFRaFRbbPbbQbbRaDfbbSaDfbbTaDibbUaDiaCiaCjbbVaCjaClaDibbUaDiaCmaDnaDoabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabdaXHbdMbeWbeXaXLaXLbdIbikbilbdLbnQbimbjPbjObdIaXLaXLbeXbeYbdMaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaUNbaAbaBbaCbaDbaEbaBbaFbaGbaHbaGbaIbaJbaGbaKbaLbaMbaNbaOapfaaaaaabaPbaQbaQbaQbaRaaaabqaZtbaSaWLaPIaRoaRobaTbaUaOubaVbaWbaXbaYbaZbbabbbbbcapfazSaOAaOAaOAaKqaKqaUuaOFbbebbfaOFbbgbbhbbiaZLbbjbbkbblaZLbbmbbnbbobbpbbqbbrbbsbbtbbubbvbbwaMkaMkaYAaLLaYAaMkaMkaUibbybbzaUibbAbbBbbCbbDbbEbbFaoGaoGaoGaoGbbGaoGaoGaoGaoGaoGaoGaGWasIasJbbHbbHbbHbbHbbHbbHbbHbambbIbbJbbKbamaUwbbMbambbNbbOaFRaFRbbPbbQbbRaDfbbSaDfbbTaDibbUaDiaCiaCjbbVaCjaClaDibbUaDiaCmaDnaDoabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabdaXHbdMbeWbeXaXLaXLbdIbikbilbdLbnQbimbjPbjObdIaXLaXLbeXbeYbdMaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqaaaaUNbcdbcebcebcfbcebcebcebcgbchbcibcjbckbckbckbclbcmbcnbcoapfaaaaaaabqabqaaaaaaabqabqabqaZtbcpbcqbcrbcsaRobctbcubcvbcwbcxbcybczbcAbcBbcCbcDapfbcEbcFbcGbcHbcIbcJbcKbcLbcMbcNbcObcPbcQbcPbcRbcSbcTbcUbcVbcPbcWbcXbcXbcYbcZbdabcXbcXbdbbdcbdcbdcbddbdebdcbdcbdfbdcbdgbdhbdcbdcbdcbdibdjaoGbdkbdlbdmbdnbdobdpbdobdqbdobdrazBbakbalaubasJbbHbdsbdtbdubdvbdwbdxbambdybdzbdzbdAbdzbdBbambdCbarbdDbdEbdEbdEbdEbdEbdFaCgbdGaCjbdHaCjaDmaCgaCgaCgbdGaCjaDmaCmaCmaCgabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdaXHbdMbeWbeXaXLaXLbdIbjQbilbdIbjRbdIbjTbjSbdIbdIaXLbeXbeYbdMaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqaUNaUNbdQaUNaWDaUNbdRaUNbcdbcebdSbdTaUNbdRaUNbdUbdVbdWbdXapfapfapfapfalLalLalLapfapfapfaZtbdYbdZbdZbdZbdZbeaaRobebbecbedbeeaYnaYnaYnaYnaWjapfapfbegapfapfbehbeibejbekbelbembenbekbelbeobepbembeqbekbekbekbelbekbekberbesbekbekbekbekbekbekbekbetbeubekbekbenbevbewbekbekbekbekbexbeybezbezbezbeAbezbezbezaoGbmMaoGaGWaoGaoGbeCbeCbeCbeCbeDbeEbeEbeFbeGbeHbambeIbeJbeKbmNbeMbeNbambeObePbeQbdEbeRbeSbeTbdEbeUaCgaCgaCgaCgaCgaCgaCgbeVaCgaCgaCgaCgaCgaLwaCgabqarBbjUabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabdaXHbdMbeWbeXaXLaXLbjWbjVbjYbjXblFblDblIblGblJbdIaXLbeXbeYbdMaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaUNabqaaaabqaaaaUNbfdaUNbfebfebffbfgaUNbfdaUNaUNaWDbfhbfibfjavTavUbfkavUbflavUbfmbfnavVbfobfpbfqbfqbfrbfsbftbfubfvbfwbfxbfybfwbfzbfAbfwbfBbfCbfDbfEbfFbfGbfHbfIbfJbfKbfKbfLbfMbfNbfObfPbfQbfRbfSbfSbfSbfSbfSbfSbfSbfTbfUbfVbfVbfVbfVbfVbfVbfVbfVbfWbfXbfYbfZbfVbgabfWbfVbfVbgbbgcbgdbezbgebgfbggbghbgibezbgjbmOaoGbglaoGaaabeCbgmbgnbeCbgobgpbgqbgrbgsbgtbambgubgvbgwbgxbmPbgzbambgAbgBbgCbdEbgDbgEbgFbdEbgGaOdaOdbgHaOdbgIaOdaOdaOdbgJaOdbgKbgLbgKbgLaefaefaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdabdaXHbdMbeWbeXaXLaXLbdIblKbilbdIblLbdIbjTbjSbdIbdIaXLbeXbeYbdMaXOabdabdabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -8601,7 +8588,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabinbiobipbiobiqbiobiobiqbiobipbirbisaWDbgVbitbiubivbiwbixbiybizbiAbgXbiBbiCbiDbiEbiFbiGbiFbiGbiHbiGbiIbfwbiJbiKbiLbiMbiNbazbiPbiQbiRbiSbiTbbdbiVbiWbiXbhqbiYbiZbjabhKbhqbjcbjdbjeabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqbhwbjfbjgbjhbjibjjbjkbjlbhwbjmbjnbjobezbjpbjqbjrbjsbjtbezaoGaoGaoGbjuaoGaaabeCbjvbjwbeCbjxbjybjzbjAbjBbjCbambjDbjEbjFbjGbjHbjIbamaFRbjJaFRbdEbjKbjLbjMbdEdeWavPdfadfcdfbdfdasXdfeanqanqaaaaaaaFRbgLaFRabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqaUUaUUblMaXNbmHblNbfbbgNaXLaXLbdIbidbilbmTbnLbnEbnMbidbdIbdIaXLbgNbgQbnNbnPbnOaWCabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabinbiobiobjZbkabkbbkcbkdbkebkfbkgbkhbkbbkibkjaUNbgVbgWbbLbklbkmbknbkobkpbkqbkrbksbktbkubkvbkvbkwbkxbkybfwbfwbfwbfwbkzbkAbkBbkCbkDaXibkEbhkbhlbkFbkGbkHbkIbfIbkJbhqbkKbkLbkMbkNbkObkPbkQbccabqabqbefbhvbhabhHbkWbiObhvbhHbkWbiObhabhabiUabqabqbhwbmRblablbblcblbbldblebhwblfbfIblgbwlbezbkkbljbkRbezbezbllblmaoGblnaoGblobeCbeCbeCbeCbbHbbHbbHblpblqbbHbambambambambambkTbkSbambltblubltbdEbkUblwbkVbdEdffdfhdfgdfgdfjdfkdfkdfkdflabqaaaaaaaaaaWwaaaabqaaaaaaaaaaaaaaaaaDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaWwbnRblEbnTbnSbnUbicbeXbeXaXLaXLbdIbpsbptbdLbqZbpubrbbrabdIbdIaXLbeXbeXbrcbijbrfaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaablOblPblQblRbkbblSblTblSblTblSblTblSbkbblUblVaUNbgVblWbgXblXblYblZbmabmbbmcbgXbmdbmebmfbmgbmhbmibmjbmkbmlbmmbmnbmobmpbmqbmrbmsbmtbmubmvbmwbmxbmybmzbmAbiVbfIbmSbhqbmQbmCbmDbmEbhqbmFbmGbjeabqabqbkXboBbopbpVboHbqfbqdbqhbqgbqkbqjbqlbkYabqabqbhwbmUbmVbmWbmXbmYbmZbnabhwbhybnbbncbndbnebnfbnebngbnhbnibnebnebnebnjbnebnkbnlbnmbnnbnebnebnobnkbngbnjbnpbnqbnobnrbnsbntbnubnvbnwbnxbnybnzbnAbnBbnCbnDblidfmdftdfqdfxdfudfydeZaoNdflabqaaaaaaaaaaWwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaaaaWwbnRblEbnKbrgbrhbeWbrjbeXaXLaXLbdIbrlbrmbifbrIbrnbrQbrKbdIbdIaXLbeXbeXbeXbeYbrfaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabiqbkbbkbbipbkbblSblTblSbnVblSblTblSbkbblUblVaUNbnWbnXbnYbnZboablkbocblkbiubiubodboebhcbfwbofbogbohboibojbokbolbfwbombonbojbkCboobfwbrXboqborbosbotbbdbkIbfIbkJbhqboubovbowboxbhqboybozbjebkWblrbkWbsbboCboDboEboDboFboDboEboDboGbscbkWblrbkWbhwboIboIboIboJboKboLboMbhwboNboOboPboQboRboSboRboTboRboUboRboRboRboVboRboWboXboYboZboRboRbpabpbbpcboVbpdboVbpebpfbpgbntbphbpibpibpjbpkbpibpidfzdfBdfAdfGdfDdfIdfHdfKdfJdgddfLdgKazDabqaaaaaaaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqbpraaaaaaaaaabqbsdbsdblMbsebsfbeWbsnaXLaXLaXLbsMbdIblHblHbsObdIbdIbdIbdIbrkaXLaXLaXLbeXbeYbdMaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabiqbkbbkbbipbkbblSblTblSbnVblSblTblSbkbblUblVaUNbnWbnXbnYbnZboablkaUtblkbiubiubodboebhcbfwbofbogbohboibojbokbolbfwbombonbojbkCboobfwbrXboqborbosbotbbdbkIbfIbkJbhqboubovbowboxbhqboybozbjebkWblrbkWbsbboCboDboEboDboFboDboEboDboGbscbkWblrbkWbhwboIboIboIboJboKboLboMbhwboNboOboPboQboRboSboRboTboRboUboRboRboRboVboRboWboXboYboZboRboRbpabpbbpcboVbpdboVbpebpfbpgbntbphbpibpibpjbpkbpibpidfzdfBdfAdfGdfDdfIdfHdfKdfJdgddfLdgKazDabqaaaaaaaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqbpraaaaaaaaaabqbsdbsdblMbsebsfbeWbsnaXLaXLaXLbsMbdIblHblHbsObdIbdIbdIbdIbrkaXLaXLaXLbeXbeYbdMaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaablObpwbpxblRbkbblSblTblSblTblSblTblSbkbblUblVaUNbpybpzbpAbpBbpCbpDbpDbpEbpFbpBbpGbpHbpIbfwbpJbpKbpLbpMbpNbpObpPbfwbpQbpRbpSbpTbpUbfwbsibpWbpXbpYbpZbfGbqabjnbqbbqcbqcbqcbqcbqcbhtbtPbqebhtbkWbtSbtRbtTboEboEboEboEbqiboEboEboEboEbtZbtYbubbkWbqmbqnbqobqpbqqbqrbqrbqsbhwbqtbqubqvbqwbqxbqybqxbqzbqxbqAbqxbqxbqBbqxbqxbqCbqDbqxbqEbqBbqFbqGbqCbqHbqxbqIbqJbqKbqLbqMblsbqObqPbqQbqRbpnbqSbqSbqTdgMdgLdgOdgNdgPanqanqanqanqanqanqanqanqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqaaaabqbsPbsRbsQbsSbrdcKIaXNbsfbsTbsUaXLbsWbsVbsXbribsZbsYbtbbtabtcbrkbtebtdbtgbtfaXLbeXbeYbdMaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrobiobiobjZbrpbkbbrqbkbbrrbrsbkbbrtbkbbkibruaUNbgVbrvbrwbrxbrybrzbrAbrBbrCbrxbrDbrEbrFbfwbrGaXibrHblvbfwbfwbfwbfwbfwaXibrJblxbfwbfwbbdbrLbrMbbdbbdbzObehbfIbrObqcbrPbumbrRbqcbrSbrTbrUbrVbrWburbrYbrZbsabsabvWbwfbwebvWbvWbsabsabsgbshbwgbkWbhwboIboIboIbsjboIboIboIbhwbskbfIbslbZiblCbsoblCbsmbspbspbspbspbspbspaoGaoGbsqaoGaoGaoGbsrbmBaoGaoGaoGbstaoGbsubsvbswbsxbsybszbsAbsBbqSbsCbsCbsDbqUbsEbjNbntbsFbsGbsHbsIbsJbsJbsKbsLabqaaaaaaabqaaaaaaaaaaaaaaaaaaabqaaaaaaaaaaaaaaaaaaabqaaaaaabuLbudbuMabqbuObuNbuQbuPbuSbuRbuTbBebuVbuUbuWbribuYbuXbvabuZbvcbvbbvebvdbvgbvfaXLbvhbvibdMaXOabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrobiobthbiobiqbiobiobiqbiobipbtibtjaWDbvjbtlbtmbfGbtnbtobtpbtobtqbfGbtrbtsbttbtubtvbtwbtxbtybtzbtwbtAbtBbtwbtvbtvbtCbtvbtDbtEbtFbtGbtHbtvbtIbtJbtKbkJbobbtMbtNbtObqcbjebjebjebjebkWbwmbtQboEboEboEbtUboEbtVbtWbtXboEboEbwnbuabAkbucbhwbwobuebufbugbuhboIbuibhwbujbfIbukboAdedbunbuobsmbupbuqbwpbusbutbuubuvbuwbuxaoGbuybuzbuAbuBbuCaoGaxcbuDaoGbuEbuFbuGbqNbuHbuHbuHbuIbuJbqSbqSbuKbvlbvkbvnbvmbvpbvobvrbvqbvsbvsbvvbvtbvwbvwbvwbxlbxmbvwbvwbvwbvwbvwbxlbvwbvwbvwbvwbvwbvwbxlbvwbxmbxobxnbxpbxpbxrbxqbxtbxsbxvbxubxxbxwbxzbxybxBbxAbxDbxCbzebxEbzgbzfbzjbzibzlbzkbznbzmbzpbzoaWCabdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -8631,12 +8618,12 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarBaaaaaabTYcfTbTYaaaabqaaaaaaaaabZUceNbZUbZUbZUbZUcfUbZUbZUcfVcfWcfVbZUbZUbZUbZUbZUcfXcfYbZUcfZcgacgbcgccgdcgecgfcggcgfcghcgicgjcgkcglcgmbVocgocgpcgqcgrcgscgtcgucgvcfkcgwcgxcgycftcgzcgAcgBcgCcgDcgEcgFcgGcgHcfxcgIcgJcgKcfxcgLbZucgMcgNcgOcgPcgQcgRcgScgTcgUcgRcgScgTcgTcgRcgVcgWcgXcgYcgZchacbVasIchbchccfKcfKcfKcfKcfKchdchechfbCMchgchhbGGbGGbSPchibIqbIqchjchkchjbIqchlchmbRibCMbCMbCMaUVaUUaUVaUUaUVaaabFcaaaabqaaabFcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabeabqabqbTYceMbTYabqabqabqabqabqbZUchnchochpbZUchqchrchsbZUchtchuchvchwchxchychzbZUchAchBchCchDchEcmJcoQchHchIchJchKchLchMchNchOcdUchPchQcaHchSchTchUchVchWchXchYchZciacgwcgxcgycibciccidciecifcigcihcihciiciicelcikcilcimcfxcinbZuciocipciqbQAcircisciuciucivciuciwciucKCcJFciybZvcizciAciBciCcfJaoGaoGaoGcfKciDciEciFciGciHciIciJbCMciKciLciMciNciOciPciQciRciSciTciUciVciWciXbRiciYciZciYcjacjacjacjacjbabqabeaaaabqaaabFcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaaacjcaaaaaaabqaaaabqaaabZUbZUbZUceNbZUcjdcjecjfcjgcjhcjicjjchychychscjkbZUcjlcjmbZUcdNcjncjocjpcdTcjqcjrcjscjtcjucjvcjwcjxcjxcjycjxcjzcjAcjBcjBcjCcjDcjEcjFcjGcjHcjIcjJcibciccicciccjKcjLcjMcjNcjOcjPceLcjRcjScjTcfxcjUbZubZubZubZubZvbZvcjVbZvbZvbZvbZvbZvbZvbZvbZvbZvbZvbZvbZvbZvcjWcjXaoGcjYcjZcfKckackbckcckdckeckfcqcbCMckhckhckickhckjckhckickkckjckjbRickhcklckmcknbCMbCMbCMckockpcjackqckoaaabFcaaaabqabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqaaackraaaaaaabqaaacksckscktckubZUckvckwckxbZUbZUbZUckyckzchyckAckBbZUbZUbZUckCckDbZUckEckEckEckEckEckEckEckFcjtckGckHckIcjxckJckKckLckMckNckOckPckQckRckSckTcfscgwckVcgybVickWckXckYckZclaclbclccldclecfxclfclgclhcfxclicljcljcljclkcljcllclmclncljcljclocljcljcljcljclpclqclrclscdocltcluclvclwbVKcfKclxclyclzclAclBclCclDbCMbCMbCMcgnbzLchRbzLcgnbzLchRchRcijbzLcijbCMbCMbCMabqabqabqclHcjaaWCabqabqabqabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaabeabqclIabqabqabqaaaabqabqbZUcbtclJclKbZUbZUbZUclLbZUbZUbZUbZUbZUbZUbZUclMclNcjlclOclPckEclQclRclSclTclUckEclVclWclXclYclZcjxcmacmbcmccmdcmecmfcmgcmhcjQcmjcjQcmkcmlckVcmmcmncmocmocmocmocmpcmqcmrcmscmtcfxcmucmvcmwcfxcmxcmycmzcmzcmzcmzcmAcmzcmBcmBcmBcmBcmBcmBcmBcmBcmBcmCbZUcmDasJasJasJaoGasJazocfKcmEcmFcmGclAcqrcqJcqIclAabqabqcmKabqcmLabqcmKabqcmMcmNcmOabqcmOabqabqabqabqaaaaaacmPcjacmQaaaaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaarBaaacmRaaaabqaaaaaaabqaaabZUcmSbZUchnchocjecmTcjecjecmUcmVcmVcmVcmWcmVcmVcmVcmXcmYcmZcnacnbcnccndcnecnfckEcdTcngckUcnicdTcjxcrjclEcjxcnlcnmcmgcnncnocnpcnqcnrcmgcnscntcnucmocnvcnwcnxcnycnxcnzcmocnAcnBcnCcnDcnCcfxcfxcnEbZUcmzcnFcnGcnHcnIcnJcmBcnKcnKcnKcnLcnMcnNcnKcmBcmCbZUcnOasIcnPcnQaoGcnRcnScfKcnTcnUcnVctucnXcnWcNmctuabqbGLcnYbzLcnYbGLcnYbzLcnYbGLcnZbzLcoabGLabqaaaabqabqabqcobcjacocabqabqabeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqarBaaacjcaaaabqaaaaaaabqaaabZUbZUbZUbZUbZUbZUbZUbZUbZUcodcoecoecofcogcogcogcogcohcogcogcogcoicojcokcolcomconcoocopcoqcorcoscotcoucovcowcoxcoycozcoAcoBcoCcoDcoEcmgcoFckVcmmcmpcoGcoHcoIcoJcoKcoLcmocoMcoNcoOcoPcmzcdNcjncrFcrvcmzcoRcoScoTcoUcoVcmBcnKcoWcoXcoYcnKcoZcpacmBcpbbZUbZUbZUbZUbZUaoGaoGaoGcfKcfKcfKclFctucpdcpecpfcpgabqbGLcphcpicpjbGLcpkcplcpmbGLcpncpocppbGLabqaaaabqaaabCMcpqcprcpscptaaabFcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaabeaaackrabqabqabqabqabqaaabZUcpucpvcpwcpxcpycpzcpAbZUcodcoecpBcpCcpDcpEcpFcoecpGcpHcpIcoecpJcpKcpLcpMcpNcpOcpPcpQcpRcpScpTcpUcpTcpScpTcpVcpWcpXcpYcpZcqacqbcrVcjQcnsckVcrWcmocqdcqecqfcqgcqhcqiclGcqkcqlcqmcqncmzcqocqpcqqcsncmzcqscqtcqucqvcqwcmBcnKcnKcqxcnKcnKcqycqzcmBcmCbZUcqAcqBbZUcqCcqDcqEcqFcqGcqHaoGcsoctuctucsRctuctuabqbGLcqKcqLcqMbGLcqNcqOcqPbGLcqQcqRcqSbGLabqabqabqabqcptcqTcqUcqVcqWabqabeabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaarBaaackrabqaaaaaaaaaabqaaacmicqYcqZcracrbcpycrccrdbZUcodcoecrecrfcrgcrhcricCKcrkcrlcrmcoeaovaotcrpcrncrocnhcrtcructAcrwcrxcrycrycrycrzcrAcrBcrCcrDcpZcrEctBcrGcmgcrHckVcrIcmocrJcrKcrLcrMcrNcrOcmocrPcrQcrRcrScmzcrTcrUctSctEcmzcrXcrYcrZcsacsbcmBcmBcsccnkcqjcqjcmBcsfcmBcsgcshcsicsjbZUcskasJasJasJcdKcslbZUcsmcynctucyqctucspabqbGLcqKcsqcqKbGLcqNcsrcqNbGLcsscstcssbGLabqaaaabqaaacqWcqUcsucqUcjaaaabFcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqaaackraaaaaaabqaaacksckscktckubZUckvckwckxbZUbZUbZUckyckzchyckAckBbZUbZUbZUckCckDbZUckEckEckEckEckEckEckEckFcjtckGckHckIcjxckJckKckLckMckNckOckPckQckRckSckTcfscgwckVcgybVickWckXckYckZclaclbclccldclecfxclfclgclhcfxclicljcljcljclkcljcllclmclncljcljclocljcljcljcljclpclqclrboccdocltcluclvclwbVKcfKclxclyclzclAclBclCclDbCMbCMbCMcgnbzLchRbzLcgnbzLchRchRcijbzLcijbCMbCMbCMabqabqabqclHcjaaWCabqabqabqabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaabeabqclIabqabqabqaaaabqabqbZUcbtclJclKbZUbZUbZUclLbZUbZUbZUbZUbZUbZUbZUclMclNcjlclOclPckEclQclRclSclTclUckEclVclWclXclYclZcjxcmacmbcmccmdcmecmfcmgcmhcjQcmjcjQcmkcmlckVcmmcmncmocmocmocmocmpcmqcmrcmscmtcfxcmucmvcmwcfxcmxcmycmzcmzcmzcmzcmAcmzcmBcmBcmBcmBcmBcmBcmBcmBcmBcmCaoGaucasJasJasJaoGasJazocfKcmEcmFcmGclAcqrcqJcqIclAabqabqcmKabqcmLabqcmKabqcmMcmNcmOabqcmOabqabqabqabqaaaaaacmPcjacmQaaaaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaarBaaacmRaaaabqaaaaaaabqaaabZUcmSbZUchnchocjecmTcjecjecmUcmVcmVcmVcmWcmVcmVcmVcmXcmYcmZcnacnbcnccndcnecnfckEcdTcngckUcnicdTcjxcrjclEcjxcnlcnmcmgcnncnocnpcnqcnrcmgcnscntcnucmocnvcnwcnxcnycnxcnzcmocnAcnBcnCcnDcnCcfxcfxcnEbZUcmzcnFcnGcnHcnIcnJcmBcnKcnKcnKcnLcnMcnNcnKcmBcmCaoGclsasIcnPcnQaoGcnRcnScfKcnTcnUcnVctucnXcnWcNmctuabqbGLcnYbzLcnYbGLcnYbzLcnYbGLcnZbzLcoabGLabqaaaabqabqabqcobcjacocabqabqabeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqarBaaacjcaaaabqaaaaaaabqaaabZUbZUbZUbZUbZUbZUbZUbZUbZUcodcoecoecofcogcogcogcogcohcogcogcogcoicojcokcolcomconcoocopcoqcorcoscotcoucovcowcoxcoycozcoAcoBcoCcoDcoEcmgcoFckVcmmcmpcoGcoHcoIcoJcoKcoLcmocoMcoNcoOcoPcmzcdNcjncrFcrvcmzcoRcoScoTcoUcoVcmBcnKcoWcoXcoYcnKcoZcpacmBcpbaoGaoGaoGaoGaoGaoGaoGaoGcfKcfKcfKclFctucpdcpecpfcpgabqbGLcphcpicpjbGLcpkcplcpmbGLcpncpocppbGLabqaaaabqaaabCMcpqcprcpscptaaabFcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaabeaaackrabqabqabqabqabqaaabZUcpucpvcpwcpxcpycpzcpAbZUcodcoecpBcpCcpDcpEcpFcoecpGcpHcpIcoecpJcpKcpLcpMcpNcpOcpPcpQcpRcpScpTcpUcpTcpScpTcpVcpWcpXcpYcpZcqacqbcrVcjQcnsckVcrWcmocqdcqecqfcqgcqhcqiclGcqkcqlcqmcqncmzcqocqpcqqcsncmzcqscqtcqucqvcqwcmBcnKcnKcqxcnKcnKcqycqzcmBcmCbZUcqAcqBbZUcqCcqDcqFcqEcqHcqGbZUcsoctuctucsRctuctuabqbGLcqKcqLcqMbGLcqNcqOcqPbGLcqQcqRcqSbGLabqabqabqabqcptcqTcqUcqVcqWabqabeabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaarBaaackrabqaaaaaaaaaabqaaacmicqYcqZcracrbcpycrccrdbZUcodcoecrecrfcrgcrhcricCKcrkcrlcrmcoeaovaotcrpcrncrocnhcrtcructAcrwcrxcrycrycrycrzcrAcrBcrCcrDcpZcrEctBcrGcmgcrHckVcrIcmocrJcrKcrLcrMcrNcrOcmocrPcrQcrRcrScmzcrTcrUctSctEcmzcrXcrYcrZcsacsbcmBcmBcsccnkcqjcqjcmBcsfcmBcsgcshcsicsjbZUcskchychychycdKcslbZUcsmcynctucyqctucspabqbGLcqKcsqcqKbGLcqNcsrcqNbGLcsscstcssbGLabqaaaabqaaacqWcqUcsucqUcjaaaabFcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqabqabqabqabeabqckrabqaaaaaaaaaabqaaacmicsvcrccqZcswcpycsxbZUbZUcsycoecrscqXcrscsdcrscoecrscsCcrscoeckEcsecsEcszckEckEcsGcsHcsIcsJcsJcsAcsDcsBcsJcsJcsNcmgcsOcsPcsQcyCcmgcmgcsSckVcsTcmocmocsUcsVcsWcsXcsYcmocsZcnBcfwcfwcmzctacmzctbcmzcmzcfwctcctdcfwcfwctectfctgcthctictjcrqctlcmBctmbZUctnctobZUctpcdKchschyctqctrbZUctscttdbjctvdbjarAabqbGLbGLbGLbGLbGLbGLbGLbGLbGLbGLbGLbGLbGLabqabqabqabqcjacqUcqUcqUcqWabqbFcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaaaaabqaaaaaaarBaaaclIaaaaaaaaaaaaabqaaacmictwcqZcswctxcpyctyctzcdOcodcoeczqczpctCctDczJcoectFctGctHcoectIctJctKctLctMcsFctOcgrctPcsJctQctRcABctTctUcsJccvcmgctVctWctXctYcjQctZcuacubcuccudcuecufcugcuhcuicujcsKculcumcuncuocupciccuqcurcusciccutcuucuvciccuwctecuxcuycuzcuAcuBcuCcuDcmBcmCbZUbZUcuEbZUcuFcuGchychycuHcuIcmiabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqabqaaaabqaaacjacqWcptbCMcptaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqaaaaaaabqaaaaaaabeaaacmRabqaaaaaaaaaabqaaacmicmicqZcpycpycqZcqZcuJcdOcodcoecuKcuLcuMcuNcuOcoecuPcuQcuRcsLcuTcuUcuVcuWcuXcuYcuZcgrcgscsAcvacvbcvccvdcvecsJchscmgcvfcvgcvhcvicvjcvkcvlckVcvmcvncvocvpcvqcvrcvscvtcvucvvcvwcvxcvycvzcvAcvBcvCcvDcvEcvDcvFcvGcvHcvIcvJcvKcvLcvMcvNcvOcvPcvQcvRcvSbZUcvTcvUcvVcbvctqchychycvWcvXbZUcvYabqaaaaaaaaaabqaaaaaaaaaaaaaaaabqaaaaaaaaaabqaaaaaaaaaaaaabqaaaabqaaaaaaabqaaaabqaaaaaaabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -8668,22 +8655,22 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarBaaaabqaaaaaacTxabqdeycHZcHZcHZcHZcHZcHZcHZaaaaaacRhcTycTzcRhcTAcTBcTCcTDcRhcTEcTFcTGcTHcTIcTJcTKcTLcTLcTMcTNcTOcTPcTQcRtcSYcTRcTacRtcSocSpcSYcLScTTcRtcTUcTVbZUcTWbZUabqaaacNzcTYcNzaaaaaacOmcWkbZUcmDchychycUacjicUbcjicUccUdcQWcOycUfcOycQWaaaabqaaaabqabqaaaaaaabqaupaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabeabqabqabqaaaaaaaaaabqabqabqaaaaaaaaaabqaaaaaaaaacRhcUgcUhcUicUjcUkcUlcUmcRhcUncRhcUocUpcUqcUrcUscTHcTHcUtcUucUvcUwcUxcUycSYcUzcTacRtcSocUAcUBcUCcUDcUEcUFcUGbZUcTjbZUabqabqcNzcUHcNzabqaaacOmcWlbZUchychychycUJcUKcctcULbZUcmicQWcOycWJcWmcWKcWKcWKcWKcWKcWKcWKcWKcWLarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabeaaaaaaaaaaaaaaaabqaaaaaaaaaabqaaaaaaaaacRhcTycUNcRhcUOcUPcUQcURcUScUTcRhcUUcUVcUWcUXcUYcUZcVacSOcSWcTacRtcVccVdcVecVfcVgcUwcVhcVicVjcVkcVkcSVcTScVkbZUaefabqaaaaaacNzcVncNzaaaaaacOmcWkbZUcVocVpcVqbZUcVrcVscVqbZUaaaabqcOycOycOyabqaaaabqaaaaaaabqabqaaacWRarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabfabeaaaaaaabqabeabfabeabqabeabeabeabqcSOcSOcSOcRhcRhcRhcRhcVtcVucRhcRhcRhcVvcVwcVxcUXcVycVzcVAcSOcSOcTacRtcRtcRtcSYcSZcTacRtcVBcVCcVDcTXabqabqaaaaaaabqaefabqaaacVFcVGcVHcVGcVIaaacOmcWkbZUbZUbZUbZUbZUbZUbZUbZUbZUaaaabqaaacWSaaaabqabqabqabqabqabqaaaaaacWRarBabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabfaaaaaacTZcVLcVMcSOcVNcVOcVPcVQcVRcVScSOcVTcVUcVVcVWcUXcUYcUZcVacVXcSOcVYcRtcVZcWacWbcrrcWdcWacWecRtcWfcVkaaaabqabqabqabqabqabqabqcVGcWgcWhcWicVGaaacOmdafcWTcWTcWTcXlcXAcXocXHcXDcXHcXDcXHcYacWSaaaabqabqaaaaaaaaaabqaaaaaacWRaupaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabfaaaaaacTZcWncVMcWocWpcWpcWpcWqcWrcWscWtcWucWvcWucWwcWpcWxcWwcWycWzcSOcWAcWBcWCcWBcWBcWBcWBcWBcWCcWBcWDcTXaaaabqaaaaaaabqaaaaaaaaacVGcWEcWFdezdeAcyncOmcYccYccYccYccZvcYycYxcYGcYzcZfcYIcZicZhcWScWScWScWScWScWScWScWScWScWScZjaaaaaaaaaaaaaaaaaaarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabfaaaaaacTZcWncWMcVRcWNcWOcUXcWPcWQcZlcZkcZmcWUcWVcWVcWWcWVcWVcWXcWYcSOcWZcXacXbcXacXacXccXacXacXdcXecXfcVkabqabqaaacVGcVGcVGcVGcVGcVGcXgcXhcXicVGcVGcVGcVGcVGcVGcYccZvcYycZncZocYzcYIcYzcZpcXDaaaabqabqaaaabqaaaaaaaaaaaaaaacVJaaaaaaabqaaaaaaaaaaupaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabfabqaaacTZcXjcVMcVRcWNcWNcXkcSOcSOcSOcSOcZwcWzcXmcUXcXncUXcXmcZxcZCcSOcXpcTXcXpcTXcTXcTXcTXcTXcXpcTXcXpcTXaaaabqabqcVGcXqcXrcXscXtcVGcXucXvcVGcVGcXwdeQcXycXzcVGcYccZvcYycYxcYIcYbcYdcYdcYecXZcZFcZFabqauparBaupabqabqabqabqcVJabqabqabqabqabqabearBarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqcSOcSOcSOcXEcUXcUXcUXcXFcXGcSOcZQcVacXIcXJcXJcXKcXJcXJcXLcZRcVkcXMcTXcXacTXaaaaaaaaacTXcXNcTXcXacTXaaaabqaaacNzcXOcXPcXQcXRcXRcXScXTcXUcXVcXVcXWcXXcXYcNzcYccZvcYycZScXHcXCcZycXCcXBcZzcZFcZFabqaaaabqaaaabqaaaaaaaaacYfaaaaaaabqaaaaaaaaaaaaaupaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaacTZcYgcYhcYicYjcYkcXKcYlcYmcSOcSOcSOcSOcUecUecUecUecUecSOcSOcVkcXpcTXcXpcTXaaaabqaaacTXcXpcTXcZUcZTabqabqaaacNzdeBcYpcYqcYrcYrcYscYtcYucYucYucYucYvcYwcNzcYccZvcYycOmcHfcZVdagdaecZFcZFcZFcZFabqaaacYAcYAcYAcYAcYAabqcYBabqcYAcYAcYAcYAcYAaaaarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqcSOcTZcSOcSOcTZcTZcTZcSOcYCcSOaaaaaacYDcYFcYFcYFcYFdahdaXcYFdaidcbcYFdcbdajcYFcYFcYFdaidakcYFdcbdalcYEcYJaaacVGcYKcYLcYMcYNcYOcYPcYQcYRdgXdgWcYUcYVcYWcVGcYcciccWkdawcOmdaxdaycZVcZFcZFcZFcZFabqabqcYXcYYcYYcYYcYYcYZcZacZbcZccZccZccZccZdabqarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqaaaaaaabqaaaaaaaaaaaaaaaabqabqdazdbadaAdcTdcPdaBcZedcncZBdaCcZBdaDcZBdaCdaCdaDdaCdaEcZBdaCcZBcZBdaKdaJaaacVGcZrcZrcZrcZrcTkcZscZtcZucTkcZrcZrcZrcZrcVGdaLciccWkdaMdaOdaNdaPdaecZFcZFcZFcZFabqabqcZAcZAcZAcZAcZAaaacYBaaacZAcZAcZAcZAcZAabqarBabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqabqabqabqabqabqabqabqdaVdaZcZedbkcZBddadbqdbhcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZgcYFaaacVGcZGcZHcZHcVbcZJcZKcZLcZMcZNcVlcZPcZPcZPcVGcYcdbudbFdbvcfwcfwcOmcfwdbGdbGaaaaaaabqaaaabqaaaabqabqabqaaacYBaaaabqaaaabqaaaabqaaaarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadbNdbOcZedbPddccZBcZBdaJcZBcZBdbQdbYdbQdbQdbQcZBdbQdbQdbQdbYdbQcZBcZBdccdaiabqcVGcZPcZPcZPcZXcZYcZZdaadabdacdadcZPcZPcZPcVGcOmcfwcOmcOmcfwdbGdbGdbGdbGdbGaaaaaaabqaaacYAcYAcYAcYAcYAabqcYBabqcYAcYAcYAcYAcYAabqarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadcddaZcZedcedddcZBcZBdcFcZBcZBcYFdclcYFdcmcYFcZBcYFdcmcYFdclcYFcZBcZBcZBcYFaaacVGdancZPcZPcVmdapdaqdardasdatcVEcZHcZHdavcVGaaadbGdbGdbGdbGdbGdbGdbGdbGdbGaaaaaaabqabqcYXcYYcYYcYYcYYcYZcYBcZbcZccZccZccZccZdabqarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadalcYEdbaddmddacZBcZBdcocZBcZBdaCdcpdaCdaCdaCcZBdaCdaCdaCdcpdaCcZBcZBdcqdaiaaacVGcZrcZrcZrcZrdaFdaGdaHdaIdaFcZrcZrcZrcZrcVGaaadbGdbGdbGdbGdbGdbGdbGdbGdbGaaaaaaabqabqcZAcZAcZAcZAcZAaaacYBabqcZAcZAcZAcZAcZAaaaarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaVdaZcZedcrcZBddccZBcZedcJcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcYFaaacVGcZGcZHcZHcVKcZJdaRdaHdaSdaTcYncZPcZPdancVGaaadbGdbGdbGdbGaaaaaaaaaaaaaaaaaaaaaabqaaaabqaaaabqaaaabqaaacYBaaaabqaaaabqabqabqabqaupaaaaaDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabfabeaaaaaaabqabeabfabeabqabeabeabeabqcSOcSOcSOcRhcRhcRhcRhcVtcVucRhcRhcRhcVvcVwcVxcUXcVycVzcVAcSOcSOcTacRtcRtcRtcSYcSZcTacRtcVBcVCcVDcTXabqabqaaaaaaabqaefabqaaacVFcVGcVHcVGcVIaaacOmcWkbZUbZUbZUbZUbZUbZUbZUbZUbZUaaaabqaaaaaaaaaabqabqabqabqabqabqaaaaaacWRarBabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabfaaaaaacTZcVLcVMcSOcVNcVOcVPcVQcVRcVScSOcVTcVUcVVcVWcUXcUYcUZcVacVXcSOcVYcRtcVZcWacWbcrrcWdcWacWecRtcWfcVkaaaabqabqabqabqabqabqabqcVGcWgcWhcWicVGaaacOmdafcWTcWTcWTcXlcXAcWScXBcXCcXBcXCcXBcXoaaaaaaabqabqaaaaaaaaaabqaaaaaacWRaupaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabfaaaaaacTZcWncVMcWocWpcWpcWpcWqcWrcWscWtcWucWvcWucWwcWpcWxcWwcWycWzcSOcWAcWBcWCcWBcWBcWBcWBcWBcWCcWBcWDcTXaaaabqaaaaaaabqaaaaaaaaacVGcWEcWFdezdeAcyncOmcYccYccYccYccZvcYycXZcXDcYbcXHcYdcYecXZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacZjaaaaaaaaaaaaaaaaaaarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabfaaaaaacTZcWncWMcVRcWNcWOcUXcWPcWQcZlcZkcZmcWUcWVcWVcWWcWVcWVcWXcWYcSOcWZcXacXbcXacXacXccXacXacXdcXecXfcVkabqabqaaacVGcVGcVGcVGcVGcVGcXgcXhcXicVGcVGcVGcVGcVGcVGcYccZvcYycYacYxcYbcYdcYbcYzcXCaaaabqabqaaaabqaaaaaaaaaaaaaaacVJaaaaaaabqaaaaaaaaaaupaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabfabqaaacTZcXjcVMcVRcWNcWNcXkcSOcSOcSOcSOcZwcWzcXmcUXcXncUXcXmcZxcZCcSOcXpcTXcXpcTXcTXcTXcTXcTXcXpcTXcXpcTXaaaabqabqcVGcXqcXrcXscXtcVGcXucXvcVGcVGcXwdeQcXycXzcVGcYccZvcYycXZcYdcYbcYdcYdcYecXZaaaaaaabqauparBaupabqabqabqabqcVJabqabqabqabqabqabearBarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqcSOcSOcSOcXEcUXcUXcUXcXFcXGcSOcZQcVacXIcXJcXJcXKcXJcXJcXLcZRcVkcXMcTXcXacTXaaaaaaaaacTXcXNcTXcXacTXaaaabqaaacNzcXOcXPcXQcXRcXRcXScXTcXUcXVcXVcXWcXXcXYcNzcYccZvcYycYGcXBcXCcZycXCcXBcZzaaaaaaabqaaaabqaaaabqaaaaaaaaacYfaaaaaaabqaaaaaaaaaaaaaupaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaacTZcYgcYhcYicYjcYkcXKcYlcYmcSOcSOcSOcSOcUecUecUecUecUecSOcSOcVkcXpcTXcXpcTXaaaabqaaacTXcXpcTXcZUcZTabqabqaaacNzdeBcYpcYqcYrcYrcYscYtcYucYucYucYucYvcYwcNzcYccZvcYycOmcOmcOmcYIcfwaaaaaaaaaaaaabqaaacYAcYAcYAcYAcYAabqcYBabqcYAcYAcYAcYAcYAaaaarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqcSOcTZcSOcSOcTZcTZcTZcSOcYCcSOaaaaaacYDcYFcYFcYFcYFdahdaXcYFdaidcbcYFdcbdajcYFcYFcYFdaidakcYFdcbdalcYEcYJaaacVGcYKcYLcYMcYNcYOcYPcYQcYRdgXdgWcYUcYVcYWcVGcYcciccWkdawcOmcZfcZhcOmaaaaaaaaaaaaabqabqcYXcYYcYYcYYcYYcYZcZacZbcZccZccZccZccZdabqarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqaaaaaaabqaaaaaaaaaaaaaaaabqabqdazdbadaAdcTdcPdaBcZedcncZBdaCcZBdaDcZBdaCdaCdaDdaCdaEcZBdaCcZBcZBdaKdaJaaacVGcZrcZrcZrcZrcTkcZscZtcZucTkcZrcZrcZrcZrcVGdaLciccWkdaMdaOcZicZncfwaaaaaaaaaaaaabqabqcZAcZAcZAcZAcZAaaacYBaaacZAcZAcZAcZAcZAabqarBabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqabqabqabqabqabqabqabqabqdaVdaZcZedbkcZBddadbqdbhcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZgcYFaaacVGcZGcZHcZHcVbcZJcZKcZLcZMcZNcVlcZPcZPcZPcVGcYcdbudbFdbvcfwcfwcOmcfwaaaaaaaaaaaaabqaaaabqaaaabqabqabqaaacYBaaaabqaaaabqaaaabqaaaarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadbNdbOcZedbPddccZBcZBdaJcZBcZBdbQdbYdbQdbQdbQcZBdbQdbQdbQdbYdbQcZBcZBdccdaiabqcVGcZPcZPcZPcZXcZYcZZdaadabdacdadcZPcZPcZPcVGcOmcfwcOmcOmcfwaaaaaaaaaaaaaaaaaaaaaabqaaacYAcYAcYAcYAcYAabqcYBabqcYAcYAcYAcYAcYAabqarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadcddaZcZedcedddcZBcZBdcFcZBcZBcYFdclcYFdcmcYFcZBcYFdcmcYFdclcYFcZBcZBcZBcYFaaacVGaOEcZPcZPcVmdapdaqdardasdatcVEcZHcZHdavcVGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqcYXcYYcYYcYYcYYcYZcYBcZbcZccZccZccZccZdabqarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadalcYEdbaddmddacZBcZBdcocZBcZBdaCdcpdaCdaCdaCcZBdaCdaCdaCdcpdaCcZBcZBdcqdaiaaacVGcZrcZrcZrcZrdaFdaGdaHdaIdaFcZrcZrcZrcZrcVGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqabqcZAcZAcZAcZAcZAaaacYBabqcZAcZAcZAcZAcZAaaaarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaVdaZcZedcrcZBddccZBcZedcJcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcZBcYFaaacVGcZGcZHcZHcVKcZJdaRdaHdaSdaTcYncZPcZPaOEcVGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqaaaabqaaaabqaaaabqaaacYBaaaabqaaaabqabqabqabqaupaaaaaDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadcddbOcZedcMdcKdcNcZBcZedcncZBdbQdbQdcQdbQdbQcZBdbQdbQdbYdbQdbQcZBcZBdcRdcoaaacVGcZPcZPcZPdbbdbccZZdbddabdbedbfcZPcZPcZPcVGaaaaaaaaaaaaaaaaaaaaaabqaaaaaaaaaaaaabqaaacYAcYAcYAcYAcYAabqdbgabqcYAcYAcYAcYAcYAabqarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadalcYEdcGdcScYEdaXddedaWcYEdcUcYFdalcYHdaXcYFdaYcYFdcVdaXcYFdcmdcWdcWdaldbaabqcVGdancZPcZPcZIdbmdaqdbndbodatcZOcZHcZHdavcVGaaaaaaabqaaaaaaabqaaaaaaaaaaaaaaaaaaarBabqcYXcYYcYYcYYcYYcYZcYBcZbcZccZccZccZccZdabqarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadalcYEdcGdcScYEdaXddedaWcYEdcUcYFdalcYHdaXcYFdaYcYFdcVdaXcYFdcmdcWdcWdaldbaabqcVGaOEcZPcZPcZIdbmdaqdbndbodatcZOcZHcZHdavcVGaaaaaaabqaaaaaaabqaaaaaaaaaaaaaaaaaaarBabqcYXcYYcYYcYYcYYcYZcYBcZbcZccZccZccZccZdabqarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaVdaZcZeddbcZEddgddfcZeddiddfddjddjcZeddnddlcZBddodaJddpddwddqcZDcZDddDdaJcVGcVGcZrcZrcZrcZrdaFdbrdaHdbsdaFcZrcZrcZrcZrcVGcVGaaaabqabqabqabqaaaaaaaaaaaaaaaaaaabqabqcZAcZAcZAcZAcZAaaadbtaaacZAcZAcZAcZAcZAaaaarBabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadbNdbOcZeddbcZEdalddEddFddiddfddfddGcZedbwcZBcZBdbicYFddHcZEcZEcZEcZEcZDcYFcVGcZGcZHcZHdaocZJdbzdbAdaHdaScZMdbBdaudbDcZPcZPcVGabqabqaaaaaaaaaaaaaaaaaaaaaaaaaaaabeaaaaaaabqabqabqaaaaaacVJabqaaaaaaabqabqaaaaaaarBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadbEaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadcddaZcZeddIcZEcZEddTdbhddYddfddfdevcZedeKcZBcZBcZBdaYdeTcZEcZEcZEcZEcZDcYFcVGcZPcZPcZPdbHdbIdabdabdbJdabdabdbKdbLdbMcZPcZPcVGaaaabqaaaaaaaaaaaaaaaaaaaaaaaaaaaarBabearBarBarBaaaaaaaaacVJaaaaaaaaaarBarBarBauparBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index c5fcc678c47..c81bd490601 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -462,7 +462,7 @@ "aiT" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/rack,/obj/item/ammo_box/shotgun/beanbag{pixel_x = -3; pixel_y = 3},/obj/item/ammo_box/shotgun/beanbag,/obj/item/ammo_box/shotgun/beanbag{pixel_x = -3; pixel_y = 3},/obj/item/ammo_box/shotgun/beanbag{pixel_x = -3; pixel_y = 3},/obj/item/ammo_box/shotgun/beanbag,/obj/item/ammo_box/shotgun/beanbag,/obj/item/ammo_box/shotgun/tranquilizer{pixel_x = 3; pixel_y = -3},/obj/machinery/ai_status_display{pixel_x = 0; pixel_y = 32},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plasteel{dir = 8; icon_state = "vault"; tag = "icon-vault (WEST)"},/area/security/securearmoury) "aiU" = (/obj/structure/rack,/obj/structure/window/reinforced{dir = 1},/obj/item/weapon/gun/projectile/shotgun/riot{pixel_x = -3; pixel_y = 3},/obj/item/weapon/gun/projectile/shotgun/riot,/obj/item/weapon/gun/projectile/shotgun/riot{pixel_x = 3; pixel_y = -3},/obj/machinery/alarm{pixel_y = 23},/turf/simulated/floor/plasteel{dir = 8; icon_state = "vault"; tag = "icon-vault (WEST)"},/area/security/securearmoury) "aiV" = (/obj/structure/rack,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/obj/item/ammo_box/shotgun/buck{pixel_x = -3; pixel_y = 3},/obj/item/ammo_box/shotgun/buck,/obj/item/ammo_box/shotgun/buck{pixel_x = 3; pixel_y = -3},/turf/simulated/floor/plasteel{dir = 8; icon_state = "vault"; tag = "icon-vault (WEST)"},/area/security/securearmoury) -"aiW" = (/turf/space,/area/security/securearmoury) +"aiW" = (/obj/item/toy/prize/honk,/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aiX" = (/obj/item/device/radio/intercom{pixel_x = -28},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/security/hos) "aiY" = (/turf/simulated/floor/plasteel{icon_state = "dark"},/area/security/hos) "aiZ" = (/obj/structure/stool/bed/chair/comfy/black,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/keycard_auth{pixel_x = 0; pixel_y = -24},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/security/hos) @@ -2029,7 +2029,7 @@ "aNa" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aNb" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aNc" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) -"aNd" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10; initialize_directions = 10; level = 1},/obj/machinery/camera{c_tag = "Fitness Rooms North"; dir = 2; network = list("SS13")},/turf/simulated/floor/plasteel{icon_state = "neutral"; dir = 4},/area/crew_quarters/fitness) +"aNd" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10; initialize_directions = 10; level = 1},/obj/machinery/camera{c_tag = "Fitness Rooms North"; dir = 2; network = list("SS13")},/obj/machinery/computer/mob_battle_terminal/red,/turf/simulated/floor/plasteel{icon_state = "neutral"; dir = 4},/area/crew_quarters/fitness) "aNe" = (/obj/machinery/access_button{command = "cycle_interior"; frequency = 1450; master_tag = "bar_maint"; name = "interior access button"; pixel_x = -25; pixel_y = 25; req_access_txt = "13"},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aNf" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'EXTERNAL AIRLOCK'"; icon_state = "space"; layer = 4; name = "EXTERNAL AIRLOCK"; pixel_x = 0; pixel_y = 32},/obj/machinery/atmospherics/unary/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister/air{filled = 0.1},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aNg" = (/obj/structure/rack,/obj/effect/spawner/lootdrop/maintenance{lootcount = 2; name = "2maintenance loot spawner"},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) @@ -2068,7 +2068,7 @@ "aNN" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "eva_inner"; locked = 1; name = "EVA Internal Access"; req_access = null; req_access_txt = "13"},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aNO" = (/obj/effect/decal/cleanable/dirt,/obj/machinery/access_button{command = "cycle_interior"; frequency = 1379; master_tag = "eva_airlock"; name = "interior access button"; pixel_x = 0; pixel_y = 25; req_access_txt = "13"},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aNP" = (/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/unary/portables_connector{dir = 8},/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/plating,/area/maintenance/fpmaint) -"aNQ" = (/obj/item/toy/prize/honk,/turf/simulated/floor/plating,/area/space) +"aNQ" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aNR" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/camera{c_tag = "Mime's Office"; dir = 1; network = list("SS13")},/obj/structure/closet/secure_closet/mime,/turf/simulated/floor/wood,/area/mimeoffice) "aNS" = (/obj/machinery/light,/obj/item/device/radio/intercom{name = "station intercom (General)"; pixel_y = -28},/obj/structure/table/woodentable,/obj/item/weapon/reagent_containers/spray/waterflower,/turf/simulated/floor/wood,/area/mimeoffice) "aNT" = (/obj/structure/cable,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/wood,/area/mimeoffice) @@ -2246,7 +2246,7 @@ "aRj" = (/mob/living/simple_animal/mouse,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aRk" = (/obj/effect/landmark{name = "blobstart"},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aRl" = (/obj/structure/table/glass,/obj/item/weapon/storage/bag/trash,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) -"aRm" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/fpmaint) +"aRm" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aRn" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aRo" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'HIGH VOLTAGE'"; icon_state = "shock"; name = "HIGH VOLTAGE"; pixel_y = -32},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aRp" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint) @@ -2305,7 +2305,7 @@ "aSq" = (/obj/structure/table/glass,/obj/item/weapon/hemostat,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aSr" = (/obj/structure/table/glass,/obj/item/weapon/restraints/handcuffs/cable/zipties,/obj/item/weapon/reagent_containers/blood/OMinus,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aSs" = (/obj/structure/closet/firecloset,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) -"aSt" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/maintenance/fpmaint) +"aSt" = (/turf/simulated/wall/r_wall,/area/maintenance/fpmaint2) "aSu" = (/turf/simulated/wall/r_wall,/area/maintenance/fpmaint) "aSv" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aSw" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint) @@ -2342,7 +2342,7 @@ "aTb" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aTc" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aTd" = (/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/crew_quarters/fitness) -"aTe" = (/turf/simulated/floor/plasteel{icon_state = "neutral"; dir = 4},/area/crew_quarters/fitness) +"aTe" = (/obj/machinery/computer/mob_battle_terminal/blue,/turf/simulated/floor/plasteel{icon_state = "neutral"; dir = 4},/area/crew_quarters/fitness) "aTf" = (/obj/effect/spawner/window/reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/crew_quarters/fitness) "aTg" = (/obj/structure/grille{density = 0; icon_state = "brokengrille"},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aTh" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/table,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/fsmaint2) @@ -2359,7 +2359,7 @@ "aTs" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{icon_state = "warningcorner"; dir = 1},/area/hallway/secondary/entry) "aTt" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plasteel{dir = 4; icon_state = "arrival"},/area/hallway/secondary/entry) "aTu" = (/turf/simulated/wall,/area/hallway/secondary/construction{name = "\improper Garden"}) -"aTv" = (/obj/structure/closet/emcloset,/turf/simulated/floor/plating,/area/maintenance/fpmaint) +"aTv" = (/obj/effect/decal/cleanable/generic,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aTw" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/gateway) "aTx" = (/obj/machinery/gateway{dir = 9},/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 1},/area/gateway) "aTy" = (/obj/machinery/gateway{dir = 1},/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 8},/area/gateway) @@ -2416,10 +2416,10 @@ "aUx" = (/obj/machinery/seed_extractor,/turf/simulated/floor/plasteel,/area/hallway/secondary/construction{name = "\improper Garden"}) "aUy" = (/obj/structure/extinguisher_cabinet{pixel_x = -5; pixel_y = 30},/turf/simulated/floor/plasteel,/area/hallway/secondary/construction{name = "\improper Garden"}) "aUz" = (/obj/structure/sink{pixel_y = 30},/turf/simulated/floor/plasteel,/area/hallway/secondary/construction{name = "\improper Garden"}) -"aUA" = (/obj/effect/decal/cleanable/generic,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/fpmaint) -"aUB" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/plating,/area/maintenance/fpmaint) -"aUC" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/plating,/area/maintenance/fpmaint) -"aUD" = (/obj/machinery/space_heater,/turf/simulated/floor/plating,/area/maintenance/fpmaint) +"aUA" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"aUB" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"aUC" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"aUD" = (/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aUE" = (/turf/simulated/wall/r_wall,/area/security/nuke_storage) "aUF" = (/turf/simulated/floor/plasteel{icon_state = "dark"},/area/gateway) "aUG" = (/obj/machinery/gateway{dir = 8},/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 8},/area/gateway) @@ -2449,7 +2449,7 @@ "aVe" = (/turf/simulated/floor/plasteel,/area/hallway/secondary/construction{name = "\improper Garden"}) "aVf" = (/obj/structure/table/glass,/obj/item/seeds/appleseed,/obj/item/seeds/bananaseed,/obj/item/seeds/cocoapodseed,/obj/item/seeds/grapeseed,/obj/item/seeds/orangeseed,/obj/item/seeds/sugarcaneseed,/obj/item/seeds/wheatseed,/obj/item/seeds/watermelonseed,/obj/item/seeds/towermycelium,/turf/simulated/floor/plasteel,/area/hallway/secondary/construction{name = "\improper Garden"}) "aVg" = (/obj/effect/decal/cleanable/fungus,/turf/simulated/wall,/area/storage/primary) -"aVh" = (/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/maintenance/fpmaint) +"aVh" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "aVi" = (/turf/simulated/wall,/area/storage/primary) "aVj" = (/turf/simulated/wall/r_wall,/area/storage/primary) "aVk" = (/obj/structure/closet/secure_closet/freezer/money,/obj/machinery/ai_status_display{pixel_x = 0; pixel_y = 32},/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 8},/area/security/nuke_storage) @@ -2487,8 +2487,8 @@ "aVQ" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/structure/grille{density = 0; icon_state = "brokengrille"},/obj/structure/window/basic{dir = 4},/obj/structure/window/basic,/turf/simulated/floor/plating{icon_state = "panelscorched"},/area/maintenance/fsmaint2) "aVR" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "maint1"; name = "Blast Door"; opacity = 0},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aVS" = (/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "maint1"; name = "Blast Door"; opacity = 0},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) -"aVT" = (/turf/simulated/floor/plasteel{icon_state = "dark"},/area/maintenance/fsmaint2) -"aVU" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/maintenance/fsmaint2) +"aVT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) +"aVU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "aVV" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_f6"; icon_state = "swall_f6"; dir = 2},/area/shuttle/arrival/station) "aVW" = (/turf/simulated/shuttle/wall{icon_state = "swall12"; dir = 2},/area/shuttle/arrival/station) "aVX" = (/obj/machinery/door/unpowered/shuttle,/turf/simulated/shuttle/floor,/area/shuttle/arrival/station) @@ -2557,11 +2557,11 @@ "aXi" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aXj" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1; level = 1},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aXk" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock/maintenance{name = "Chapel Maintenance"; req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) -"aXl" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/maintenance/fsmaint2) -"aXm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/maintenance/fsmaint2) -"aXn" = (/obj/machinery/mass_driver{dir = 4; id_tag = "chapelgun"},/obj/machinery/door/window{dir = 8; name = "Mass Driver"; req_access_txt = "22"},/turf/simulated/floor/plating{tag = "icon-warnplate (WEST)"; icon_state = "warnplate"; dir = 8},/area/maintenance/fsmaint2) -"aXo" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'EXTERNAL AIRLOCK'"; icon_state = "space"; layer = 4; name = "EXTERNAL AIRLOCK"; pixel_x = 0; pixel_y = 32},/obj/machinery/atmospherics/unary/vent_pump,/turf/simulated/floor/plating{tag = "icon-warnplate (EAST)"; icon_state = "warnplate"; dir = 4},/area/maintenance/fsmaint2) -"aXp" = (/obj/machinery/door/poddoor{id_tag = "chapelgun"; name = "Chapel Launcher Door"; protected = 0},/obj/structure/fans/tiny,/turf/simulated/floor/plating,/area/maintenance/fsmaint2) +"aXl" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'EXTERNAL AIRLOCK'"; icon_state = "space"; layer = 4; name = "EXTERNAL AIRLOCK"; pixel_x = 0; pixel_y = 32},/obj/machinery/atmospherics/unary/vent_pump,/turf/simulated/floor/plating{tag = "icon-warnplate (EAST)"; icon_state = "warnplate"; dir = 4},/area/chapel/main) +"aXm" = (/obj/machinery/mass_driver{dir = 4; id_tag = "chapelgun"},/obj/machinery/door/window{dir = 8; name = "Mass Driver"; req_access_txt = "22"},/turf/simulated/floor/plating{tag = "icon-warnplate (WEST)"; icon_state = "warnplate"; dir = 8},/area/chapel/main) +"aXn" = (/obj/machinery/door/poddoor{id_tag = "chapelgun"; name = "Chapel Launcher Door"; protected = 0},/obj/structure/fans/tiny,/turf/simulated/floor/plating,/area/chapel/main) +"aXo" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/wall,/area/chapel/main) +"aXp" = (/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) "aXq" = (/turf/simulated/shuttle/wall{icon_state = "swall11"; dir = 2},/area/shuttle/arrival/station) "aXr" = (/obj/effect/landmark{name = "HONKsquad"},/obj/structure/closet/walllocker/emerglocker/north,/turf/simulated/shuttle/floor,/area/shuttle/arrival/station) "aXs" = (/turf/simulated/shuttle/floor,/area/shuttle/arrival/station) @@ -2637,7 +2637,7 @@ "aYK" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall,/area/chapel/office) "aYL" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1; initialize_directions = 11; level = 1},/turf/simulated/wall,/area/chapel/office) "aYM" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/driver_button{id_tag = "chapelgun"; name = "Chapel Mass Driver"; pixel_x = 25},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) -"aYN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/wall,/area/maintenance/fsmaint2) +"aYN" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/maintenance/asmaint2) "aYO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/wall,/area/chapel/main) "aYP" = (/turf/simulated/wall,/area/chapel/main) "aYQ" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/chapel/main) @@ -3376,7 +3376,7 @@ "bmV" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/firealarm{dir = 8; pixel_x = -24},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plasteel,/area/hallway/secondary/exit) "bmW" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel,/area/hallway/secondary/exit) "bmX" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor4,/area/shuttle/escape) -"bmY" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"bmY" = (/obj/structure/stool/bed/chair,/turf/simulated/shuttle/floor4,/area/shuttle/escape) "bmZ" = (/obj/effect/decal/warning_stripes/east,/turf/simulated/floor/plasteel,/area/hallway/secondary/exit) "bna" = (/obj/machinery/status_display{pixel_y = 30},/obj/machinery/light/spot{tag = "icon-tube1 (NORTH)"; icon_state = "tube1"; dir = 1},/obj/structure/stool/bed/chair,/turf/simulated/shuttle/floor4,/area/shuttle/escape) "bnb" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "8"},/turf/simulated/floor/plating,/area/shuttle/escape) @@ -4231,9 +4231,9 @@ "bDs" = (/turf/simulated/floor/plasteel{dir = 2; icon_state = "escape"},/area/hallway/secondary/exit) "bDt" = (/obj/structure/closet/emcloset,/obj/item/clothing/mask/breath,/obj/item/clothing/mask/breath,/obj/item/weapon/tank/emergency_oxygen,/obj/item/weapon/tank/emergency_oxygen,/obj/machinery/light,/obj/effect/decal/warning_stripes/southeastcorner,/turf/simulated/floor/plasteel,/area/hallway/secondary/exit) "bDu" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/floor/plasteel,/area/hallway/secondary/exit) -"bDv" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/floor/plating,/area/shuttle/escape) +"bDv" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/shuttle/floor4,/area/shuttle/escape) "bDw" = (/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) -"bDx" = (/obj/structure/stool/bed/chair{dir = 8},/obj/item/device/radio/intercom{dir = 4; name = "station intercom (General)"; pixel_x = 28},/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"bDx" = (/obj/machinery/door/airlock/glass_medical{id_tag = null; name = "Escape Shuttle Infirmary"; req_access_txt = "0"},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "bDy" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plasteel,/area/hallway/secondary/exit) "bDz" = (/turf/simulated/shuttle/floor4,/area/shuttle/escape) "bDA" = (/obj/structure/stool/bed/chair{dir = 4},/obj/machinery/light/spot{tag = "icon-tube1 (WEST)"; icon_state = "tube1"; dir = 8},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/specops) @@ -4368,7 +4368,7 @@ "bFZ" = (/obj/machinery/light{dir = 1},/obj/structure/stool,/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTH)"; icon_state = "whiteblue"; dir = 1},/area/medical/reception) "bGa" = (/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/reception) "bGb" = (/obj/machinery/camera{c_tag = "Medbay Lobby East"; network = list("SS13")},/obj/structure/stool,/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTH)"; icon_state = "whiteblue"; dir = 1},/area/medical/reception) -"bGc" = (/obj/structure/stool,/obj/structure/closet/walllocker/emerglocker/north,/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTH)"; icon_state = "whiteblue"; dir = 1},/area/medical/reception) +"bGc" = (/obj/structure/closet/walllocker/emerglocker/north,/obj/structure/table,/obj/machinery/computer/mob_healer_terminal,/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTH)"; icon_state = "whiteblue"; dir = 1},/area/medical/reception) "bGd" = (/obj/machinery/newscaster{pixel_x = 30},/obj/machinery/alarm{pixel_y = 26},/obj/item/weapon/twohanded/required/kirbyplants,/turf/simulated/floor/plasteel{tag = "icon-whiteblue (NORTHEAST)"; icon_state = "whiteblue"; dir = 5},/area/medical/reception) "bGe" = (/obj/machinery/status_display{layer = 4; pixel_x = 0; pixel_y = 32},/obj/machinery/light{dir = 1},/obj/machinery/bodyscanner,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/medical/exam_room) "bGf" = (/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/item/device/radio/intercom{broadcasting = 0; name = "station intercom (General)"; pixel_y = 25},/obj/machinery/body_scanconsole,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/medical/exam_room) @@ -6998,7 +6998,7 @@ "cED" = (/obj/structure/closet/l3closet,/obj/item/clothing/mask/gas,/turf/simulated/floor/plasteel{icon_state = "blue"; dir = 10},/area/medical/biostorage) "cEE" = (/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/clothing/shoes/magboots,/obj/item/clothing/suit/space/rig/medical,/obj/item/clothing/mask/gas,/obj/item/clothing/head/helmet/space/rig/medical,/turf/simulated/floor/plasteel{dir = 0; icon_state = "blue"},/area/medical/biostorage) "cEF" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/clothing/shoes/magboots,/obj/item/clothing/suit/space/rig/medical,/obj/item/clothing/mask/gas,/obj/item/clothing/head/helmet/space/rig/medical,/turf/simulated/floor/plasteel{icon_state = "blue"; dir = 6},/area/medical/biostorage) -"cEG" = (/obj/structure/lattice,/turf/space,/area/maintenance/asmaint) +"cEG" = (/obj/structure/barricade/wooden,/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cEH" = (/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cEI" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cEJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) @@ -7050,7 +7050,7 @@ "cFD" = (/obj/structure/table/glass,/obj/machinery/computer/med_data/laptop,/obj/machinery/atmospherics/unary/vent_scrubber{dir = 1; on = 1},/obj/machinery/door_control{id = "medprivacyb"; name = "Privacy Shutters"; pixel_y = -30},/turf/simulated/floor/plasteel{dir = 6; icon_state = "whitered"},/area/medical/patient_b) "cFE" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/plasteel{icon_state = "blue"; dir = 8},/area/medical/patients_rooms) "cFF" = (/turf/simulated/wall/r_wall,/area/medical/patients_rooms) -"cFG" = (/turf/space,/area/maintenance/asmaint) +"cFG" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5; level = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cFH" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 4; on = 1},/obj/machinery/light,/obj/effect/decal/warning_stripes/southeastcorner,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cFI" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4; initialize_directions = 11; level = 1},/obj/machinery/atmospherics/unary/vent_pump{dir = 4; on = 1},/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/effect/decal/warning_stripes/south,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cFJ" = (/obj/machinery/alarm{dir = 1; pixel_y = -22},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/light,/obj/effect/decal/warning_stripes/southwestcorner,/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) @@ -8517,7 +8517,7 @@ "dhO" = (/obj/effect/landmark{name = "xeno_spawn"; pixel_x = -1},/turf/simulated/floor/plating,/area/maintenance/asmaint) "dhP" = (/obj/structure/grille{density = 0; icon_state = "brokengrille"},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/maintenance/asmaint) "dhQ" = (/obj/structure/grille,/turf/simulated/floor/plating,/area/maintenance/asmaint) -"dhR" = (/obj/structure/barricade/wooden,/turf/simulated/floor/plating,/area/maintenance/asmaint) +"dhR" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/wall,/area/maintenance/asmaint2) "dhS" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "dhT" = (/obj/machinery/door/airlock/maintenance,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "dhU" = (/obj/structure/rack,/obj/effect/decal/cleanable/cobweb2,/turf/simulated/floor/plating,/area/maintenance/asmaint2) @@ -8544,7 +8544,7 @@ "dip" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/alarm{dir = 8; pixel_x = 25; pixel_y = 0},/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/maintenance/turbine) "diq" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/wall,/area/maintenance/asmaint) "dir" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/wall,/area/maintenance/asmaint) -"dis" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5; level = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint) +"dis" = (/obj/machinery/portable_atmospherics/scrubber,/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) "dit" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4; level = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "diu" = (/obj/structure/stool/bed/chair,/obj/item/weapon/storage/fancy/cigarettes,/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4; level = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "div" = (/obj/structure/stool/bed/chair,/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4; level = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint2) @@ -8926,7 +8926,7 @@ "dpH" = (/obj/machinery/light/small{dir = 8},/obj/machinery/camera{c_tag = "AI Satellite Antechamber South"; dir = 4},/obj/machinery/turretid/stun{control_area = "\improper AI Satellite Atmospherics"; name = "AI Satellite Atmospherics Turret Control"; pixel_x = -28; pixel_y = 0; req_access_txt = "75"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,/turf/simulated/floor/plasteel{dir = 1; icon_state = "darkbluecorners"},/area/turret_protected/aisat_interior) "dpI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{dir = 5; icon_state = "dark"; tag = "icon-vault (NORTHEAST)"},/area/turret_protected/aisat_interior) "dpJ" = (/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,/obj/machinery/light/small{dir = 4; pixel_y = 8},/obj/machinery/turretid/stun{control_area = "\improper AI Satellite Service"; name = "AI Satellite Service Bay Turret Control"; pixel_x = 24; pixel_y = 0; req_access_txt = "75"},/turf/simulated/floor/plasteel{dir = 4; icon_state = "darkbluecorners"},/area/turret_protected/aisat_interior) -"dpK" = (/obj/effect/decal/warning_stripes/north,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light/small{dir = 8},/obj/effect/landmark{name = "JoinLateCyborg"},/obj/item/device/radio/intercom{dir = 8; name = "station intercom (General)"; pixel_x = -28},/turf/simulated/floor/plasteel{dir = 1; icon_state = "darkbluecorners"},/area/aisat/maintenance{name = "\improper AI Satellite Service"}) +"dpK" = (/obj/effect/decal/warning_stripes/north,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light/small{dir = 8},/obj/effect/landmark{name = "JoinLateCyborg"},/obj/item/device/radio/intercom{dir = 8; name = "station intercom (General)"; pixel_x = -28},/obj/machinery/computer/cryopod/robot{pixel_x = -30; pixel_y = 30},/turf/simulated/floor/plasteel{dir = 1; icon_state = "darkbluecorners"},/area/aisat/maintenance{name = "\improper AI Satellite Service"}) "dpL" = (/obj/effect/decal/warning_stripes/north,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{dir = 5; icon_state = "dark"; tag = "icon-vault (NORTHEAST)"},/area/aisat/maintenance{name = "\improper AI Satellite Service"}) "dpM" = (/obj/effect/decal/warning_stripes/northeast,/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 1; scrub_Toxins = 1},/turf/simulated/floor/plasteel{dir = 5; icon_state = "dark"; tag = "icon-vault (NORTHEAST)"},/area/aisat/maintenance{name = "\improper AI Satellite Service"}) "dpN" = (/obj/machinery/light/small{dir = 4; pixel_y = 8},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/structure/rack,/obj/item/weapon/storage/toolbox/electrical{pixel_x = -3; pixel_y = 3},/obj/item/weapon/storage/toolbox/mechanical{pixel_x = 0; pixel_y = 0},/obj/item/device/multitool,/obj/machinery/camera{c_tag = "AI Satellite Service Bay"; dir = 8; network = list("SS13","MiniSat")},/turf/simulated/floor/plating,/area/aisat/maintenance{name = "\improper AI Satellite Service"}) @@ -8955,13 +8955,12 @@ "dqk" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel{dir = 5; icon_state = "dark"; tag = "icon-vault (NORTHEAST)"},/area/aisat/maintenance{name = "\improper AI Satellite Service"}) "dql" = (/obj/machinery/porta_turret{dir = 8},/turf/simulated/floor/plasteel{dir = 8; icon_state = "vault"; tag = "icon-vault (WEST)"},/area/aisat/maintenance{name = "\improper AI Satellite Service"}) "dqm" = (/turf/simulated/wall/r_wall,/area/aisat{name = "\improper AI Satellite Hallway"}) -"dqn" = (/turf/simulated/wall,/area/aisat) +"dqn" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) "dqo" = (/obj/machinery/door/airlock/maintenance_hatch{name = "MiniSat Maintenance"; req_access_txt = "75"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) "dqp" = (/turf/simulated/wall,/area/aisat{name = "\improper AI Satellite Hallway"}) "dqq" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/hatch{name = "MiniSat Chamber Hallway"; req_access_txt = "75"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel{dir = 5; icon_state = "dark"; tag = "icon-vault (NORTHEAST)"},/area/aisat{name = "\improper AI Satellite Hallway"}) "dqr" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/wall/r_wall,/area/aisat{name = "\improper AI Satellite Hallway"}) "dqs" = (/obj/machinery/door/airlock/maintenance_hatch{name = "MiniSat Maintenance"; req_access_txt = "75"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) -"dqt" = (/obj/machinery/portable_atmospherics/scrubber,/turf/simulated/floor/plating,/area/aisat) "dqu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) "dqv" = (/turf/simulated/floor/bluegrid,/area/aisat{name = "\improper AI Satellite Hallway"}) "dqw" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) @@ -8970,11 +8969,8 @@ "dqz" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) "dqA" = (/obj/structure/rack,/obj/item/weapon/crowbar/red,/obj/item/weapon/wrench,/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) "dqB" = (/turf/simulated/floor/plating/airless,/obj/structure/cable,/obj/machinery/power/tracker,/turf/simulated/floor/plating/airless/catwalk{tag = "icon-catwalk1"; icon_state = "catwalk1"},/area/solar/starboard) -"dqC" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/plating,/area/aisat) "dqD" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) "dqE" = (/obj/structure/lattice,/obj/machinery/camera{c_tag = "AI Satellite Exterior West"; dir = 8; network = list("SS13","MiniSat")},/turf/space,/area/aisat) -"dqF" = (/turf/simulated/wall/r_wall,/area/aisat) -"dqG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/aisat) "dqH" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/machinery/porta_turret{dir = 4; installation = /obj/item/weapon/gun/energy/gun; name = "hallway turret"},/turf/simulated/floor/bluegrid,/area/aisat{name = "\improper AI Satellite Hallway"}) "dqI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/unary/vent_scrubber{dir = 4; on = 1},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel{dir = 5; icon_state = "dark"; tag = "icon-vault (NORTHEAST)"},/area/aisat{name = "\improper AI Satellite Hallway"}) "dqJ" = (/obj/effect/spawner/window/reinforced,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4; initialize_directions = 11; level = 1},/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) @@ -8997,7 +8993,6 @@ "dra" = (/obj/structure/cable,/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/turf/simulated/floor/bluegrid,/area/aisat{name = "\improper AI Satellite Hallway"}) "drb" = (/obj/effect/spawner/window/reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5; level = 1},/turf/simulated/floor/plating,/area/aisat{name = "\improper AI Satellite Hallway"}) "drc" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/unary/vent_pump{dir = 8; on = 1},/turf/simulated/floor/plasteel{dir = 5; icon_state = "dark"; tag = "icon-vault (NORTHEAST)"},/area/aisat{name = "\improper AI Satellite Hallway"}) -"drd" = (/turf/simulated/floor/plating,/area/aisat) "dre" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/item/device/radio/intercom/locked/ai_private{broadcasting = 1; listening = 0; pixel_x = -29; pixel_y = -29},/turf/simulated/floor/plasteel{dir = 5; icon_state = "dark"; tag = "icon-vault (NORTHEAST)"},/area/aisat{name = "\improper AI Satellite Hallway"}) "drf" = (/turf/simulated/wall/r_wall,/area/turret_protected/ai) "drg" = (/obj/machinery/status_display,/turf/simulated/wall/r_wall,/area/turret_protected/ai) @@ -9055,10 +9050,9 @@ "dsg" = (/obj/item/flag/nt,/obj/effect/decal/warning_stripes/east,/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 32; pixel_y = 0},/turf/simulated/floor/plasteel,/area/hallway/secondary/exit) "dsh" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = null; name = "Shuttle Cargo Hatch"},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "dsi" = (/obj/structure/noticeboard,/turf/simulated/shuttle/wall{icon_state = "swall12"; dir = 2},/area/shuttle/escape) -"dsj" = (/obj/machinery/door/airlock/glass_security{name = "Escape Shuttle Cell"; req_access_txt = "2"},/obj/machinery/door/airlock/glass_medical{id_tag = null; name = "Escape Shuttle Infirmary"; req_access_txt = "0"},/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"dsj" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape) "dsk" = (/obj/structure/closet/emcloset,/obj/item/clothing/mask/breath,/obj/item/clothing/mask/breath,/obj/item/weapon/tank/emergency_oxygen,/obj/item/weapon/tank/emergency_oxygen,/obj/effect/decal/warning_stripes/southeast,/turf/simulated/floor/plasteel,/area/hallway/secondary/exit) "dsl" = (/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape) -"dsm" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/space,/area/shuttle/escape) "dsn" = (/obj/structure/closet/crate,/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape) "dso" = (/obj/structure/table,/obj/item/weapon/storage/firstaid/o2{layer = 2.8; pixel_x = 4; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = 2; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = -2; pixel_y = 4},/obj/item/bodybag/cryobag{pixel_x = 5},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "dsp" = (/obj/machinery/vending/wallmed1{layer = 3.3; name = "Emergency NanoMed"; pixel_x = 28; pixel_y = 0; req_access_txt = "0"},/obj/structure/stool/bed/roller,/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) @@ -9133,7 +9127,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabTahyahyahyabTaaaacqahNahOahPacsaaaabTahyahyahyabTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahQahQahQahQahQahQahRahSahTahUahVahWabNahXaaaaaaaaaaaaaaaaaaaabaabaabahYafXafXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagZahIagZagZagZagZagZagZagZahZagZagZagZagZagZagZagZahIagZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacqahNahOahPacsaaaaaaaaaaaaaaaaaaaaaacqahNahOahPacsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahQaiaaibaicaidaieaifaigabNabNabNabNabNaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaihaihaihaiiaijaihaihaihaikaikaikaikaikaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahoahIailailailailailailagwaimagwailailailailailailahIahraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahQainaioaipaiqairaisaitabNaiuaivaivaivaivaivaaaaaaaaaaaaaaaaaaaaaaaaaihaiwaixaiyaizaiAaiBaihafXafXafXafXafXaikaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiCaiDaiEaiFaiGaiHagwahZagZahZagZahZagwaiIaiJaiKaiLaiDaiMaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahQaiNaiOaiPaiQaiRaiSaitabNaivaivaiTaiUaiVaivaivaiWaaaaaaaaaaaaaaaaaaaihaiXaiYaiZaiYaiYajaaihajbajbajbajbajbajbafXajcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahJaiDahaahaahaajdagwahaahaahaahaahaagwahaahaajeahaaiDahMaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahQaiNaiOaiPaiQaiRaiSaitabNaivaivaiTaiUaiVaivaivaaaaaaaaaaaaaaaaaaaaaaihaiXaiYaiZaiYaiYajaaihajbajbajbajbajbajbafXajcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahJaiDahaahaahaajdagwahaahaahaahaahaagwahaahaajeahaaiDahMaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahQahQahQahQahQahQajfajgaivaivajhajiajjajkajlaivaivaaaaaaaaaaaaaaaaaaaihajmajnajoajpajqajraihajsajtajuajvajwajxajyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagwajzajAajBajCajDagwajEahaahaahaajFagwajGahaajHajIajzagwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaabaabaababNajJajKaivajLajMajNajOajPajQajRaivaaaaaaaaaaaaaaaaaaaihajSajTajUajVaiYajWaihajXajwajwajwajwajxajyaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagwajYajYagZagZagZagwajZahaahaahaakaagwagZagZagZajYajYagwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaababNahRaigaivakbakcakdajOakeakfakgaivaaaaaaaaaaaaaaaakhaihakiakjakkaklaiYakmaihaknajwakoajwajwajxajyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahsakpakpahnaaaaaaagwakqahaahaahaakragwaaaaaaahsakpakpahnaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -9170,27 +9164,27 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaIIaIJaIIaaaaaaaabaGnaIKaILaHSaHSaIMaHSaGnaIIaIIaGjaGjaINaIOaIaaHSaGnaGnaIIaIIaIIaGnaGnaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaIbaIPaIQaIRaISaITaIgaIUaIVaIWaIjaIXaIlaIYaIZaJaaJbaJcaJdaJeaJfaJgaJhaJiaJjaJkaJlaJmaFFaFHaJnaJoaJpaJqaJraJqaJqaJqaJsaJqaJqaJqaJqaJtaJuaJvaJwaJxaJyaJzaJAaJBaJCaJDaDPaabaJEaJFaJFaJFaJFaJFaJGaabaabaaaaaaaaaaaaaHNaJHaHNaaaaIFaGTaGTaJIaJJaGTaJKaGYaGYaGYaHaaJLaGYaJMaGXaGYaGYaGYaJNaHaaGYaGXaJOaJPaGXaGYaJQaGXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaJRaJSaJTaaaaJUaJVaJWaabaabaIIaHSaIIaaaaaaaabaGnaJXaJYaJZaKaaKbaKcaGnaKdaHSaKeaKfaKgaKhaKhaKhaKhaKhaKhaKhaKhaKiaGnaaaaKjaaaaaaaaaaaaaaaaaaaaaaaaaIbaKkaKlaKmaKnaKoaKpaKqaKraKsaIjaIXaIlaKtaKuaKvaJbaJcaKwaKxaKxaKxaKxaKxaJjaKyaJlaFzaFFaFHaEjaKzaKAaKBaKCaKBaKBaKDaKEaKFaKFaKFaKFaKFaKFaKGaKHaKIaKJaKKaKLaKMaKNaDPaDPaKOaKPaKQaKQaKQaKQaKQaKPaKOaabaaaaaaaaaaaaaHNaKRaKSaaaaIFaKTaKUaKVaKWaGYaGYaGYaHaaGYaHaaKXaGYaGYaGXaGYaKYaKZaKXaIHaGYaGXaLaaLbaGXaGYaLcaGXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLdaLeaLfaLeaLdaLgaLhaLgaLdaabaIIaLiaLjaaaaaaaGnaGnaGnaGnaGnaLkaLlaLmaLnaLoaLpaLpaLqaLraLraLsaLtaGnaHSaGnaGnaGnaLuaGnaaaaabaaaaaaaaaaaaaaaaaaaabaabaIbaLvaLwaLxaLyaLzaLAaLBaLCaKsaIjaIXaIlaLDaLEaLFaJbaLGaLHaKxaLIaKxaLJaLJaJjaKxaJlaFzaFFaLKaEjaLLaKAaLMaLNaLOaLPaLQaLRaLSaLTaLUaLVaLWaLXaLYaLZaMaaMbaMcaMdaMeaMfaMgaMhaKOaKPaKQaKQaKQaKQaKQaKPaKOaabaabaabaabaHNaHNaMiaMjaHNaIFaMkaGYaMlaGYaHbaGYaGXaGXaMmaGXaGXaMnaHaaHaaKXaMoaMpaGYaGXaGYaMqaMqaMqaMqaMqaMqaMqaMqaMqaMraMraMraMraacaMraMraabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMsaLeaMtaLeaMsaLgaMuaLgaMsaGnaIIaMvaMwaIIaIIaGnaHSaHSaHSaHSaHSaHSaHSaLkaLuaGnaGnaGnaGnaGnaMxaGnaGnaHSaMyaGnaMzaLuaGnaGnaGnaaaaaaaaaaaaaaaaMAaMAaMAaMAaMAaMAaMAaMAaIcaLAaMBaMCaMDaMEaMFaMGaMHaMIaMJaMKaJcaMLaKxaMMaMNaMOaMPaMQaMRaJlaFzaFFaFHaEjaAPaMSaMTaLNaLOaLPaMUaMVaMVaMVaMVaMVaMVaMVaMVaMVaMVaMWaMXaMYaMZaNaaNbaNcaNdaKPaKQaKQaKQaKQaKQaKPaKOaKOaKOaaaaaaaHNaGYaNeaNfaJKaHaaMoaKXaMlaGYaNgaGZaNhaIHaGYaGYaGYaGYaNiaGYaGYaMoaNjaGYaMnaGYaMqaNkaNlaNmaMqaNnaNoaNpaMqaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMsaNqaNraNsaMsaNtaNuaNvaNwaNxaHSaNyaNzaNAaMyaNBaHSaGnaGnaGnaGnaGnaGnaGnaLuaGnaNCafOaNDaGnaNEaNFaNGaHSaNBaGnaNAaNHaKhaKiaNIaaaaaaaaaaaaaaaaNJaNKaNLaNMaNNaNOaNPaMAaNQaLAaNRaNSaNTaLAaNUaIlaNVaNWaNXaNYaJcaNZaKxaOaaObaOcaOdaOeaOfaOgaOhaOiaOjaOkaOlaOmaOnaLNaLOaLPaOoaMVaOpaOpaOpaMVaMVaOqaOraOraOsaMWaOtaOuaOvaOvaOwaOxaOyaOzaKQaKQaKQaKQaKQaOAaOBaOCaODaaaaaaaHNaGYaGYaOEaGYaHaaOFaGYaOGaOHaOHaOHaOHaOIaOHaOJaGYaGYaGYaGYaGYaGYaGYaGYaHaaGZaMqaOKaOLaOLaMqaOMaONaOOaMqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMsaLeaMtaLeaMsaLgaMuaLgaMsaGnaIIaMvaMwaIIaIIaGnaHSaHSaHSaHSaHSaHSaHSaLkaLuaGnaGnaGnaGnaGnaMxaGnaGnaHSaMyaGnaMzaLuaGnaGnaGnaaaaaaaaaaaaaaaaMAaMAaMAaMAaMAaMAaMAaMAaMAaLAaMBaMCaMDaMEaMFaMGaMHaMIaMJaMKaJcaMLaKxaMMaMNaMOaMPaMQaMRaJlaFzaFFaFHaEjaAPaMSaMTaLNaLOaLPaMUaMVaMVaMVaMVaMVaMVaMVaMVaMVaMVaMWaMXaMYaMZaNaaNbaNcaNdaKPaKQaKQaKQaKQaKQaKPaKOaKOaKOaaaaaaaHNaGYaNeaNfaJKaHaaMoaKXaMlaGYaNgaGZaNhaIHaGYaGYaGYaGYaNiaGYaGYaMoaNjaGYaMnaGYaMqaNkaNlaNmaMqaNnaNoaNpaMqaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMsaNqaNraNsaMsaNtaNuaNvaNwaNxaHSaNyaNzaNAaMyaNBaHSaGnaGnaGnaGnaGnaGnaGnaLuaGnaNCafOaNDaGnaNEaNFaNGaHSaNBaGnaNAaNHaKhaKiaNIaaaaaaaaaaaaaaaaNJaNKaNLaNMaNNaNOaNPaMAaiWaLAaNRaNSaNTaLAaNUaIlaNVaNWaNXaNYaJcaNZaKxaOaaObaOcaOdaOeaOfaOgaOhaOiaOjaOkaOlaOmaOnaLNaLOaLPaOoaMVaOpaOpaOpaMVaMVaOqaOraOraOsaMWaOtaOuaOvaOvaOwaOxaOyaOzaKQaKQaKQaKQaKQaOAaOBaOCaODaaaaaaaHNaGYaGYaOEaGYaHaaOFaGYaOGaOHaOHaOHaOHaOIaOHaOJaGYaGYaGYaGYaGYaGYaGYaGYaHaaGZaMqaOKaOLaOLaMqaOMaONaOOaMqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMsaOPaOQaORaMsaOPaOQaORaNwaKcaHSaOSaHSaHSaHSaHSaHSaGnaOTaOUaOVaOWaOXaGnaLuaGnafOaOYaNCaOZaPaaPbaGnaPcaGnaGnaGnaGnaPcaLuaNIaaaaHQaHQaHQaHQaPdaNKaPeaPfaPgaPhaPiaPjaMAaLAaPkaPlaPlaPlaPmaPnaPoaPnaPnaPnaPpaPqaPraPsaPtaPtaPtaPtaPuaPvaPwaFFaPxaEjaAPaPyaPzaLNaLOaLPaMUaOpaPAaPAaPBaOpaMVaPCaPDaPDaPEaPFaOtaPGaPHaPIaPJaMVaPKaODaKQaKQaKQaKQaKQaODaPLaPMaODaabaabaGXaGYaGYaHaaHaaHaaHPaHPaGXaGXaGXaHaaHaaHaaGXaPNaPOaGXaHaaHaaGXaHaaHaaGXaGXaPPaPQaPRaPSaPTaPUaPVaOKaPWaMqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPXaPYaLdaMsaPZaQaaLdaMsaPZaQaaLdaGnaLkaGnaGnaGnaGnaGnaHSaGnaHSaQbaQcaHSaHSaGnaLuaGnaQdaabaQdaGnaJYaPbaGnaQeaQfaGnaNAaKcaGnaIXaMAaMAaQgaQgaQgaQgaQgaQgaQgaQgaQgaPiaPiaPjaQhaQiaQjaQkaQlaQmaQnaQoaQpaQpaQpaQpaQqaQraQsaQtaQuaQpaQpaQvaQvaQwaQxaQyaQzaQAaQBaPyaQCaQDaQDaLPaMUaOpaPAaQEaQFaOpaMVaPCaPDaPDaPEaQGaOtaPGaPIaPIaPJaMVaPKaODaKQaKQaKQaKQaKQaODaQHaPMaODaaaaaaaGXaQIaGYaGYaQJaHaaQKaHOaQLaQMaHbaGXaOFaHbaGXaQNaGYaGXaQOaGYaGXaQPaQQaQRaOHaQSaOHaQTaQUaQVaQWaQXaQYaQZaMqaMraMraacaacaMraMraMraMraabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaRbaOQaRbaRcaRcaRcaRdaRcaRcaRcaReaRfaRgaRgaRgaRgaRhaGnaHSaGnaRiaRjaRkaHSaRlaPcaLuaGnaGnaGnaGnaGnaGnaPcaGnaHSaRkaLkaHSaHSaPiaRmaRnaRoaRpaRpaRpaRpaRqaRpaRpaRraRsaRoaRtaRuaRuaRuaRuaRuaRuaRuaRvaRwaRwaRwaRwaRxaRyaRwaRzaRwaRAaRxaRwaRwaRwaRwaRBaRCaRDaREaRFaOmaRGaRHaQDaRIaMUaOpaRJaRKaRLaOpaMVaRMaRNaRNaROaMWaOtaRPaRQaRQaRRaMVaRSaRTaKQaKQaKQaKQaKQaRUaRVaRWaODaaaaaaaGXaGYaGYaGYaGYaGYaGYaQRaOHaOHaOHaOHaOHaOHaOHaKVaGYaGYaGYaGYaMnaGYaGYaMlaGYaRXaRYaRZaSaaSbaOLaOLaOLaScaMqaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPYaPYaSdaSeaSfaSgaShaSiaSjaSkaSlaSjaSmaSnaSjaSjaSoaGnaHSaGnaSpaHSaHSaSqaSraGnaNHaKiaHSaHSaHSaHSaHSaHSaPcaSsaHSaGnaNxaNxaMAaStaMAaSuaSvaSwaSwaSwaSxaSwaSwaSwaSyaSuaSzaSAaSAaSAaSAaSAaSAaSAaPiaRwaSBaSCaSDaSEaSFaSGaSHaSIaSJaSKaSLaSCaSMaRwaSNaFFaSOaEjaSPaPyaSQaSRaSRaSSaSTaSUaSVaSWaSWaSXaSYaSZaSXaSYaSYaTaaTbaTcaMVaMVaTdaMVaTeaTfaKQaKQaKQaKQaKQaTfaKOaKOaKOaGXaGXaGXaHbaHaaHaaIHaGXaGXaMlaHaaGXaTgaHaaGXaIHaGXaMlaQIaHaaGXaIHaGXaGYaQIaMlaGYaThaMqaTiaQUaTjaTkaTlaQUaTmaMqaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaMsaSdaTnaSdaToaSfaSfaTpaSdaTnaSdaTqaTraTsaTtaGnaHSaPcaPcaGnaGnaGnaTuaTuaTuaIkaTuaTuaTuaTuaTuaPiaMAaMAaMAaMAaMAaMAaMAaStaTvaSuaaaaabaaaaabaaaaabaaaaabaaaaSuaSzaSAaTwaTxaTyaTzaTAaSAaPiaRwaTBaTBaTCaTDaTEaTFaTGaTFaTHaTIaTJaTBaTBaRwaSNaFFaTKaEjaSPaPyaPzaLNaLOaLPaMUaTLaTMaTNaTOaTPaTPaTQaTRaTPaTRaTSaTTaTUaTVaTWaTXaTYaKOaTfaKQaKQaKQaKQaKQaTfaGXaLcaGYaTZaUaaHaaGXaHaaLcaGYaGXaLcaMlaGXaUbaGYaGXaUcaGYaHaaUdaUeaGXaUfaGYaHaaIHaIHaMlaIHaUgaMqaUhaQUaUiaUjaUiaQUaUkaMqaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaUlaLdaUmaOQaSdaUnaUoaUpaUqaSdaOQaUraPYaLdaUsaUtaGnaHSaHSaHSaHSaHSaHSaTuaUuaUvaUwaUxaUyaUzaUuaTuaUAaUBaRpaRpaRpaRpaRpaRpaUCaUDaSuaabaUEaUEaUEaUEaUEaUEaUEaabaSuaSzaSAaUFaUGaUHaUIaUFaSAaPiaRwaUJaUJaUJaUKaULaSCaUMaSCaULaUNaUJaUJaUJaRwaSNaFFaUOaEjaSPaPyaOnaLNaLOaLPaOoaUPaUQaUQaUQaUQaUQaUQaUQaURaUQaUSaUSaUSaUSaUSaUTaGXaKOaTfaKQaKQaKQaKQaKQaTfaGXaGXaGYaUUaUaaHaaUVaGXaGYaGYaGXaGYaMlaHaaGYaGYaGXaGYaGYaHaaMlaGZaGXaGYaGYaHaaUWaGYaMlaGYaUXaUYaUYaMqaMqaMqaMqaMqaMqaMqaMraMraMraMraMraabaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPYaTnaSdaSdaSdaSdaSdaSdaTnaPYaUZaLdaVaaVbaVcaVcaVcaVcaVcaVcaVdaTuaUuaVeaUwaVfaVeaVeaUuaTuaVgaVhaViaViaViaViaViaViaViaViaVjaaaaUEaVkaVlaVmaVnaVoaUEaaaaSuaSzaSAaVpaVqaVraVsaUFaSAaPiaRwaVtaVtaTCaVuaVvaTFaTGaTFaVvaVwaVxaTBaTBaRwaSNaFFaSOaEjaVyaKAaVzaLNaLOaLPaMUaUPaUQaVAaVBaVCaVCaUQaVDaVEaVFaUSaVGaVHaVIaUSaVJaGXaaaaVKaVLaVLaVLaVLaVLaVMaaaaGXaGYaVNaVOaHaaHaaGXaGXaHaaHaaVPaVQaHaaGXaHPaGXaGXaHaaHaaVRaVSaGXaGXaGXaQLaUWaGYaMlaGYaUXaHOaHbaOFaGXaVTaVUaVTaGXaGXaGXaabaabaabaabaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVVaVWaVXaVWaVWaVYaVZaVWaVWaVXaWaaWbaLdaToaWcaVcaWdaWeaWfaWgaWhaWiaTuaUuaVeaUwaWjaVeaVeaUuaTuaWkaWlaWmaWnaWoaWpaWqaWraWsaWtaVjaabaUEaWuaWvaWwaWxaWyaUEaabaSuaSzaSAaWzaWAaWBaWCaWDaSAaPiaRwaSBaSCaWEaWFaULaSCaWGaSCaULaWHaWIaSCaSMaRwaSNaFFaWJaEjaSPaMSaMTaLNaLOaLPaWKaWLaUQaWMaVEaVEaVEaWNaWOaWPaWQaUSaWRaWSaWTaWUaWVaHPaaaaaaaaaaaaaaaaaaaaaaaaaaaaGXaWWaWXaWYaWZaXaaGXaNgaGYaQIaMlaGYaGXaaaaGXaGYaGYaGYaGYaMlaXbaXcaXdaXdaXdaXdaXeaXfaXgaXhaXiaXjaXiaXkaXlaXlaXmaXnaXoaXpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVVaWaaVWaXqaXraXsaXtaXuaXvaXwaXxaXyaXzaXAaXBaSdaToaXCaVcaXDaXEaXFaXGaXFaXHaTuaXIaVeaXJaXKaXLaXKaXMaXNaXOaXPaXQaXQaXQaXQaXQaXQaXRaXSaVjaaaaUEaXTaWvaXUaWxaXVaUEaaaaSuaSzaSAaXWaXXaXYaXZaYaaSAaPiaRwaYbaYbaTCaYcaVvaTFaYdaTFaVvaYeaTJaYfaYfaRwaYgaIraYhaEjaSPaMSaYiaYiaYiaYiaYjaYkaYlaYmaYnaYoaYoaYoaYpaYoaYqaYraYsaYtaYuaYraYvaYwaHPaGXaGXaGXaGXaGXaGXaGXaGXaGXaGXaGXaGXaYxaGXaGXaGXaGXaGYaMlaWWaHNaabaHNaGYaYyaYzaYAaYBaYCaYDaYEaYEaYEaYEaYFaYGaYHaYIaYJaYKaYJaYLaYJaYJaYMaYNaYOaYPaYQaYRaYSaYSaYSaYSaYSaYSaYSaYSaYSafXajcaaaaaaaaaaaaaaaaaaaaaaYTaYUaYVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPXaPYaLdaMsaPZaQaaLdaMsaPZaQaaLdaGnaLkaGnaGnaGnaGnaGnaHSaGnaHSaQbaQcaHSaHSaGnaLuaGnaQdaabaQdaGnaJYaPbaGnaQeaQfaGnaNAaKcaGnaLuaMAaMAaQgaQgaQgaQgaQgaQgaQgaQgaQgaPiaPiaPjaQhaQiaQjaQkaQlaQmaQnaQoaQpaQpaQpaQpaQqaQraQsaQtaQuaQpaQpaQvaQvaQwaQxaQyaQzaQAaQBaPyaQCaQDaQDaLPaMUaOpaPAaQEaQFaOpaMVaPCaPDaPDaPEaQGaOtaPGaPIaPIaPJaMVaPKaODaKQaKQaKQaKQaKQaODaQHaPMaODaaaaaaaGXaQIaGYaGYaQJaHaaQKaHOaQLaQMaHbaGXaOFaHbaGXaQNaGYaGXaQOaGYaGXaQPaQQaQRaOHaQSaOHaQTaQUaQVaQWaQXaQYaQZaMqaMraMraacaacaMraMraMraMraabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaRaaRbaOQaRbaRcaRcaRcaRdaRcaRcaRcaReaRfaRgaRgaRgaRgaRhaGnaHSaGnaRiaRjaRkaHSaRlaPcaLuaGnaGnaGnaGnaGnaGnaPcaGnaHSaRkaLkaHSaHSaHSaNQaRnaRoaRpaRpaRpaRpaRqaRpaRpaRraRsaRoaRtaRuaRuaRuaRuaRuaRuaRuaRvaRwaRwaRwaRwaRxaRyaRwaRzaRwaRAaRxaRwaRwaRwaRwaRBaRCaRDaREaRFaOmaRGaRHaQDaRIaMUaOpaRJaRKaRLaOpaMVaRMaRNaRNaROaMWaOtaRPaRQaRQaRRaMVaRSaRTaKQaKQaKQaKQaKQaRUaRVaRWaODaaaaaaaGXaGYaGYaGYaGYaGYaGYaQRaOHaOHaOHaOHaOHaOHaOHaKVaGYaGYaGYaGYaMnaGYaGYaMlaGYaRXaRYaRZaSaaSbaOLaOLaOLaScaMqaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPYaPYaSdaSeaSfaSgaShaSiaSjaSkaSlaSjaSmaSnaSjaSjaSoaGnaHSaGnaSpaHSaHSaSqaSraGnaNHaKiaHSaHSaHSaHSaHSaHSaPcaSsaHSaGnaNxaNxaGnaRmaMAaSuaSvaSwaSwaSwaSxaSwaSwaSwaSyaSuaSzaSAaSAaSAaSAaSAaSAaSAaPiaRwaSBaSCaSDaSEaSFaSGaSHaSIaSJaSKaSLaSCaSMaRwaSNaFFaSOaEjaSPaPyaSQaSRaSRaSSaSTaSUaSVaSWaSWaSXaSYaSZaSXaSYaSYaTaaTbaTcaMVaMVaTdaMVaTeaTfaKQaKQaKQaKQaKQaTfaKOaKOaKOaGXaGXaGXaHbaHaaHaaIHaGXaGXaMlaHaaGXaTgaHaaGXaIHaGXaMlaQIaHaaGXaIHaGXaGYaQIaMlaGYaThaMqaTiaQUaTjaTkaTlaQUaTmaMqaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaMsaSdaTnaSdaToaSfaSfaTpaSdaTnaSdaTqaTraTsaTtaGnaHSaPcaPcaGnaGnaGnaTuaTuaTuaIkaTuaTuaTuaTuaTuaHSaGnaGnaGnaGnaGnaGnaGnaRmaKdaStaaaaabaaaaabaaaaabaaaaabaaaaSuaSzaSAaTwaTxaTyaTzaTAaSAaPiaRwaTBaTBaTCaTDaTEaTFaTGaTFaTHaTIaTJaTBaTBaRwaSNaFFaTKaEjaSPaPyaPzaLNaLOaLPaMUaTLaTMaTNaTOaTPaTPaTQaTRaTPaTRaTSaTTaTUaTVaTWaTXaTYaKOaTfaKQaKQaKQaKQaKQaTfaGXaLcaGYaTZaUaaHaaGXaHaaLcaGYaGXaLcaMlaGXaUbaGYaGXaUcaGYaHaaUdaUeaGXaUfaGYaHaaIHaIHaMlaIHaUgaMqaUhaQUaUiaUjaUiaQUaUkaMqaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaUlaLdaUmaOQaSdaUnaUoaUpaUqaSdaOQaUraPYaLdaUsaUtaGnaHSaHSaHSaHSaHSaHSaTuaUuaUvaUwaUxaUyaUzaUuaTuaTvaUBaUAaUAaUAaUAaUAaUAaUCaNxaStaabaUEaUEaUEaUEaUEaUEaUEaabaSuaSzaSAaUFaUGaUHaUIaUFaSAaPiaRwaUJaUJaUJaUKaULaSCaUMaSCaULaUNaUJaUJaUJaRwaSNaFFaUOaEjaSPaPyaOnaLNaLOaLPaOoaUPaUQaUQaUQaUQaUQaUQaUQaURaUQaUSaUSaUSaUSaUSaUTaGXaKOaTfaKQaKQaKQaKQaKQaTfaGXaGXaGYaUUaUaaHaaUVaGXaGYaGYaGXaGYaMlaHaaGYaGYaGXaGYaGYaHaaMlaGZaGXaGYaGYaHaaUWaGYaMlaGYaUXaUYaUYaMqaMqaMqaMqaMqaMqaMqaMraMraMraMraMraabaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPYaTnaSdaSdaSdaSdaSdaSdaTnaPYaUZaLdaVaaVbaVcaVcaVcaVcaVcaVcaVdaTuaUuaVeaUwaVfaVeaVeaUuaTuaVgaUDaViaViaViaViaViaViaViaViaVjaaaaUEaVkaVlaVmaVnaVoaUEaaaaSuaSzaSAaVpaVqaVraVsaUFaSAaPiaRwaVtaVtaTCaVuaVvaTFaTGaTFaVvaVwaVxaTBaTBaRwaSNaFFaSOaEjaVyaKAaVzaLNaLOaLPaMUaUPaUQaVAaVBaVCaVCaUQaVDaVEaVFaUSaVGaVHaVIaUSaVJaGXaaaaVKaVLaVLaVLaVLaVLaVMaaaaGXaGYaVNaVOaHaaHaaGXaGXaHaaHaaVPaVQaHaaGXaHPaGXaGXaHaaHaaVRaVSaGXaGXaGXaQLaUWaGYaMlaGYaUXaHOaHbaOFaYPbcDaVhbcDaYPaYPaYPaabaabaabaabaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVVaVWaVXaVWaVWaVYaVZaVWaVWaVXaWaaWbaLdaToaWcaVcaWdaWeaWfaWgaWhaWiaTuaUuaVeaUwaWjaVeaVeaUuaTuaWkaWlaWmaWnaWoaWpaWqaWraWsaWtaVjaabaUEaWuaWvaWwaWxaWyaUEaabaSuaSzaSAaWzaWAaWBaWCaWDaSAaPiaRwaSBaSCaWEaWFaULaSCaWGaSCaULaWHaWIaSCaSMaRwaSNaFFaWJaEjaSPaMSaMTaLNaLOaLPaWKaWLaUQaWMaVEaVEaVEaWNaWOaWPaWQaUSaWRaWSaWTaWUaWVaHPaaaaaaaaaaaaaaaaaaaaaaaaaaaaGXaWWaWXaWYaWZaXaaGXaNgaGYaQIaMlaGYaGXaaaaGXaGYaGYaGYaGYaMlaXbaXcaXdaXdaXdaXdaXeaXfaXgaXhaXiaXjaXiaXkaVTaVTaVUaXmaXlaXnaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVVaWaaVWaXqaXraXsaXtaXuaXvaXwaXxaXyaXzaXAaXBaSdaToaXCaVcaXDaXEaXFaXGaXFaXHaTuaXIaVeaXJaXKaXLaXKaXMaXNaXOaXPaXQaXQaXQaXQaXQaXQaXRaXSaVjaaaaUEaXTaWvaXUaWxaXVaUEaaaaSuaSzaSAaXWaXXaXYaXZaYaaSAaPiaRwaYbaYbaTCaYcaVvaTFaYdaTFaVvaYeaTJaYfaYfaRwaYgaIraYhaEjaSPaMSaYiaYiaYiaYiaYjaYkaYlaYmaYnaYoaYoaYoaYpaYoaYqaYraYsaYtaYuaYraYvaYwaHPaGXaGXaGXaGXaGXaGXaGXaGXaGXaGXaGXaGXaYxaGXaGXaGXaGXaGYaMlaWWaHNaabaHNaGYaYyaYzaYAaYBaYCaYDaYEaYEaYEaYEaYFaYGaYHaYIaYJaYKaYJaYLaYJaYJaYMaXoaYOaYPaYQaYRaYSaYSaYSaYSaYSaYSaYSaYSaYSafXajcaaaaaaaaaaaaaaaaaaaaaaYTaYUaYVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaXAaYWaYXaYYaXzaYZaXsaYZaXsaYZaXsaYZaXzaZaaZbaSdaToaZcaVcaZdaZeaZfaZgaZhaZiaTuaZjaVeaZkaZlaZmaZnaZoaTuaZpaZqaXQaXQaXQaXQaXQaXQaXRaZraVjaabaUEaZsaZtaZuaZvaZwaUEaabaSuaSzaSAaZxaZyaZzaZAaZBaSAaPiaRwaUJaUJaUJaZCaULaSCaUMaSCaULaZDaUJaUJaUJaRwaZEaZFaZGaEjaVyaZHaZIaZIaZIaZJaZKaZLaZMaZNaZOaZMaZPaZQaZRaZMaZSaZTaZUaZVaZWaUSaZXaZYaZZbaabaaaZYbabbacbacbacbacbacbadbaebacbafbagbahbaibajbakbalbambanbaobanbapbaqaGYaGXbarbasbatbaubavbawbaxbaybazbaAbazbaBbaCbaDbaEbaFbaGbaHbaIbaJbaKbaLaYPbaMbaNbaObaPbaQbaRbaSbaTbaUbaVaaaaaaaaaaaaaaaaaaaaaaYTbaWbaXbaYaYVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaZaXsaXsaVXaXzaYZaXsaYZbbaaYZaXsaYZaXzaZaaZbaSdaTobbbaVcaVcbbcbbdbbebbdaVcaTuaTuaTuaTubbfbbgbbhbbiaTubbjbbkbblaXQaXQbbmaXQbbnbbobbpaVjaaaaUEaUEbbqbbrbbqaUEaUEaaaaSuaSzaSAbbsbbtbbuaZAbbvaSAaPiaRwaSBaSCbbwaWFaULaSCaUMaSCaULaWHbbxaRwaRwaRwbbybbzbbAbbBbbCbbDatGatGbbEbbFbbGbbHaUQbbIaVEaUQbbJaUQbbKaUQbbLbbMbbNbbObbPbbQbbRbbSbbTbbUbbVbbWbbXbbVbbVbbYbbVbbSbbZbbSaXjbcabbSbcbbccbcdbcebcfbcgbchbcibcjbckbclaXibcmbcnbcobcpbcqbcrbcsbctbaybcubcvbazbcwbcxbcybczbaFbcAbcBbcCbcDbcEbcFaYPbcGbcHbcHbcIbaTbaTbaTbaTbaUbaVaaaaaaaaaaaaaaaaaaaYTbaWbcJbcKbcLbaYaYVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaXAbcMbcNaYYaXzaYZaXsaYZaXsaYZaXsaYZaXzaZaaZbaSdaTobcObcPbcQbcRbcSbcSaSfbcTbcUbcVbcWbcXbcYbcZaVebdaaTubdbbdcbddbdebdfbdgbdhbdibdjbdkaVjaaaaabaaabdlbdmbdlaaaaabaaaaSuaSzaSAbdnbdobdpbdqbdraSAaPiaRwbdsbdtaTCbdubdvaTFbdwaTFbdxbdybdzaRwbdAbdBbdCbdDbdEbdFbdGbdHaaaaaabbEbdIbdJbdKaUQbdLbdMaVEaVEbdNaVEaVEaVEbdOaUSbdPaUSbdQbdRaUSbdSaUSbdTbdUbdVbdWbdXbdYbdTbdZbeabebbecbebbebbebbebbedbeebebbefbegbehbeibebbejaGYbaubekbcpbelbembenbeobepbeqberbesbazbetbeubevbewbexbcAbcBbcCbcDbaKbeyaYPbezbcHbcHbcIbaTbaTbaTbaTbaUbaVaaaaaaaaaaaaaaaaaaaYUbeAbeBbeCbeBbeDaYUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabeEbeFaVWaXqaXzaXsbeGbeHaXsaXsbeIbeGaXzaXAbeJaSdaTobeKbeLbeMbeNbeMbeMbeMbeMbeMbeOaSfaTubePbeQbePaTuaTubeRbeSbeRaViaViaViaVibeRbeTbeUaVjbeVbeWbeWbeXbeYbeXbeWbeWbeZaSubfaaSAbfbaSAbfcbfdbfeaSAbffaRwaRwaRwaRwbfgbfhbfibfjbfibfhbfgaRwaRwbfkbdDbdDbdDbdDbflbfmbfnbfobfpbbEbfqbdJbfraUQaUQaUQaUQaUQaUQaUQaUSaUSbdObfsbftbfubfvbfwbfxbfybfzbdTbfAbfBbfCbfDbfEbdTbfFbfGbfHbfIbfHbfJbfKbfLbfMbfNbfObfPbfQbfRbfSbebbfTbfUbfVbfWbfXbelbfYbfZbeobgabazbgbbgcbgdbgebgfbczbczbazbazbcBbcCbcDbcEbggaYPbghbgibgjbgkbglbgmbaTbaTbgnbaVaaaaaaaaaaaaaaaaYTbaWbgobeCbeCbeCbgpbaYaYVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabeEaVWaVXaVWaVWaVYaVZaVWaVWaVXbeFbgqaLdbgrbeKaPYbgsbgsbgtbgsbguaMsbgvbgwaSfbgxbgybgzbgzbgAbgBbgzbgCbgzbgzbgzbgDbgzbgzbgEbgFbgGbgHbgIbgJbgHbgKbgHbgHbgHbgHbgLbgMbgNbgzbgzbgObgPbgQbgRbgSbgTbgUbgVbgWbgXbgXbgXbgXbgXbgXbgXbgYbgZbhabhbbhcbhdbhebhfbhgbhhbdDbdDbhibhjbhkbhjbhkbhlbhmbhnbhobhpbhqaUSbhrbhsbhtbhubhvbhvbhwbhxbhybhzbdTbhAbhBbhCbhCbhDbdTbhEbhFbhGbhHbhIbhIbhJbhKbhLbhMbhNbhObhPbhQbhRbebbejaTgbaubhSbhTbhTbhUbhVbhTbhWbazbhXbhYbazbhZbiabczbibbazbicbidbiebcDaYPaYPaYPbifbigbihbiibigbigbigbigaYSafXajcaaaaaaaaaaaabijbikbilbeCbeCbimbinbeCbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPYbioaSdaSdaSdaSdaSdaSdbioaPYaUZaLdbipbiqaPYbirbisbitbitbiuaMsbivbgwbiwbixbgybiybizbiAbiBbiBbiCbiDbiDbiDbiEbiFbiFbiGbiHbiIbiBbiBbiJbiFbiKbiLbiMbiMbiNbiObiPbiQbiQbiQbiRbgPbgQbgRbgSbgSbgSbgSbiSbgSbgSbgSbgSbgSbgSbiTbiUbiVbiWbiXbiYbiZbjabjbbjcbiVbiVbiVbjdbjebjebjebjfbhqbhqbhqbjgbjhbhqaUSbjibjjbhvbhvbjkbhvbjlbjmbhybjnbdTbjobjpbjqbjrbjsbdTbjtbjubjvbjwbjxbjybebbebbjzbjAbebbebbjBbjCbjBbebbejaGYbaubjDbcpbcpbcpbjEbcpbjFbazbazbazbazbazbazbazbjGbazbcDbcDbcCbcDbjHbjIaYPbjJbjNbjLblwbjKbjObjPbjQbjRaaaaaaaaaaaaaYTbjSbjTbjSbjSbjSbjUbjSbjVbjSbjTbjSaYVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaUlaLdaPYaOQaSdbjWbjXbjYbjZaSdaOQaPYaPYaLdbkabeKaPYbkbbkcbitbitbiuaMsbkdbgwaSfbixbgybgzbkebkfbkgbkgbkhbkibkjbkgbkkbkgbklbkgbkmbknbkgbkgbkgbkgbkgbkobkpbkgbkqbkrbksbktbgzbgzbkubkvbkwbkxbkybkzbkybkAbkBbkAbkAbkAbkAbkAbkAbkCbkDbkEbkEbkEbkEbkFbkEbkGbkHbkEbkEbkIbkJbkKbkKbkKbkKbkKbkKbkKbkLbhqbhqaUSbkMbkNbkObkPbkPbkQbkRbjmbhybkSbdTbdTbdTbdTbdTbkTbdTbkUbkVbkWbkXbfHbkYbebbkZblablbblcbldbleblfblgbebbejaQLbaublhblibcpbljblkbcpbllbllbaublmblnbloaYPblpblqblrbcDbcDblsbltaYPbluaYPblvbjKbjLblxblybjKbjKblzbjRaaaaaaaaaaaabijbmXbnabmYblDblAbeCblCblDblAblBblCbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaMsaPYbioaSdaToaSfaSfaTpaSdbioaSdblEblFblGblHaPYblIblIbgtblIbguaMsblJbgwaSfaMsblKblKblLblMblMblMblMblMblMblNblOblMblMblMblMblMblMblPblQblRblRblSblRblTblUblVblTblTblWblXblYblKblZblZbmabmabmabmbbmbbmbbmbbmbbmbbmbbmbbmcbmdbmdbmebmdbmfbmfbmfbmfbmgbmhbmfbmcbmibmibmibmibmibmibmibmibmjbmjbmjaUSbmkbmlbmmbmmbmmbmmbmnbmobmpbmqbmrbmsbmtbmubmvbmwbdTbdTbmxbmybmzbmybmybebbmAbmBbmCbmDbmDbmDbmEbmFbebbmGbmHbaubmIbcpbljbljblkbljbcpbmJbaubmKbmLbmMaYPbcDbmNbmObmPbmPbmQbmRbmSbmTbmUbmVbmWboObzpbjMbjKbjKblzbjRbjRbjRbjRbjRbijbBTbDzbDzbBVbDwbeCblCbnbblAbeCbncbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabndbneaSfbnfbngbnhbnibnjbnkbnibnlbnmbnibnibnnbnobnpbnqbnrbnrbnrbnsbnrbntbnuaMsbnvbnwbnxblMbnybnzbnAbnBbnCbnDbnEbnFbnGbnHbnIbnJblMbnKbnLblRbnMbnNbnOblTbnPbnQbnRblTbnSbnTbnUbnSbnSbnSbnVbgSbnWbmbaaaaaaaaaaaaaaaaaaaaabmcbnXbnYbnZboabobbocbodboebofbogbohbmcaaaaaaaaaaaaaaaaaaaaabmiboibhqbojaUSbokbmlbmqbmqbmqbmqbmqbolbombmqbmqbmqbonbooboobopboqborbosbotboubovbowbebboxboybozboAboAboBboCboDbebbejaGYbauboEboFbcpbljblkbcpboGboGbaubauboHbauaYPboIblqbltboJboJboKbltaYPaYPaYPboLbjKbEFbDubjMbjKbjKbmZbAMbrKbrMbrMbrKbDvbDzbGJbDxbnbblAbeCblCbnbblAbeCblCaYUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabndboPboQboPboPboPboPboPboPboQboPboPboRaSfboSboTboUaSfboVaSfboWboXboYboZbpaaMsbnwbnwbpbblMbpcbnDbnDbnDbnDbnDbnEbpdbnDbnDbnDbpeblMbnKbpfblRbpgbphbpiblTbpjbpkbplblTbpmbpnbpobppbpqbnTbnVbgSbnWbmbaaaaaaaaaaaabmcbmcbmcbmcbprbpsbptbpubpvbpwbpxbpybpzbpAbpBbmcbmcbmcbmcaaaaaaaaaaaabmiboibhqbpCbpDbpEbpFbpGbpHbpEbpIbpJbpKbpLbpMbpNbmqbpObpPboobpQbpRboobpSbpTbpUbpVboobpWbpXbpYbozboAboAboBbpZbqabebbejaTgbaubmIbcpbljbljblkbljbcpbcpbqbbqcbcpbqdaYPbqebqfbqgboJboJbqhbqgbqiaYPbqjbqkbjKbDybDybEHbEIbDybDybjRbqnbjRbjRbjRbEJbjSbjSbjSbqoblAbeCblCbqoblAbeCblCbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaUlaLdaPYaOQaSdbjWbjXbjYbjZaSdaOQaPYaPYaLdbkabeKaPYbkbbkcbitbitbiuaMsbkdbgwaSfbixbgybgzbkebkfbkgbkgbkhbkibkjbkgbkkbkgbklbkgbkmbknbkgbkgbkgbkgbkgbkobkpbkgbkqbkrbksbktbgzbgzbkubkvbkwbkxbkybkzbkybkAbkBbkAbkAbkAbkAbkAbkAbkCbkDbkEbkEbkEbkEbkFbkEbkGbkHbkEbkEbkIbkJbkKbkKbkKbkKbkKbkKbkKbkLbhqbhqaUSbkMbkNbkObkPbkPbkQbkRbjmbhybkSbdTbdTbdTbdTbdTbkTbdTbkUbkVbkWbkXbfHbkYbebbkZblablbblcbldbleblfblgbebbejaQLbaublhblibcpbljblkbcpbllbllbaublmblnbloaYPblpblqblrbcDbcDblsbltaYPbluaYPblvbjKbjLblxblybjKbjKblzbjRaaaaaaaaaaaabijbmXbnabmYbmYblDbeCblCblDblAblBblCbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaMsaPYbioaSdaToaSfaSfaTpaSdbioaSdblEblFblGblHaPYblIblIbgtblIbguaMsblJbgwaSfaMsblKblKblLblMblMblMblMblMblMblNblOblMblMblMblMblMblMblPblQblRblRblSblRblTblUblVblTblTblWblXblYblKblZblZbmabmabmabmbbmbbmbbmbbmbbmbbmbbmbbmcbmdbmdbmebmdbmfbmfbmfbmfbmgbmhbmfbmcbmibmibmibmibmibmibmibmibmjbmjbmjaUSbmkbmlbmmbmmbmmbmmbmnbmobmpbmqbmrbmsbmtbmubmvbmwbdTbdTbmxbmybmzbmybmybebbmAbmBbmCbmDbmDbmDbmEbmFbebbmGbmHbaubmIbcpbljbljblkbljbcpbmJbaubmKbmLbmMaYPbcDbmNbmObmPbmPbmQbmRbmSbmTbmUbmVbmWboObzpbjMbjKbjKblzbjRbjRbjRbjRbjRbijbBTbDzbDzbDzbBVbeCblCbnbblAbeCbncbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabndbneaSfbnfbngbnhbnibnjbnkbnibnlbnmbnibnibnnbnobnpbnqbnrbnrbnrbnsbnrbntbnuaMsbnvbnwbnxblMbnybnzbnAbnBbnCbnDbnEbnFbnGbnHbnIbnJblMbnKbnLblRbnMbnNbnOblTbnPbnQbnRblTbnSbnTbnUbnSbnSbnSbnVbgSbnWbmbaaaaaaaaaaaaaaaaaaaaabmcbnXbnYbnZboabobbocbodboebofbogbohbmcaaaaaaaaaaaaaaaaaaaaabmiboibhqbojaUSbokbmlbmqbmqbmqbmqbmqbolbombmqbmqbmqbonbooboobopboqborbosbotboubovbowbebboxboybozboAboAboBboCboDbebbejaGYbauboEboFbcpbljblkbcpboGboGbaubauboHbauaYPboIblqbltboJboJboKbltaYPaYPaYPboLbjKbEFbDubjMbjKbjKbmZbAMbrKbrMbrMbrKbDvbDzbDzbGJbGJbnbbeCblCbnbblAbeCblCaYUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabndboPboQboPboPboPboPboPboPboQboPboPboRaSfboSboTboUaSfboVaSfboWboXboYboZbpaaMsbnwbnwbpbblMbpcbnDbnDbnDbnDbnDbnEbpdbnDbnDbnDbpeblMbnKbpfblRbpgbphbpiblTbpjbpkbplblTbpmbpnbpobppbpqbnTbnVbgSbnWbmbaaaaaaaaaaaabmcbmcbmcbmcbprbpsbptbpubpvbpwbpxbpybpzbpAbpBbmcbmcbmcbmcaaaaaaaaaaaabmiboibhqbpCbpDbpEbpFbpGbpHbpEbpIbpJbpKbpLbpMbpNbmqbpObpPboobpQbpRboobpSbpTbpUbpVboobpWbpXbpYbozboAboAboBbpZbqabebbejaTgbaubmIbcpbljbljblkbljbcpbcpbqbbqcbcpbqdaYPbqebqfbqgboJboJbqhbqgbqiaYPbqjbqkbjKbDybDybEHbEIbDybDybjRbqnbjRbjRbjRbEJbjSbjSbjSbjSbqobeCblCbqoblAbeCblCbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLdaLdaPYaPYaPYaPYaPYaPYaPYaPYaPYaLdaMsbqpbqqbqrbqrbqrbqrbqrbqrbqsbqrbqrbqraMsbnwbnKbqtblMbqubnDbnDbqvbqwbqxbqybqvbnDbnDbnDbqzblMbnKbnLblRbqAbqBbqCblTbqDbqEbqFblTbqGbqHbqIbqJbqKbnTbqLbqMbnWbmbbmbbqNbmcbmcbmcbqObqPbqQbqRbqSbqSbqTbqUbqSbqVbqSbqWbqXbqYbqZbrabrbbmcbmcbmcbqNbmibmiboibhqbhqaUSbrcbrdbpMbrebmqbrfbrgbmqbrhbribpNbmqbonbooboobrjbrkbrlbrmbrnbrobrpboobrqbpXbrrbozboAboAbrsbrtbrubebbejaGYbaubrvbrwbrxbljblkbrybcpbcpbrzbcpbrAbrBaYPbrCbrDbrEboJboJbrFbrEbrGaYPbrHbqkbjKbjObGIbjMbjKbjKbrIbrJbrKbrLbrMbrKbrNbeCbeCbeCbeCbeCbeCbeCbeCbeCbeCblCbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrObrPbrPbrQbrPbrPbrPbrRbrPbrPbrSaabaPYaUnaShbrTbqrbrUbrVbrWbrXbrYbrZbsabsbbqrbscbsdbsebsfblMbsgbnDbnDbqvbqxbshbsibqvbnDbnDbsjbskblMbnKbnLblRblRbslblRblTbsmbsnbsoblTbspbqJbsqbqJbsrbnTbnVbssbnWbgXbgXbstbsubsvbmcbswbptbsxbqSbqSbsybszbsAbsBbsAbsCbsDbsEbsFbsGbsHbsIbmcbsJbsubsKbsLbsMboibhqbhqbsNbmqbsObmqbmqbmqbsPbsQbmqbrhbsRbpNbmqbpObooboobsSbsTbsUbsVbsWbsXbrpbsYbebbsZbtabtbboAboAboBbrtbtcbebbtdbtebaubtfbaubaubtgblkbthbtibcpbtjbtkbtlbtmbmUbtnbtobtpbtqbtqbtrbtsbttbmUbtubtvbjKbtwbjKbjMdsfbjKbtxbjRbjRbjRbjRbqnbijbtybeCblCblDblAbeCblCblDblAbeCbtzbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrObtAbtBbtCbtDbtDbtEbtDbtDbtDbtEbrQaPXaPYaSdaToboSbqrbrUbtFbtGbrUbtHbtIbtJbtKbqrbtLbtMbtNblQblMbtObtPbtQbtRbtSbtTbtUbtVbtVbtVbtWbtXblMbnKbsdbtYbtZbuabubblTblTblTblTblTbucbudbuebufbugbnTbnVbssbgSbgSbgSbuhbuibujbukbulbumbqSbunbuobupbuqburbusbutbuubuvbuwbuxbulbuybuzbuAbuBbuCbuDbuEbuEbuFbhqbuGaUSbmqbuHbuIbpNbmqbuJbuKbmqbuLbuMbpNbmqbonboobooboobopboobuNboobsXbrpbuObebbuPbrrboBboAboAboBbrtbuQbebbuRbuSbuTbuUbuVbuWbuXbuYbuZbuZbuZbuZbuZbuZbvabvbbvcboJboJboJboJboJboJbvdbvebvfbqkbjKbjKbjKbjMbjKbjKbvgbqnbvhbvhbvhbjRblDblAbeCblCbnbblAbeCblCbnbblAbeCblCblDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -9198,10 +9192,10 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwEbwFbwGbwHbwIbwIbwJbwIbwIbwIbwJbrQaPYaPYaSdbwKblHbwLbrUbwMbvnbvnbvnbvobwMbrUbqrbwNbwObtNbvsbwPbwQbwRbwSbvsbwTbwUbwVblMbwWbwXbwYbwZblMbnKbxabxbbxbbxcbxbbxbbxbbxbbxdbxebxebxebxfbxebxgbxhbxibxjbxkbxlbxlbxlbxlbxlbxmbxmbxnbxmbvXbvXbxobxpbxqbxrbxsbxtbxobxubvXbxvbxwbxvbxvbxvbxvbxvbxvbxvbwkbhqbhqaUSbxxbmqbxybxzbmqbxAbmqbxBbxCbxDbmqbxEbdTbxFbxGbdTbdTbxHbxIbxJbxIbdTbdTbebbxKbxLbxMbxMbxMbxMbxLbxNbebbxObwvbwvbwwbxPbaubxQbxRbxSbxTbxUbxVbxWbxXbxYaYPbxZbcDbyaboJboJbyabcDbybaYPbycbqkbjKbqlbqlbqmbqlbjKbvgbqnbvhbvhbvhbjRbqoblAbeCblCbqoblAbeCblCbqoblAbeCblCbqoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwEbrPbrPbrQbrPbrPbrPbrRbrPbrPbydaabaPYbyebngbyfbqrbtFbtFbtFbrUbygbyhbyibyjbqrbykbylbtNbvsbymbvsbynbyobvsbypbyqbyrblMbwWbwXbwYbskblMbnKbxabxbbysbytbyubyvbywbxbbyxbyybyzbyAbyBbyBbyBbyCbyDbyEbyFbxlbyGbyHbyIbyJbyKbyLbyMbyNbvXbyObxqbxqbyPbyQbyPbxqbxqbyRbvXbySbyTbyUbyVbyWbyXbyYbyZbxvbzabzbbzbbzcaUSaUSaUSaUSbzdbsNbzdbzeaUSbdRaUSaUSbdTbdTbdTbdTbzfbzgbzgbzgbzgbzhbzibebbjBbzjbjBbzkbzkbjBbzjbjBbebbxObwvbwvbzlbxPbaubaubaubaubaubtfbaubaubaubauaYPaYOaYQaYQaYQaYQaYQaYQaYPaYPbzmbznbjKbjKbjKbjMbjKbjKdsgbjRbjRbjRbjRbqnbijbzobeCbeCbeCbeCbeCbeCbeCbeCbeCbeCbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaUlaLdaSdaSdaSdaMsaMsaMsaMsaMsaMsbzqbzrbqrbqrbqrbqrbqrbqrbzsbqrbqrbqrbnKbnKbztbvsbzubzvbynbzwbvsbzxbzybzzblMbwWbwXbwYbnDblMbnKbxabxbbzAbzBbzCbyvbzCbxbbyxbzDbzEbzFbzGbzHbzIbzJbzKbzLbyFbzMbzNbzObzPbzQbzQbzPbzRbzSbvXbzTbxqbxqbyPbzUbyPbxqbxqbzVbwbbzWbzXbzYbzZbAabAbbzYbAcbxvbAdbAebAfbAgbAhbAibAjbAkbAkbAkbAkbAkbAkbAlbAmbAnbAkbAkbAobAkbAkbAkbAkbAkbAkbAkbAkbApbAqbArbArbArbArbArbArbAsbAibAtbAubAubAvbAwbAxbAwbAybAwbAzbAAbABbAwbACbADbAEbAFbAGbAGbAGbAGbAGbAGbAGbAHbAIbAJbAJbAJbAJbAKbAJbALbrIbAMbrKbANbrMbrKbAObeCbeCbeCbeCbAPbeCbAPbeCbeCbeCbeCaYUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabAQbARbARbARbARbASbASbARbARbATaaaaabaPYaUnaShbAUbAVbAWbAXbAXbAXbAXbAYbAZbBablQbnwbBbbBcbvsbvsbvsbBdbyobvsblMblMblMblMbwWbBebBfbBgblMbBhbBibxbbBjbBkbyvbzCbBlbxbbyxbBmbzEbzFbBnbBobBpbzJbBqbzLbyFbzMbBrbBsbBtbBubBvbBwbzRbBxbvXbBybyPbxqbBzbBAbBzbxqbyPbBBbxubBCbzYbzYbzZbBDbAbbzYbBEbxvbBFbAfbAfbAgbAhbAibAkbAkbAkbAkbAkbAkbAkbBGbAkbAkbAkbAkbAkbAkbBHbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBJbBKbBLbAGbAGbBMbwvbwvbwvbwvbwvbwwbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbBNbwvbBObBPbjKbjKbjKbjKbjKbjKbjKbBQbjRbqnbjRbjRbjRbEJbjSdsidshbjSbBUaYUbBUaYUdsjbBRbBSbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabBWbBXbBYbBZbCabCbbCbbCcbCdbARbATaPXaPYaPYaTobCebCfbCgbCfbCfbCfbCfbChbCibCjblQblQbCkbClbvsbwPbCmbCnbzwbvsbCobCpbCoblMblMblMblMbCqblMbCrbCsbxbbCtbCubzCbCvbCwbxbbyxbzJbCxbzFbBnbBnbCybzJbCzbzLbyFbzMbCAbBsbBtbCBbCCbBwbzRbCDbvXbCEbCFbxqbCGbCHbCIbxqbCJbCKbCLbCMbCNbCObCPbCQbCRbzYbCSbxvbCTbCUbAfbAgbAhbAibAkbCVbAkbAkbAkbAkbCWbCXbCXbCXbCXbCYbAkbAkbAkbAkbCZbAkbCVbDabAkbDbbDcbDdbAkbDebDfbDfbDgbDhbDibDjbwvbwvbwvbwvbwvbwvbwvbDkbDlbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbDmbDnbDnbDobDpbDqbDrbDsbDsbDsbDsbDtdskbAMbrKbrMbrMbrKdsmdsldsldsldsnbijaaabijdsobDwbDwdspbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabAQbARbARbARbARbASbASbARbARbATaaaaabaPYaUnaShbAUbAVbAWbAXbAXbAXbAXbAYbAZbBablQbnwbBbbBcbvsbvsbvsbBdbyobvsblMblMblMblMbwWbBebBfbBgblMbBhbBibxbbBjbBkbyvbzCbBlbxbbyxbBmbzEbzFbBnbBobBpbzJbBqbzLbyFbzMbBrbBsbBtbBubBvbBwbzRbBxbvXbBybyPbxqbBzbBAbBzbxqbyPbBBbxubBCbzYbzYbzZbBDbAbbzYbBEbxvbBFbAfbAfbAgbAhbAibAkbAkbAkbAkbAkbAkbAkbBGbAkbAkbAkbAkbAkbAkbBHbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBJbBKbBLbAGbAGbBMbwvbwvbwvbwvbwvbwwbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbBNbwvbBObBPbjKbjKbjKbjKbjKbjKbjKbBQbjRbqnbjRbjRbjRbEJbjSdsidshbjSbBUaYUbBUaYUbDxbBRbBSbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabBWbBXbBYbBZbCabCbbCbbCcbCdbARbATaPXaPYaPYaTobCebCfbCgbCfbCfbCfbCfbChbCibCjblQblQbCkbClbvsbwPbCmbCnbzwbvsbCobCpbCoblMblMblMblMbCqblMbCrbCsbxbbCtbCubzCbCvbCwbxbbyxbzJbCxbzFbBnbBnbCybzJbCzbzLbyFbzMbCAbBsbBtbCBbCCbBwbzRbCDbvXbCEbCFbxqbCGbCHbCIbxqbCJbCKbCLbCMbCNbCObCPbCQbCRbzYbCSbxvbCTbCUbAfbAgbAhbAibAkbCVbAkbAkbAkbAkbCWbCXbCXbCXbCXbCYbAkbAkbAkbAkbCZbAkbCVbDabAkbDbbDcbDdbAkbDebDfbDfbDgbDhbDibDjbwvbwvbwvbwvbwvbwvbwvbDkbDlbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbDmbDnbDnbDobDpbDqbDrbDsbDsbDsbDsbDtdskbAMbrKbrMbrMbrKdsjdsldsldsldsnbijaaabijdsobDwbDwdspbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabBWbBXbDAbCbbCbbCbbCbbCbbCbbCbbDBbDCaOQbDCaSfbDDbCfbDEbDFbDGbDHbDIbChbDJbDKbDLbDLbDMbDNbvsbvsbvsbynbDObymblQblQblQblQbDPbnKbnKbCsbnKbCrbCsbxbbDQbDRbDSbDTbyvbxbbDUbzJbDVbzFbBnbBnbDWbDXbDYbzLbDZbxlbEabEbbzPbzPbzPbzPbzRbEcbvXbEdbEebvXbvXbvXbvXbvXbvXbvXbxubxvbEfbEgbEhbEibEjbEkbElbxvbEmbEnbEnbEobEobEobEobEobEobEobEpbEpbEqbErbEsbEsbErbEqbEpbEpbEtbEtbEtbEtbEtbEtbEubEubEvbEubEubEubEubEubEubEwbExbEybwvbwvbEzbEzbEAbEAbEAbEAbEAbEBbDnbDnbDmbDnbwvbDnbDnbDnbDnbECbEDbEDbEDbEDbEEbEFbEFbEGbEGbEGbEGbEGbEGbEGbjRbjRbjRbjRaYUdsqdsldsldsrbijaaabijdssbDwbDwdstbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabBWbBXbEKbELbELbCbbELbELbELbARbEMaPYaPYaPYaTobENbCfbEObEPbEPbEPbEQbChbnKbERbESbETbEUbEVbvsbwPbEWbynbEXbymbEYbEZbFabFbbFcbFdbFdbFebFdbFfbFgbxbbFhbFibFjbFkbFlbFmbFnbyBbFobFpbBnbFqbFrbFsbDYbzLbFtbxlbFubFvbFwbFxbFybFzbFAbxmbxmbFBbFCbFDbFEbFFbFEbFGbFCaaabFHbxvbFIbFJbFKbFLbEjbzYbFMbxvbFNbFObFPbEobFQbFRbFSbFTbFUbFVbFWbFXbFYbFZbGabGabFZbGbbGcbGdbEtbGebGfbGgbGhbEtbGibGjbGkbGlbGmbGnbGnbGobEubGpbGqbGrbGsbGrbGtbGtbEAbGubGvbGwbEAbGxbGybGxbEAbGzbDnbECbEDbGAbGBbGAbEDbGCbGDbEDbGEbGFbGGbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabijdsudswdsvdsvbijaaabijdsxdsxdsxbDwbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabBWbBXbEKbELbELbCbbELbELbELbARbEMaPYaPYaPYaTobENbCfbEObEPbEPbEPbEQbChbnKbERbESbETbEUbEVbvsbwPbEWbynbEXbymbEYbEZbFabFbbFcbFdbFdbFebFdbFfbFgbxbbFhbFibFjbFkbFlbFmbFnbyBbFobFpbBnbFqbFrbFsbDYbzLbFtbxlbFubFvbFwbFxbFybFzbFAbxmbxmbFBbFCbFDbFEbFFbFEbFGbFCaaabFHbxvbFIbFJbFKbFLbEjbzYbFMbxvbFNbFObFPbEobFQbFRbFSbFTbFUbFVbFWbFXbFYbFZbGabGabFZbGbbGcbGdbEtbGebGfbGgbGhbEtbGibGjbGkbGlbGmbGnbGnbGobEubGpbGqbGrbGsbGrbGtbGtbEAbGubGvbGwbEAbGxbGybGxbEAbGzbDnbECbEDbGAbGBbGAbEDbGCbGDbEDbGEbGFbGGbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabijdsudswdsvdsvbijaaabijdsxbDwdsxbDwbijaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabGKbARbARbARbARbARbARbARbARbEMaaaaaaaPYbGLbngbGMbCfbGNbCfbGObEPbGPbGQbChbGRbGSbGTbGUbEVbvsbvsbvsbvsbvsbvsbGVbGWbGXbGYbGZbxbbxbbxbbxbbxbbxbbxbbHabxbbxbbxbbHbbxbbHcbHdbHebBnbBnbBnbHfbDXbHgbzLbHhbxlbHibFvbxlbxlbxlbxmbHjbxmbHkbHlbHmbHnbHobHpbHqbHrbHsbHtbHubxvbHvbzYbHwbHxbEjbHybzYbxvbHzbHAbHBbEobHCbHDbHEbHFbHGbHHbHIbGabGabGabGabGabGabGabGabHJbHKbHLbHMbHNbHObEtbHPbHQbHRbHSbHTbHUbHQbHTbEubHVbGqbHWbHXbHYbHZbHZbIabIbbIcbIdbIebIfbIgbIhbEAbIibIjbIkbEDbIlbImbInbIobIpbIqbEDbIrbGGbIsbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabItbjVbIubIubIubIvaaabIwbIxbIxbIxbjVbIyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaUlaLdaSdaSdaPYaPYaPYaPYaPYaPYaPYaToaSfbIzbCfbIAbIBbICbIDbIDbIEbIFbIGbIHbIHbIIbIJbDLbDLbDLbDLbDLbDLbIKbILbILbIMbINbxbbIObIPbIQbIRbISbITbIUbIVbxbbIWbIXbyBbyCbDXbHebBnbBnbIYbzJbzJbIZbJabJbbJcbJdbJebJfbJgbJhbJibJjbJkbJlbJmbHsbJnbJobJnbJobJpbHsbHtbJqbJrbJsbJtbJubJvbJwbJxbJybJrbJzbFObFObEobJAbJBbJCbJDbJEbEobHIbGabGabGabGabGabGabGabJFbJGbJHbJIbJJbHLbJKbEtbJLbJMbJNbHSbHTbHUbJObJPbEubJQbJRbJSbJTbJTbJUbJVbJWbJXbJYbJYbJYbJZbJYbKabKbbKcbKdbKebKfbKgbKhbKibKibKibKjbEDbKkbGGbKlbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabItbKmbKmbKmbIyaaabItbKmbKmbKmbIyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaPYbKnbKobKpaRcaRcaRcbngaSfaSfbCfbKqbCfbKrbKsbKtbKubCfblQbKvbKvbKwbKxbKwbKwbKwbKxbKwblQblQbxbbxbbxbbKybxbbKzbKzbKzbKzbKzbKzbIUbKAbKBbKCbzFbKDbKEbKFbKGbKHbKIbKJbKKbKLbKMbKNbKObKPbKQbKQbKRbKSbKTbKUbKVbKWbKXbKYbFCbKZbHqbLabHobLbbFCaaabLcbLdbLebLfbLdbLdbLdbLdbLgbxvbLhbFObLibLjbLkbLlbLmbLnbLobEobLpbLqbLrbLsbLtbLubLvbLwbGabLxbEtbLybJJbLzbLAbEtbLBbLCbHRbHSbHTbHUbHQbHTbEubHVbGqbLDbLEbLFbLGbLHbLIbLJbLKbLLbLMbLNbLObLPbEAbLQbLRbLSbEDbLTbLUbLVbIpbLWbLXbEDbKkbGGbLYbGHaaaaaaaaaaaaaabaabaabaabaabaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -9232,10 +9226,10 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaczEczFczFczFczFczGczHczIczJczKczKczLcwxcsncoLcqFcoLcoLcoLcoLcoLcoLcoLcoLcoLcvocvocwIczMcwIcvocwIczMcvoczNcsqcngaaacymczOczPczQczRczSczTczUczRczRczVczWczXczYczZczZcAacAbctYcAccAdcyBcyDcyDcyDcyDcAecvIcsLcsLcxhcAfcAgcAhcAicAjcAkcAkcAlcAmcAncAocyKcApcxhcAqcuocArcvYcAscAtcAucAvcAwcAxcxBcAycAzcAAcxBcABcACcADcAEcAEcAEcAEcAEcAFcAGcAHcAIcAJcAJcAKcAKcAJcALcAMcANcAOcAPcAPcAQcARcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAScATcAUbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacnfcieciectJctJckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacAVcAWcAXcAYcAXcAZcBacBbcBccBdcBecwxcsncgQcgQcBfcngcngcngcngcngcngcngcBgcvocwIcwIcwIcwIcBhcwIcwIcvocygcqGcngaaacymcBicBjcBkcBlcwOcBmcBncBocBpcvxcyvcsBcnycBqcsDcBrcsDcvBcvBcvBcBscBtcyDcyDcBucBvcvIcsLcBwcxhcBxcBycBzcBAcBAcBBcBCcBDcBAcBAcBEcyKcBFcxhcBGcuocBHcvYcvYcBIcvYcvYcAwcBJcxBcBKcBLcBMcxBcBNcBOcBwcBPcBPcBPcBPcBPcBQcBQcBQcBPcBPaaaaaaaaaaaacBRcBScBTcBUcAPcBVcBWcBXcBYcBZcCacCbcCccCdcCecCfcCgcChcCicAPcAScCjcCkcClcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCncCocieclzcieckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacAVcCpcCqcCrcCsczJcCtcCucCvczJcCwcCxcCycskcgQcoLcngaaaaaaaaaaaaaaacngcoLcCzcwFcCAcwIcwIcwIcwIcCBcCCcCDcCEcngaaacCFcwKcCGcwMcCHcwOcwOcCIcCJcCKcCLcCMcCNcCOcBqcsDcCPcCQcCRcCScCTcvHcCUcyDcyDcyDcCVcvIcsLcsLcCWcCWcCXcCYcCZcCZcDacDbcDccDdcDdcDecDfcDgcDfcAqcuocArcDhcDicDjcDkcDlcAwcDmcxBcDncDocDpcxBcsLcBOcBPcBPaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcDrcDscDtcDucDvcDwcDwcDxcDwcDwcDwcDwcDwcDycDzcDAcDBcDCbGHcDDcjUbGHbGHaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciecDEcDFcDGciecieckbckbcDHckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacAVcDIcAXcDJcAXcDKcDLcDMcDNcBbcDOcwxcDPcqBcgQcqzcvpaaaaaaaaaaaaaaacvpcDQcvocDRcDRcwFcDScDTcwIcDUcvocoLcqGcvpaaaaaaaaaaaacvqcDVcDWcDXcDXcvxcDYcvxcDZcsBcnycEacEbcEccEdcEecEecEecEfcEgcyDcEhcyDcEicvIcsLcsLcCWcEjcEkcElcEmcEncEocCWcEpcEqcErcEscEtcEucDfcEvcEwcExcDhcEycEzcEAcEBcECczbcxBcEDcEEcEFcxBcsLcBOcBPcEGaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcEHcEIcEJcEKcELcEMcENcEOcDwcDwcEPcDwcDwcDycDAcDAcDAcEQbGHcERbGGbGHaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciccEScETclAcidciecieckbckcckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacEUcEUcEUcEUcEUcwxcEVcEWcEWcEWcEWcEWcEXcEYcEYcEYcEWcEWcEWcEWcEWcEWcEWcEYcEYcEYcvocvocvocvocvocvocvocqFcEZcFacFacFacFacFacvqcvxcvxcvxcvxcvxcvxcvxcFbcsBcnycFccFdcFecFfcFgcFhcFicFjcFkcFlcFmcFncFocvIcsLcsLcCWcFpcFqcFrcFscFscFtcCWcFucFvcFvcFwcFvcFxcFycFzcFzcFzcFAcFBcFCcFDcDlcFEczbcFFcFFcFFcBPcBPcsLcBOcBQcFGaaaaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcFHcFIcFJcFKcFLcFMcFNcFOcDwcDwcDwcDwcFPcFQcFRcFScFTcFUbGHcERbGGbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacicciccicciccidcidcieciecieciecifaabaabaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaacFVcFWcFXcFYcFXcFZcFWcGacGbcGccGccGdcGecGfcGgcGhcGicGjcGkcGlcGmcGmcGncGmcGocGpcGpcGqcGrcGscGtcGucGtcGtcGtcGscGtcGtcGvcGwcGxcGycsBcnycGzcGAcGBcGCcsDcGDczZcGEcGFcGGcGHcGIcGJcGKcsLcsLcCWcGLcGMcGNcGOcGPcGQcCWcGRcGScGTcGUcGVcGWcGXaaaaaaaaacFAcDhcGYcDhcDhcGZcHacHbcHccHdcHechfcsLcBOcBQcFGaaaaaaaabaabaabaaaaaaaaaaaaaaaaaaaaaaaacBScBRcHfcHgcBScHhcHicHjcHkcHlcHmcHncDwcDwcHocHpcHqcHrcHsbGHcERbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacFVcFWcFXcFXcFXcFZcFWcHtcFXcHucFXcHvcHwcHxcHycHzcHAcHzcHBcHCcHDcHEcHDcHDcHFcnzcnzcHDcHGcHDcHDcHDcHDcHDcHDcHDcHDcHDcHDcHHcHIcHJcHKcHLcHMcHNcHOcHPcHQcHRcHScHTcHUcHVcHWcHXcHYcHZcAEcIacIbcIccIdcIecIfcIgcIhcDfcIicErcIjcIkcErcIlcGXaaaaaaaaacImcIncIocIpcIqcGZcIrcIscItcIucIvcracrecIwcBQcFGaaaaaaaaaaabaabaabaaaaaaaaaaaaaaaaaaaaacBRcIxcIycIzcBRcAPcAPcAPcAPcAPcAPcIAcHncIBcICcIDcIEcAPcAPbGHcERbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacAVcDIcAXcDJcAXcDKcDLcDMcDNcBbcDOcwxcDPcqBcgQcqzcvpaaaaaaaaaaaaaaacvpcDQcvocDRcDRcwFcDScDTcwIcDUcvocoLcqGcvpaaaaaaaaaaaacvqcDVcDWcDXcDXcvxcDYcvxcDZcsBcnycEacEbcEccEdcEecEecEecEfcEgcyDcEhcyDcEicvIcsLcsLcCWcEjcEkcElcEmcEncEocCWcEpcEqcErcEscEtcEucDfcEvcEwcExcDhcEycEzcEAcEBcECczbcxBcEDcEEcEFcxBcsLcBOcBPaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcEHcEIcEJcEKcELcEMcENcEOcDwcDwcEPcDwcDwcDycDAcDAcDAcEQbGHcERbGGbGHaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciccEScETclAcidciecieckbckcckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacEUcEUcEUcEUcEUcwxcEVcEWcEWcEWcEWcEWaXpcEYcEYcEYcEWcEWcEWcEWcEWcEWcEWcEYcEYcEYcvocvocvocvocvocvocvocqFcEZcFacFacFacFacFacvqcvxcvxcvxcvxcvxcvxcvxcFbcsBcnycFccFdcFecFfcFgcFhcFicFjcFkcFlcFmcFncFocvIcsLcsLcCWcFpcFqcFrcFscFscFtcCWcFucFvcFvcFwcFvcFxcFycFzcFzcFzcFAcFBcFCcFDcDlcFEczbcFFcFFcFFcBPcBPcsLcBOcBQaaaaaaaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcFHcFIcFJcFKcFLcFMcFNcFOcDwcDwcDwcDwcFPcFQcFRcFScFTcFUbGHcERbGGbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacicciccicciccidcidcieciecieciecifaabaabaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaacFVcFWcFXcFYcFXcFZcFWcGacGbcGccGccGdcGecGfcGgcGhcGicGjcGkcGlcGmcGmcGncGmcGocGpcGpcGqcGrcGscGtcGucGtcGtcGtcGscGtcGtcGvcGwcGxcGycsBcnycGzcGAcGBcGCcsDcGDczZcGEcGFcGGcGHcGIcGJcGKcsLcsLcCWcGLcGMcGNcGOcGPcGQcCWcGRcGScGTcGUcGVcGWcGXaaaaaaaaacFAcDhcGYcDhcDhcGZcHacHbcHccHdcHechfcsLcBOcBQaaaaaaaaaaabaabaabaaaaaaaaaaaaaaaaaaaaaaaacBScBRcHfcHgcBScHhcHicHjcHkcHlcHmcHncDwcDwcHocHpcHqcHrcHsbGHcERbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacFVcFWcFXcFXcFXcFZcFWcHtcFXcHucFXcHvcHwcHxcHycHzcHAcHzcHBcHCcHDcHEcHDcHDcHFcnzcnzcHDcHGcHDcHDcHDcHDcHDcHDcHDcHDcHDcHDcHHcHIcHJcHKcHLcHMcHNcHOcHPcHQcHRcHScHTcHUcHVcHWcHXcHYcHZcAEcIacIbcIccIdcIecIfcIgcIhcDfcIicErcIjcIkcErcIlcGXaaaaaaaaacImcIncIocIpcIqcGZcIrcIscItcIucIvcracrecIwcBQaaaaaaaaaaaaaabaabaabaaaaaaaaaaaaaaaaaaaaacBRcIxcIycIzcBRcAPcAPcAPcAPcAPcAPcIAcHncIBcICcIDcIEcAPcAPbGHcERbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacFVcIFcFXcIGcFXcFZcIHcIIcIJcIKcILcIMcINcIOcIPcIQcIRcIScITcIUcIVcIWcIXcIYcqVcIZcqVcIUcJacIUcIUcIUcIUcIUcIUcIUcIUcIUcIUcJbcHDcJccJdcJecJfcJgcJhcJicJjcJkcJlcJmcJncJocJpcJqcJrcGHcrecJscJtcJucEmcElcEmcEmcJvcDfcJwcErcErcEscErcJxcGXaaaaaaaaacImcJycJzcJAcJBcJCcJDcJEcJFcHdcsLcuccJGcBOcBPaaaaaaaaaaaaaaaaabcBRcBRcBRcBRcBRcBRcBRcBRcBRcJHcJIcJJcxNcJKcJKcJLcBRaabcAPcAPcJMcAPcJNcJOcJPcAPcJQcuQcERbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacJRcJScEWcEWcEWcEWcEXcEYcEYcEYcEYcJTcEYcJUcJVcJVcJWcJXcJYcEYcJZcKacKbcKbcKccKbcKdcKbcKbcKecKfcKbcKbcKfcKfcKfcKbcKbcKbcKbcKgcKhcKicKjcKkcKlcKmcKncKocKncKncKncKncKpcKqcKrcKscKtcGKcsLcKucKvcKwcKxcKycKzcKAcKBcDfcKCcKDcKEcKFcKGcKHcFyaaaaaaaaacImcKIcKJcKKcIqcKLcKMcJDcKNcHdcKOchfchfcBOcBPaaaaaaaaaaaaaaaaaacBRcKPcKQcKRcKScKTcKUcKVcxNcKWcKXcKYcxNcJKcKZcLacBRaabaabcLbcLccLdcLecLfcLgcLbbGGbGGcERcLhbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalwalwalwalvalvalwalvalvaabamhaabayiaaaayiayicLicLjcLkcLkcLkcLlcLmcEYcLncLocLpcLqcLrcLscEYcLtcLucKfcLvcLwcLxcLycLzcLAcLBcLCcLDcKbcLCcLEcLFcLGcLGcLHcKbcLIcLJcHCcLKcnycLLcLMcLNcLOcLPcLQcLPcLRcLScLTcLUcLVcLWcGKcGKcKucKvcCWcCWcLXcCWcCWcKvcLYcLZcLZcLZcMacLZcMbcFyaaaaaaaaacImcImcImcImcImcFFcMccMdcMecHdcsLcsLcMfcBOcBPaaaaaaaaaaaaaaaaaacBRcJKcMgcJKcMhcMicEHcJIcxNcxQcMjcxQcxNcJKcJKcMkcBRaabaaacLbcMlcMmcLecLecMncLbcMobGGcERbKlcMpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -9258,12 +9252,12 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcXucXucXudcLdcMdcMdcMdardcNdcOdcPdcPdcQdcRdawdcSdcTdcUdcVdcWdcXdcYdcZddaddbddcddddcYddeddfddgddhddiddjddkddldbDcZSddmddncSddaMcSdddocSddaPdaQcXTcXUddpcXWdbIcQZcQZcQZcQZcQZcRacBQddqcYccuccTBddrddsddsddsddtchfdduddvddwchfddxcYbcYbddyddzcMfcsLcsLcBPcBPaaaaaaddAaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabaabaaabGHcJQddBddCcuQddDddEbGGbZZaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaddFcXucZucZucZudcMaabaabdarddGddHdcPdcPddIdarddJddKddLddMddNddOddPcSUddQddRddScVjddTcSUddUddVddWddMddMddXddYcSUddZcZSdeadebcSddaMcSdcZUcZVdecdeddaRdeedefcWXdegcSndehdeideicQZcRacBQdejdekchfchfcOYchfchfcsLdelchfchfdemchfchfdendeodepdeqdercBPcBPcBPcBPaaaaaaaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaabaabbGHdbgcASbZYcuQcuQcuQbGGbGHaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcXucZucZucZudcMaabaaadardesddHdcPdcPdetdardeudevcSUdewdexdexdeycSUdezdeAdeBdeCdeDcSUdexdexdexdewcSUdeEdeucSUdbDcZSdeFdeGdeHdeIdeJdeKdeLdeMcWUdeNcXUdeOcXWdbIcTodePdeQdeRcQZcRacBPcBPcOYcprdeScOYdeTchfcsLdeUdeVdeWdeXddsddsdeYcYichfdeZcBPcBPaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaabGHbGHbGHbGHbGHdfabZYcuQdfbdfcbGGbGHaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacXucXudcMdcLdfdaaaaaadardfedffdcPdcPdfgdardfhdfidfjdfkdfldfmdfndfodfpdfqdfrdfsddkdfodfldfldfldftdfjdfudfvcSUdbDdfwdaMdfxdfydeLdfzdfAdfBdfCdfDdfEdfFdfGcZadcycSndfHdeideicQZcRacBPcsLdfIdfJdfKdeYcsKchfcsLcsLcsLcYidfLcsLcXkdfMddzchfcOYbGHaaaaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaabGHbGGbGGbGGcJQdfNdfOcuQdfPbGGbGGbGHaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadfQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadfRdfSdfSdfTdfSdfSdfUdardfVdcOdcPdcPdfWdardaGdfXcSUcSUdfodfodfodfodfYdfZdgaddMdgbdfodfodfodfocSUcSUdgcdgdcSUdbDcZSdgedgfdfydggdghcSdcSddgicXPdggcXUdgjcXWdbIcQZcQZcQZcQZcQZcRacBPcTBcsLdgkdglcsLdgmchfchfdgnchfdgocpscJGdgpchfchfchfcOYbGHaaaaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabaaaaaaaaaaaabGHbGHcuQdgqdgrcJQdfNbZYbGGbGGbGGdgsbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadgtdgudgvdgwdgvdgxdgydardgzdgAdcPdcPdgBdarcSUdgCcSUdgDaacdgEdfodfodfodfodgFdfodfodfodfodgEaacdgDcSUdgGcSUcSUdbDcZSdgHdeHdgIdgJdgKdgLdgMdgJdgMdgJdgNdeLdgOdbIdgPdgQdgQdgQdgQdgRdgSdgTdgTdgUdgVdgTdgTdgTdgWdgXdgYdgodgZchfdgochfdhachfcOYbGHbZZbZZbZZbGHbZZbZZbZZbZZbGHbZZbZZbZZbZZbGHbGHbGHbGHbGHbGHbGHbGHbGHbGHcMpbGHcJQcuQdhbbGGcQwdfNbZYcuQcuQdbhcuQbGHaabdhcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadgtdgudgvdgwdgwdhddhedardhfdhgdcPdcPdhhdardhidhjdhkaacdhldhmdhmdhmdhmdhmdhndhmdhmdhmdhmdhmdhoaacdhpdhqdhrcSUdhsdaIdhtdhudhvdhwdhxdhydhzdhAcSddhBdhCdhDdhEdbIdhFaaaaabaabaaadhGdhHdhIdhJdhKdhLdhMdhNdgTdhOcsLcsLdhPcpsdhQcYicsLcsLdhRddqdhSdhSdhSdhSdhSdhSdhSdhSdhSdhSdhSdhSdhSdhSdhTdhSdhSdhSdhSczDcuQbPAcAUbGGdhUcMpcuQcuQcuQdbhcuQdfNbZYcuQdhVbGGbGGbGHaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadgtdgudgvdhWdgvdhXdhYdardfVdcOdcPdcPdhZdardiadibdibaaadicaacaacaacaacaacaacaacaacaacaacaacdicaaadibdibdiacSUdaGcZSdhEdiddiedifdigdihdhEdifdhEcXWdhEcXWdhEdbIdhFaaaalwalwdiidhHdijdikdildimdindiodipdgTcsLcsLchfdgodiqchfcYicXkdfMdirdisditditditditditditdiudivditditditditditditdiwdixdiydizdiAdiBdiCdiCdiCdiCdiDdiEdiFdiCdiCdiCdiCdiGcjUcuQdfcbGGdiHbGHaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadiIdfSdfSdfSdfSdfSdiJdardiKdiLdcPdcPdiMdardiNdiOdiPaabdicaacdiQaaaaaaaaaaaadiQaaaaaadiQaacdicaaadiRdiSdiTcSUdaGcSUaabdiUaabdiVdiWdiXdiYdiZdiYdjadiYdjadjbdjcdhFaaaalwaabdjddgSdjedjfdjgdjhdjidjjdjkdgTdjlcsLcsLcYidjmchfcYicYidjncBPcBPbZZbZZbZZbZZbGHbZZbZZbZZbZZbGHbZZbZZbZZbZZbGHdjobGGcuQcTLbGGcuQcuQbZZbZZcxScuQdjpbGGdjpcuQdjqbZYdjrbGHbGHbGHbGHbGHaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacXucXudcMdcLdfdaaaaaadardfedffdcPdcPdfgdardfhdfidfjdfkdfldfmdfndfodfpdfqdfrdfsddkdfodfldfldfldftdfjdfudfvcSUdbDdfwdaMdfxdfydeLdfzdfAdfBdfCdfDdfEdfFdfGcZadcycSndfHdeideicQZcRacBPcsLdfIdfJdfKdeYcsKchfcsLcsLcsLcYidfLcsLcXkdfMddzcuQcERbGHaaaaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaabGHbGGbGGbGGcJQdfNdfOcuQdfPbGGbGGbGHaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadfQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadfRdfSdfSdfTdfSdfSdfUdardfVdcOdcPdcPdfWdardaGdfXcSUcSUdfodfodfodfodfYdfZdgaddMdgbdfodfodfodfocSUcSUdgcdgdcSUdbDcZSdgedgfdfydggdghcSdcSddgicXPdggcXUdgjcXWdbIcQZcQZcQZcQZcQZcRacBPcTBcsLdgkdglcsLdgmchfchfdgnchfdgocpscJGdgpchfchfcuQcERbGHaaaaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabaaaaaaaaaaaabGHbGHcuQdgqdgrcJQdfNbZYbGGbGGbGGdgsbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadgtdgudgvdgwdgvdgxdgydardgzdgAdcPdcPdgBdarcSUdgCcSUdgDaacdgEdfodfodfodfodgFdfodfodfodfodgEaacdgDcSUdgGcSUcSUdbDcZSdgHdeHdgIdgJdgKdgLdgMdgJdgMdgJdgNdeLdgOdbIdgPdgQdgQdgQdgQdgRdgSdgTdgTdgUdgVdgTdgTdgTdgWdgXdgYdgodgZchfdgochfdhacuQcERbGHbZZbZZbZZbGHbZZbZZbZZbZZbGHbZZbZZbZZbZZbGHbGHbGHbGHbGHbGHbGHbGHbGHbGHcMpbGHcJQcuQdhbbGGcQwdfNbZYcuQcuQdbhcuQbGHaabdhcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadgtdgudgvdgwdgwdhddhedardhfdhgdcPdcPdhhdardhidhjdhkaacdhldhmdhmdhmdhmdhmdhndhmdhmdhmdhmdhmdhoaacdhpdhqdhrcSUdhsdaIdhtdhudhvdhwdhxdhydhzdhAcSddhBdhCdhDdhEdbIdhFaaaaabaabaaadhGdhHdhIdhJdhKdhLdhMdhNdgTdhOcsLcsLdhPcpsdhQcYicsLcsLcEGaYNdhSdhSdhSdhSdhSdhSdhSdhSdhSdhSdhSdhSdhSdhSdhTdhSdhSdhSdhSczDcuQbPAcAUbGGdhUcMpcuQcuQcuQdbhcuQdfNbZYcuQdhVbGGbGGbGHaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadgtdgudgvdhWdgvdhXdhYdardfVdcOdcPdcPdhZdardiadibdibaaadicaacaacaacaacaacaacaacaacaacaacaacdicaaadibdibdiacSUdaGcZSdhEdiddiedifdigdihdhEdifdhEcXWdhEcXWdhEdbIdhFaaaalwalwdiidhHdijdikdildimdindiodipdgTcsLcsLchfdgodiqchfcYicXkdfMdhRcFGditditditditditditdiudivditditditditditditdiwdixdiydizdiAdiBdiCdiCdiCdiCdiDdiEdiFdiCdiCdiCdiCdiGcjUcuQdfcbGGdiHbGHaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadiIdfSdfSdfSdfSdfSdiJdardiKdiLdcPdcPdiMdardiNdiOdiPaabdicaacdiQaaaaaaaaaaaadiQaaaaaadiQaacdicaaadiRdiSdiTcSUdaGcSUaabdiUaabdiVdiWdiXdiYdiZdiYdjadiYdjadjbdjcdhFaaaalwaabdjddgSdjedjfdjgdjhdjidjjdjkdgTdjlcsLcsLcYidjmchfcYicYidjnbGHbGHbZZbZZbZZbZZbGHbZZbZZbZZbZZbGHbZZbZZbZZbZZbGHdjobGGcuQcTLbGGcuQcuQbZZbZZcxScuQdjpbGGdjpcuQdjqbZYdjrbGHbGHbGHbGHbGHaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadardjsdiLdcPdcPdjtdardjudibdjvaaadjwdjxaaaaaaaaaaaaaaadjyaaaaaaaaadjzdjAaaadibdibdjucSUdaGcSUcQZdjBcTodjBcQZdjBcTodjBcQZdjCcTodjDcQZaabdhFaaaalwaabdjEdgSdjFdjfdjGdjHdjidjIdjJdjKdirdjLdjMcYicpscsLdjNdgochfcBPaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaabGHdjOcLhcuQdjPbGGcuQaaaaaaaaaaaacuQbGGbGGdbgdjQdjQdjRdjSdjQaaaaabaabaabaabdjTaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadardjUdcOdcPdcPdhZdardjVdjWdibaaadicaacaaaaaaaabaabaabaabaabaaaaaaaacdicaaadibdjXdjYcSUdjZcSUcQZdkadkbdkccQZdkddkedkfcQZdkgdkhdkicQZaabdhFaaaalwaaadjEdkjdkkdkldkmdkndkodkpdkqdgTdkrdgochfdgodkschfdktdgocBNcBPcBQcBQcBQaHQaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaabGHdkucuQcuQcQxbGGcuQcuQbZZbZZcuQcuQbGGdkvcLhdjQdkwdkxdkydjQaaaaaaaabaabaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacdardardardardardardarcSUdiadibaaadicaacdiQaabaabdkzdkAdkBaabdkCaaaaacdicaaadibdiacSUcSUdaGcSUcQZdkDdkEdkDcQZdkFdkGdkFcQZdkHdkIdkHcQZaabdhFaaaalwaaadjddgSdkJdkKdkLdkldkMdkNdkOdgTdkPdkQdkRdkSdkTcsLcYicYidkUdkVdkWcsLdkXaHQaaaaabaaabZZbZZbZZbGHbGHbGHbGHbGHbGHdkYcJQcuQdkZbGGbGGcuQbGGbGGbGGbGGdhbbGGdfPdjQdladlbdlcdjQaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -9287,19 +9281,19 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadpddpCdpDdpEdpFdpGdpHdpIdpJdpGdpKdpLdpMdpNdppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWaabdogdohdohdohdohdpOdpPdpOdoldoldoldoldpcaabamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaadpddpQdpRdpSdpTdpUdpVdpWdpXdpYdpZdqadqbdqcdppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWaabdovdovdovdovdovaaadnAaaadovdovdovdovdovaaaamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadpddpddqddqedqfdpfdqgdqhdqidpfdqjdqkdqldppdppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWaaaaaaaabaabaabaaaaaadnAaabaaaaaaaabaabaaaaaaamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqmdqndqodqpdqmdqmdqqdqrdqmdqpdqsdqpdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWamWamWamWamWaaaaaaaaadnAaaaaaaaaaamWamWamWayiamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqmdqtdqudqpdqvdqwdqxdqydqvdqpdqzdqAdqmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWaabdqBaabamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqmdqCdqudqpdqvdqwdqxdqydqvdqpdqzdqDdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWaaaaabaaaamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqEdqmdqFdqGdqpdqHdqwdqIdqJdqKdqpdqzdqmdqmdqLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWamWamWamWamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabdqFdqMdqpdqNdqwdqxdqydqvdqpdqOdqmaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqFdqPdqQdqRdqSdqTdqydqUdqVdqWdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqFdqXdqpdqYdqZdqxdqydradqpdqXdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabdqFdqXdqpdqHdrbdrcdqydqKdqpdqXdqmaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqmdqFdqXdqpdqvdqwdqxdqydqvdqpdqXdqmdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqmdrddqXdqpdqvdqwdredqydqvdqpdqXdqXdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqmdrddrfdrfdrgdrfdrhdridrgdrfdrfdqXdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadrjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqmdrddrfdrfdrkdrldrmdrndrodrfdrfdqXdqmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqmdrddrfdrfdrpdrqdrrdrsdrtdrfdrfdqXdqmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqmdqpdqodqpdqmdqmdqqdqrdqmdqpdqsdqpdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWamWamWamWamWaaaaaaaaadnAaaaaaaaaaamWamWamWayiamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqmdisdqudqpdqvdqwdqxdqydqvdqpdqzdqAdqmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWaabdqBaabamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqmdqndqudqpdqvdqwdqxdqydqvdqpdqzdqDdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWaaaaabaaaamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqEdqmdqmdqudqpdqHdqwdqIdqJdqKdqpdqzdqmdqmdqLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamWamWamWamWamWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabdqmdqMdqpdqNdqwdqxdqydqvdqpdqOdqmaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqmdqPdqQdqRdqSdqTdqydqUdqVdqWdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqmdqXdqpdqYdqZdqxdqydradqpdqXdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabdqmdqXdqpdqHdrbdrcdqydqKdqpdqXdqmaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqmdqmdqXdqpdqvdqwdqxdqydqvdqpdqXdqmdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdqmdqXdqXdqpdqvdqwdredqydqvdqpdqXdqXdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqmdqXdrfdrfdrgdrfdrhdridrgdrfdrfdqXdqmaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadrjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqmdqXdrfdrfdrkdrldrmdrndrodrfdrfdqXdqmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqmdqXdrfdrfdrpdrqdrrdrsdrtdrfdrfdqXdqmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqmdrudrfdrfdrvdrvdrwdrxdrvdrfdrfdrudqmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadqmdrudrfdrydrydrzdrAdrsdrydrydrfdrudqmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadrfdrfdrfdrBdrCdrDdrEdrFdrGdrHdrfdrfdrfaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/_maps/map_files/shuttles/emergency_bar.dmm b/_maps/map_files/shuttles/emergency_bar.dmm index 66c7a9ff8c8..d96ec7d366d 100644 --- a/_maps/map_files/shuttles/emergency_bar.dmm +++ b/_maps/map_files/shuttles/emergency_bar.dmm @@ -22,7 +22,7 @@ "av" = (/obj/machinery/door/airlock/glass_command{name = "Escape Shuttle Cockpit"; req_access_txt = "19"},/turf/simulated/shuttle/floor,/area/shuttle/escape) "aw" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor4,/area/shuttle/escape) "ax" = (/obj/machinery/status_display{pixel_y = 30},/obj/machinery/light/spot{tag = "icon-tube1 (NORTH)"; icon_state = "tube1"; dir = 1},/obj/structure/stool/bed/chair,/turf/simulated/shuttle/floor4,/area/shuttle/escape) -"ay" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"ay" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/shuttle/escape) "az" = (/obj/item/weapon/twohanded/required/kirbyplants,/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape) "aA" = (/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape) "aB" = (/obj/item/weapon/twohanded/required/kirbyplants,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/shuttle/escape) @@ -34,7 +34,7 @@ "aH" = (/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/shuttle/escape) "aI" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/floor/plating,/area/shuttle/escape) "aJ" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/shuttle/floor4,/area/shuttle/escape) -"aK" = (/obj/structure/stool/bed/chair{dir = 8},/obj/item/device/radio/intercom{dir = 4; name = "station intercom (General)"; pixel_x = 28},/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"aK" = (/obj/structure/stool/bed/chair,/turf/simulated/shuttle/floor4,/area/shuttle/escape) "aL" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "16"},/turf/simulated/floor/plating,/area/shuttle/escape) "aM" = (/obj/item/weapon/stool,/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape) "aN" = (/obj/structure/table/woodentable,/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape) @@ -60,10 +60,10 @@ "bh" = (/obj/machinery/status_display{pixel_y = -30},/obj/machinery/light/spot,/turf/simulated/floor/plasteel{icon_state = "cafeteria"; dir = 2},/area/shuttle/escape) "bi" = (/obj/machinery/door/airlock{name = "Toilet"; req_access_txt = "0"},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "bj" = (/turf/simulated/shuttle/wall{tag = "icon-swall14"; icon_state = "swall14"; dir = 2},/area/shuttle/escape) -"bk" = (/obj/machinery/door/airlock/glass_security{name = "Escape Shuttle Cell"; req_access_txt = "2"},/obj/machinery/door/airlock/glass_medical{id_tag = null; name = "Escape Shuttle Infirmary"; req_access_txt = "0"},/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"bk" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "15"},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "bl" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "14"},/turf/simulated/floor/plating,/area/shuttle/escape) "bm" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "17"},/turf/simulated/floor/plating,/area/shuttle/escape) -"bn" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/space,/area/shuttle/escape) +"bn" = (/obj/machinery/door/airlock/glass_medical{id_tag = null; name = "Escape Shuttle Infirmary"; req_access_txt = "0"},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "bo" = (/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/shuttle/escape) "bp" = (/obj/machinery/light/spot{tag = "icon-tube1 (EAST)"; icon_state = "tube1"; dir = 4},/obj/machinery/shower,/obj/structure/curtain/open/shower,/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/shuttle/escape) "bq" = (/obj/structure/table,/obj/item/weapon/storage/firstaid/o2{layer = 2.8; pixel_x = 4; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = 2; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = -2; pixel_y = 4},/obj/item/bodybag/cryobag{pixel_x = 5},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) @@ -97,10 +97,10 @@ aaaaaaacakaialaiamacaaaaaa aaaaabaeaialanalaoagadaaaa aaaaapaqaralalasalarapaaaa abatauatatatavatatatauatad -apawaxayacazaAazaAaBaCaDap -apaEaFaFaGaAaAaAaAaHaHaHap -aIaFaJaKaLaAaAaMaNaNaOaPac -aQatatataRaAaAaMaNaAaAaSap +apawaxaKaKacaAazaAaBaCaDap +apaEaFaFaFaGaAaAaAaHaHaHap +aIaFaFaJaJaLaAaMaNaNaOaPac +aQatatatatbkaAaMaNaAaAaSap aTaAaAaAaAaAaAaMaNaAaAaUap apaHaVaVaHaAaAaMaNaAaAaWap aLaXaYaYaHaAaAaMaNaAaAaZaL @@ -108,10 +108,11 @@ baaBbbbcaHaAaAaMaNaAaAbdba aRaXaYaYaHaAaAaMaNaNaNaNaR apaHbebeaHaAaAazaMaMaMbfap bgaAaAaAaAbhaAbhaAaAaAaAac -aQatatbiatbjatbjacbkblbmap -bnbobobobobobpapbqbrbrbsap +aQatatbiatbjatbjacbnblbmap +aybobobobobobpapbqbrbrbsap acbtbubvbubwbuapbxbrbrbyap -apbzbubzbubAbBapbCbCbCbDap +apbzbubzbubAbBapbCbrbCbDap bEbFbGbGbGbHatbIbJbJbJbFbK aabEbLbLbLbKaabEbLbLbLbKaa "} + diff --git a/_maps/map_files/shuttles/emergency_clown.dmm b/_maps/map_files/shuttles/emergency_clown.dmm index 4b1d1c8f79b..f8bf085bb50 100644 --- a/_maps/map_files/shuttles/emergency_clown.dmm +++ b/_maps/map_files/shuttles/emergency_clown.dmm @@ -48,10 +48,10 @@ "aV" = (/obj/structure/noticeboard,/turf/simulated/shuttle/wall{icon_state = "swall12"; dir = 2},/area/shuttle/escape) "aW" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = null; name = "Shuttle Cargo Hatch"},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "aX" = (/turf/simulated/shuttle/wall{tag = "icon-swall14"; icon_state = "swall14"; dir = 2},/area/shuttle/escape) -"aY" = (/obj/machinery/door/airlock/glass_security{name = "Escape Shuttle Cell"; req_access_txt = "2"},/obj/machinery/door/airlock/glass_medical{id_tag = null; name = "Escape Shuttle Infirmary"; req_access_txt = "0"},/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"aY" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/floor/noslip,/area/shuttle/escape) "aZ" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "14"},/turf/simulated/floor/plating,/area/shuttle/escape) "ba" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "17"},/turf/simulated/floor/plating,/area/shuttle/escape) -"bb" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/space,/area/shuttle/escape) +"bb" = (/obj/machinery/door/airlock/glass_medical{id_tag = null; name = "Escape Shuttle Infirmary"; req_access_txt = "0"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/shuttle/escape) "bc" = (/obj/machinery/vending/clothing,/turf/simulated/floor/noslip,/area/shuttle/escape) "bd" = (/obj/structure/table,/obj/item/weapon/storage/firstaid/o2{layer = 2.8; pixel_x = 4; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = 2; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = -2; pixel_y = 4},/obj/item/bodybag/cryobag{pixel_x = 5},/turf/simulated/floor/noslip,/area/shuttle/escape) "be" = (/obj/machinery/vending/wallmed1{layer = 3.3; name = "Emergency NanoMed"; pixel_x = 28; pixel_y = 0; req_access_txt = "0"},/obj/structure/stool/bed/roller,/turf/simulated/floor/noslip,/area/shuttle/escape) @@ -90,10 +90,11 @@ aJaDamaDaJaDapaDaJaDamaDaJ aOaDamaDaOaDapaDaOaDamaDaO araSamamamamamamamamamamar aTamamamamaUamaUamamamamac -aNaxaVaWaxaXacaXacaYaZbaar -bbawawawbcaraaarbdawawbear +aNaxaVaWaxaXacaXacbbaZbaar +aYawawawbcaraaarbdawawbear acbfawawbgaraaarbhawawbiar -arbjbjbkblaraaarbmbmbmawar +arbjbjbkblaraaarbmawbmawar bnaAbobobobpaabqbrbrbraAbs aabnbtbtbtbsaabnbtbtbtbsaa "} + diff --git a/_maps/map_files/shuttles/emergency_cyb.dmm b/_maps/map_files/shuttles/emergency_cyb.dmm index 562f7a9cbff..14a9b7b3788 100644 --- a/_maps/map_files/shuttles/emergency_cyb.dmm +++ b/_maps/map_files/shuttles/emergency_cyb.dmm @@ -25,7 +25,7 @@ "ay" = (/turf/simulated/shuttle/wall{icon_state = "swall14"; dir = 2},/area/shuttle/escape) "az" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor4,/area/shuttle/escape) "aA" = (/obj/machinery/status_display{pixel_y = 30},/obj/machinery/light/spot{tag = "icon-tube1 (NORTH)"; icon_state = "tube1"; dir = 1},/obj/structure/stool/bed/chair,/turf/simulated/shuttle/floor4,/area/shuttle/escape) -"aB" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"aB" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape) "aC" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "aD" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "aE" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "16"},/turf/simulated/floor/plating,/area/shuttle/escape) @@ -38,7 +38,7 @@ "aL" = (/obj/structure/stool/bed/chair{dir = 8},/obj/structure/closet/walllocker/emerglocker{pixel_x = 28},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "aM" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/floor/plating,/area/shuttle/escape) "aN" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/shuttle/floor4,/area/shuttle/escape) -"aO" = (/obj/structure/stool/bed/chair{dir = 8},/obj/item/device/radio/intercom{dir = 4; name = "station intercom (General)"; pixel_x = 28},/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"aO" = (/obj/structure/stool/bed/chair,/turf/simulated/shuttle/floor4,/area/shuttle/escape) "aP" = (/turf/simulated/shuttle/wall{tag = "icon-swall7"; icon_state = "swall7"; dir = 2},/area/shuttle/escape) "aQ" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "15"},/turf/simulated/floor/plating,/area/shuttle/escape) "aR" = (/obj/docking_port/mobile/emergency{dir = 4; dwidth = 11; height = 13; timid = 1; width = 24},/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/shuttle/floor,/area/shuttle/escape) @@ -50,10 +50,10 @@ "aX" = (/obj/structure/noticeboard,/turf/simulated/shuttle/wall{icon_state = "swall12"; dir = 2},/area/shuttle/escape) "aY" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = null; name = "Shuttle Cargo Hatch"},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "aZ" = (/turf/simulated/shuttle/wall{tag = "icon-swall14"; icon_state = "swall14"; dir = 2},/area/shuttle/escape) -"ba" = (/obj/machinery/door/airlock/glass_security{name = "Escape Shuttle Cell"; req_access_txt = "2"},/obj/machinery/door/airlock/glass_medical{id_tag = null; name = "Escape Shuttle Infirmary"; req_access_txt = "0"},/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"ba" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "15"},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "bb" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "14"},/turf/simulated/floor/plating,/area/shuttle/escape) "bc" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "17"},/turf/simulated/floor/plating,/area/shuttle/escape) -"bd" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/space,/area/shuttle/escape) +"bd" = (/obj/machinery/door/airlock/glass_medical{id_tag = null; name = "Escape Shuttle Infirmary"; req_access_txt = "0"},/turf/simulated/shuttle/floor,/area/shuttle/escape) "be" = (/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape) "bf" = (/obj/structure/closet/crate,/turf/simulated/shuttle/floor{icon_state = "floor2"},/area/shuttle/escape) "bg" = (/obj/structure/table,/obj/item/weapon/storage/firstaid/o2{layer = 2.8; pixel_x = 4; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = 2; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = -2; pixel_y = 4},/obj/item/bodybag/cryobag{pixel_x = 5},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) @@ -82,10 +82,10 @@ aaaaaaacakalamalanacaaaaaa aaaaabaeaoamamamapagadaaaa aaaaaqarasamamatauamaqaaaa abavawavavavaxavayavawavad -aqazaAaBacaCamaDaEaCaFaDaq -aqaGaHaHaIaJamaDaKaCamaLaq -aMaHaNaOaEaCamaDaKaCamaDac -aPavavavaQaCamaDaQaCamaDaq +aqazaAaOaOacamaDaEaCaFaDaq +aqaGaHaHaHaIamaDaKaCamaLaq +aMaHaHaNaNaEamaDaKaCamaDac +aPavavavavbaamaDaQaCamaDaq aRamamamamamamamamamamaDaq aqaSamaDaEaCamaDaEaCamaTaq aEaCamaDaKaCamaDaKaCamaDaE @@ -93,10 +93,11 @@ aKaCamaDaKaCamaDaKaCamaDaK aQaCamaDaQaCamaDaQaCamaDaQ aqaUamamamamamamamamamamaq aVamamamamaWamaWamamamamac -aPavaXaYavaZacaZacbabbbcaq -bdbebebebfaqaaaqbgaJaJbhaq +aPavaXaYavaZacaZacbdbbbcaq +aBbebebebfaqaaaqbgaJaJbhaq acbibebebjaqaaaqbkaJaJblaq -aqbmbnboboaqaaaqbpbpbpaJaq +aqbmbnboboaqaaaqbpaJbpaJaq bqaybrbrbrbsaabtbububuaybv aabqbwbwbwbvaabqbwbwbwbvaa "} + diff --git a/_maps/map_files/shuttles/emergency_narnar.dmm b/_maps/map_files/shuttles/emergency_narnar.dmm index 040961227cc..537d0f5ba82 100644 --- a/_maps/map_files/shuttles/emergency_narnar.dmm +++ b/_maps/map_files/shuttles/emergency_narnar.dmm @@ -34,18 +34,18 @@ "aH" = (/obj/item/candle/eternal,/turf/simulated/floor/engine/cult,/area/shuttle/escape) "aI" = (/obj/effect/decal/cleanable/blood/writing,/turf/simulated/floor/engine/cult,/area/shuttle/escape) "aJ" = (/obj/structure/closet/walllocker/emerglocker{pixel_x = 28},/obj/machinery/light/spot{tag = "icon-tube1 (EAST)"; icon_state = "tube1"; dir = 4},/turf/simulated/floor/engine/cult,/area/shuttle/escape) -"aK" = (/mob/living/simple_animal/construct/harvester,/turf/simulated/floor/engine/cult,/area/shuttle/escape) -"aL" = (/mob/living/simple_animal/construct/builder,/turf/simulated/floor/engine/cult,/area/shuttle/escape) +"aK" = (/obj/effect/rune,/mob/living/simple_animal/hostile/construct/wraith,/turf/simulated/floor/engine/cult,/area/shuttle/escape) +"aL" = (/mob/living/simple_animal/hostile/construct/armoured,/turf/simulated/floor/engine/cult,/area/shuttle/escape) "aM" = (/obj/effect/decal/cleanable/blood/innards,/obj/effect/decal/cleanable/blood/gibs/body,/turf/simulated/floor/engine/cult,/area/shuttle/escape) -"aN" = (/mob/living/simple_animal/construct/wraith,/turf/simulated/floor/engine/cult,/area/shuttle/escape) -"aO" = (/mob/living/simple_animal/construct/armoured,/turf/simulated/floor/engine/cult,/area/shuttle/escape) +"aN" = (/mob/living/simple_animal/construct/wraith,/mob/living/simple_animal/hostile/construct/builder,/turf/simulated/floor/engine/cult,/area/shuttle/escape) +"aO" = (/mob/living/simple_animal/construct/builder,/mob/living/simple_animal/hostile/construct/behemoth,/turf/simulated/floor/engine/cult,/area/shuttle/escape) "aP" = (/obj/item/weapon/storage/firstaid/fire,/obj/item/weapon/extinguisher,/obj/item/weapon/crowbar,/obj/machinery/light/spot{tag = "icon-tube1 (WEST)"; icon_state = "tube1"; dir = 8},/turf/simulated/floor/engine/cult,/area/shuttle/escape) "aQ" = (/obj/effect/decal/cleanable/blood/writing,/obj/effect/decal/cleanable/blood/writing,/turf/simulated/floor/engine/cult,/area/shuttle/escape) "aR" = (/turf/simulated/shuttle/wall{icon_state = "swall3"; dir = 2},/obj/effect/spawner/window/reinforced{color = "red"},/turf/simulated/wall/cult,/area/shuttle/escape) "aS" = (/obj/machinery/status_display{pixel_y = -30},/obj/machinery/light/spot,/turf/simulated/floor/engine/cult,/area/shuttle/escape) "aT" = (/obj/machinery/door/airlock/cult/friendly,/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "aU" = (/obj/effect/spawner/window/reinforced{color = "red"},/turf/simulated/shuttle/wall{tag = "icon-swall14"; icon_state = "swall14"; dir = 2},/area/shuttle/escape) -"aV" = (/obj/machinery/door/airlock/cult/friendly,/turf/simulated/shuttle/floor4,/area/shuttle/escape) +"aV" = (/mob/living/simple_animal/construct/armoured,/mob/living/simple_animal/hostile/construct/harvester,/turf/simulated/floor/engine/cult,/area/shuttle/escape) "aW" = (/obj/structure/dresser,/turf/simulated/floor/engine/cult,/area/shuttle/escape) "aX" = (/obj/structure/table,/obj/item/weapon/storage/firstaid/o2{layer = 2.8; pixel_x = 4; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = 2; pixel_y = 6},/obj/item/weapon/storage/firstaid/regular{pixel_x = -2; pixel_y = 4},/obj/item/bodybag/cryobag{pixel_x = 5},/turf/simulated/floor/engine/cult,/area/shuttle/escape) "aY" = (/obj/effect/decal/cleanable/blood/tracks/footprints,/turf/simulated/floor/engine/cult,/area/shuttle/escape) @@ -73,17 +73,18 @@ abasatauacavajavajajawajab abaxajajayajajajajajazaAab arajaBaCacajajajajajajajaD ababababacajajajajajajajab -aEajajajajajaFajajajajajab +aEajajajajajaKajajajajajab abaGajajaFaHaIaHaFajajaJab -acajajajaHaKaIaLaHajajajac +acajajajaHaLaIaOaHajajajac acajajaFaIaIaMaIaIaFajajac -acajajajaHaNaIaOaHajajajac +acajajajaHaNaIaVaHajajajac abaPajajaFaHaQaHaFajajajaR arajajajajaSaFaSajajajajac -abababaTababacaUacaVacacab +abababaTababacaUacaracacab arajajajaWabaaabaXaYaYaZab baajajajbbabaaabbcbcbdaZab abajajbebfabaaabbgbcbdaZab ababbhbhbhabaaabbibibiabab aaabbjbjbjabaaabbjbjbjabaa "} + diff --git a/_maps/map_files/shuttles/emergency_old.dmm b/_maps/map_files/shuttles/emergency_old.dmm index db5b88cd337..faffa6374d1 100644 --- a/_maps/map_files/shuttles/emergency_old.dmm +++ b/_maps/map_files/shuttles/emergency_old.dmm @@ -31,7 +31,6 @@ "aE" = (/obj/structure/stool/bed/chair{dir = 4},/obj/structure/closet/walllocker/emerglocker{pixel_x = -28},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "aF" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "8"},/turf/simulated/floor/plating,/area/shuttle/escape) "aG" = (/obj/structure/stool/bed/chair{dir = 8},/obj/structure/closet/walllocker/emerglocker{pixel_x = 28},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) -"aH" = (/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/floor/plating,/area/shuttle/escape) "aI" = (/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/escape) "aJ" = (/obj/structure/grille,/obj/structure/window/full/shuttle{icon_state = "15"},/turf/simulated/floor/plating,/area/shuttle/escape) "aK" = (/obj/docking_port/mobile/emergency{dir = 4; dwidth = 9; height = 13; timid = 1; width = 24},/obj/machinery/door/airlock/shuttle{aiControlDisabled = 1; hackProof = 1; id_tag = "s_docking_airlock"; name = "Shuttle Hatch"},/turf/simulated/shuttle/floor,/area/shuttle/escape) @@ -76,7 +75,7 @@ aaaaarasatananauavanaraaaa abawaxawawawayawazawaxawad araAaBaCaDaAanaCaDaAaBaCar araEanaCaFaAanaCaFaAanaGar -aHaIanaCaFaAanaCaFaAanaCac +aWaIanaCaFaAanaCaFaAanaCac araAanaCaJaAanaCaJaAanaCar aKananananananananananaCar araLanaCaDaAanaCaDaAanaMar @@ -92,3 +91,4 @@ arbfaIaIbgaraaaYbhbhbhbhar biazbjbjbjbkaablbmbmbmazbn aabibobobobnaabibobobobnaa "} + diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm index fad455ed438..47c5689054c 100644 --- a/code/ATMOSPHERICS/atmospherics.dm +++ b/code/ATMOSPHERICS/atmospherics.dm @@ -66,6 +66,10 @@ Pipelines + Other Objects -> Pipe network /obj/machinery/atmospherics/update_icon() return null +/obj/machinery/atmospherics/proc/update_pipe_image() + pipe_image = image(src, loc, layer = 20, dir = dir) //the 20 puts it above Byond's darkness (not its opacity view) + pipe_image.plane = HUD_PLANE + /obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0) if(!istype(icon_manager)) if(!safety) //to prevent infinite loops diff --git a/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm b/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm index 37ce3b19057..299d0c20e22 100644 --- a/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm +++ b/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm @@ -100,6 +100,8 @@ overlays += icon_manager.get_atmos_icon("device", , , vent_icon) + update_pipe_image() + /obj/machinery/atmospherics/unary/vent_pump/update_underlays() if(..()) underlays.Cut() diff --git a/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm index 244e9c26aa3..5554723c945 100644 --- a/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm @@ -107,6 +107,7 @@ scrubber_icon = "scrubberweld" overlays += icon_manager.get_atmos_icon("device", , , scrubber_icon) + update_pipe_image() /obj/machinery/atmospherics/unary/vent_scrubber/update_underlays() if(..()) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 4ec7b664efe..daf9b889f53 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -257,10 +257,11 @@ 0, 0, 1, 0,\ 0, 0, 0, 1) -#define MATRIX_GREYSCALE list(0.3, 0.3, 0.3, 0,\ - 0.3, 0.3, 0.3, 0,\ - 0.3, 0.3, 0.3, 0,\ - 0, 0, 0, 1) +#define MATRIX_GREYSCALE list(0.33, 0.33, 0.33, 0,\ + 0.33, 0.33, 0.33, 0,\ + 0.33, 0.33, 0.33, 0,\ + 0.00, 0.00, 0.00, 1,\ + 0.00, 0.00, 0.00, 0) //Gun trigger guards #define TRIGGER_GUARD_ALLOW_ALL -1 #define TRIGGER_GUARD_NONE 0 diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index d39cc600221..05200eea7dd 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -27,3 +27,10 @@ #define DONATOR_PUBLIC 32768 #define TOGGLES_DEFAULT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC|MEMBER_PUBLIC|DONATOR_PUBLIC) + +// Playtime tracking system, see jobs_exp.dm +#define EXP_TYPE_LIVING "Living" +#define EXP_TYPE_CREW "Crew" +#define EXP_TYPE_SPECIAL "Special" +#define EXP_TYPE_GHOST "Ghost" +#define EXP_TYPE_EXEMPT "Exempt" \ No newline at end of file diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 155f7dfae58..883856cc9b7 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -209,7 +209,7 @@ var/turf/ear = get_turf(M) if(ear) // Ghostship is magic: Ghosts can hear radio chatter from anywhere - if(speaker_coverage[ear] || (istype(M, /mob/dead/observer) && (M.client) && (M.client.prefs.toggles & CHAT_GHOSTRADIO))) + if(speaker_coverage[ear] || (istype(M, /mob/dead/observer) && M.get_preference(CHAT_GHOSTRADIO))) . |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down. return . diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index ed0b7887e5a..c8d4fd2c659 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -49,6 +49,9 @@ whitelisted_species += S.name init_subtypes(/datum/crafting_recipe, crafting_recipes) + + all_cults = typesof(/datum/cult_info) + return 1 /* // Uncomment to debug chemical reaction list. diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index cfbd9c854cd..86b5e7b75e6 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -123,6 +123,7 @@ result += e else result = first - second + return result /* diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 61e0deec1ad..f8aed0096b8 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1816,7 +1816,7 @@ var/global/list/g_fancy_list_of_types = null sleep(world.tick_lag*4) //you might be thinking of adding more steps to this, or making it use a loop and a counter var // not worth it. - + /proc/getpois(mobs_only=0,skip_mindless=0) var/list/mobs = sortmobs() var/list/names = list() @@ -1878,4 +1878,13 @@ var/global/list/g_fancy_list_of_types = null spawn(0) animate(C, color = initial(C.color), time = flash_time) -#define RANDOM_COLOUR (rgb(rand(0,255),rand(0,255),rand(0,255))) \ No newline at end of file +#define RANDOM_COLOUR (rgb(rand(0,255),rand(0,255),rand(0,255))) + +/proc/make_bit_triplet() + var/list/num_sample = list(1, 2, 3, 4, 5, 6, 7, 8, 9) + var/result = 0 + for(var/i = 0, i < 3, i++) + var/num = pick(num_sample) + num_sample -= num + result += (1 << num) + return result \ No newline at end of file diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 8507b8f3edc..49b7d8335f6 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -33,6 +33,6 @@ var/global/list/shuttle_caller_list = list() //list of all communication cons var/global/list/tracked_implants = list() //list of all current implants that are tracked to work out what sort of trek everyone is on. Sadly not on lavaworld not implemented... var/global/list/pinpointer_list = list() //list of all pinpointers. Used to change stuff they are pointing to all at once. var/global/list/abductor_equipment = list() //list of all abductor equipment -var/global/list/global_intercoms = list() //list of all intercomms, across all z-levels +var/global/list/global_intercoms = list() //list of all intercomms, across all z-levels var/global/list/poi_list = list() //list of points of interest for observe/follow \ No newline at end of file diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index d844292fbb1..7e146a8fc4e 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -108,6 +108,7 @@ #define ui_construct_pull "EAST-1:28,SOUTH+1:10" //above the zone_sel icon +#define ui_construct_health "EAST,CENTER:15" //same height as humans, hugging the right border //Pop-up inventory #define ui_shoes "WEST+1:8,SOUTH:5" diff --git a/code/_onclick/hud/constructs.dm b/code/_onclick/hud/constructs.dm new file mode 100644 index 00000000000..7ed1d66724f --- /dev/null +++ b/code/_onclick/hud/constructs.dm @@ -0,0 +1,63 @@ +/mob/living/simple_animal/hostile/construct/armoured/create_mob_hud() + if(client && !hud_used) + hud_used = new /datum/hud/construct/armoured(src) + +/mob/living/simple_animal/hostile/construct/behemoth/create_mob_hud() + if(client && !hud_used) + hud_used = new /datum/hud/construct/armoured(src) + +/datum/hud/construct/armoured/New(mob/owner) + ..() + mymob.healths = new /obj/screen() + mymob.healths.icon = 'icons/mob/screen_construct.dmi' + mymob.healths.icon_state = "juggernaut_health0" + mymob.healths.name = "health" + mymob.healths.screen_loc = ui_construct_health + infodisplay += mymob.healths + +/mob/living/simple_animal/hostile/construct/builder/create_mob_hud() + if(client && !hud_used) + hud_used = new /datum/hud/construct/builder(src) + +/datum/hud/construct/builder/New(mob/owner) + ..() + mymob.healths = new /obj/screen() + mymob.healths.icon = 'icons/mob/screen_construct.dmi' + mymob.healths.icon_state = "artificer_health0" + mymob.healths.name = "health" + mymob.healths.screen_loc = ui_construct_health + infodisplay += mymob.healths + +/mob/living/simple_animal/hostile/construct/wraith/create_mob_hud() + if(client && !hud_used) + hud_used = new /datum/hud/construct/wraith(src) + +/datum/hud/construct/wraith/New(mob/owner) + ..() + mymob.healths = new /obj/screen() + mymob.healths.icon = 'icons/mob/screen_construct.dmi' + mymob.healths.icon_state = "wraith_health0" + mymob.healths.name = "health" + mymob.healths.screen_loc = ui_construct_health + infodisplay += mymob.healths + +/mob/living/simple_animal/hostile/construct/harvester/create_mob_hud() + if(client && !hud_used) + hud_used = new /datum/hud/construct/harvester(src) + +/datum/hud/construct/harvester/New(mob/owner) + ..() + mymob.healths = new /obj/screen() + mymob.healths.icon = 'icons/mob/screen_construct.dmi' + mymob.healths.icon_state = "harvester_health0" + mymob.healths.name = "health" + mymob.healths.screen_loc = ui_construct_health + infodisplay += mymob.healths + +/datum/hud/construct/New(mob/owner) + ..() + mymob.pullin = new /obj/screen/pull() + mymob.pullin.icon = 'icons/mob/screen_construct.dmi' + mymob.pullin.icon_state = "pull0" + mymob.pullin.name = "pull" + mymob.pullin.screen_loc = ui_construct_pull \ No newline at end of file diff --git a/code/controllers/Processes/nano_mob_hunter.dm b/code/controllers/Processes/nano_mob_hunter.dm new file mode 100644 index 00000000000..469ce22651d --- /dev/null +++ b/code/controllers/Processes/nano_mob_hunter.dm @@ -0,0 +1,157 @@ +var/global/datum/controller/process/mob_hunt/mob_hunt_server + +/datum/controller/process/mob_hunt + var/max_normal_spawns = 15 //change this to adjust the number of normal spawns that can exist at one time. trapped spawns (from traitors) don't count towards this + var/list/normal_spawns = list() + var/max_trap_spawns = 15 //change this to adjust the number of trap spawns that can exist at one time. traps spawned beyond this point clear the oldest traps + var/list/trap_spawns = list() + var/list/connected_clients = list() + var/server_status = 1 //1 is online, 0 is offline + var/reset_cooldown = 0 //number of controller cycles before the manual_reboot proc can be used again (ignored if server is offline so you can always boot back up) + var/obj/machinery/computer/mob_battle_terminal/red_terminal + var/obj/machinery/computer/mob_battle_terminal/blue_terminal + var/battle_turn = null + +/datum/controller/process/mob_hunt/setup() + name = "Nano-Mob Hunter GO Server" + start_delay = 20 + mob_hunt_server = src + +/datum/controller/process/mob_hunt/doWork() + if(reset_cooldown) //if reset_cooldown is set (we are on cooldown, duh), reduce the remaining cooldown every cycle + reset_cooldown-- + if(!server_status) + return + client_mob_update() + if(normal_spawns.len < max_normal_spawns) + spawn_mob() + +//leaving this here in case admins want to use it for a random mini-event or something +/datum/controller/process/mob_hunt/proc/server_crash(recover_time = 3000) + server_status = 0 + for(var/datum/data/pda/app/mob_hunter_game/client in connected_clients) + client.disconnect("Server Crash") + for(var/obj/effect/nanomob/N in trap_spawns) + N.despawn() + for(var/obj/effect/nanomob/N in normal_spawns) + N.despawn() + //just in case + normal_spawns.Cut() + trap_spawns.Cut() + connected_clients.Cut() + if(!isnum(recover_time)) + recover_time = 3000 + if(recover_time > 0) //when provided with a negative or zero valued recover_time argument, the server won't auto-restart but can be manually rebooted still + //set a timer to automatically recover after recover_time has passed (can be manually restarted if you get impatient too) + addtimer(src, "auto_recover", recover_time, TRUE) + +/datum/controller/process/mob_hunt/proc/client_mob_update() + var/list/ex_players = list() + for(var/datum/data/pda/app/mob_hunter_game/client in connected_clients) + var/mob/living/carbon/human/H = client.get_player() + if(connected_clients[client]) + if(!H || H != connected_clients[client]) + ex_players |= connected_clients[client] + connected_clients[client] = H + if(ex_players.len) //to make sure we don't do this if we didn't lose any player since the last update + for(var/obj/effect/nanomob/N in (normal_spawns + trap_spawns)) + N.conceal(ex_players) + +/datum/controller/process/mob_hunt/proc/auto_recover() + if(server_status != 0) + return + server_status = 1 + while(normal_spawns.len < max_normal_spawns) //repopulate the server's spawns completely if we auto-recover from crash + spawn_mob() + +/datum/controller/process/mob_hunt/proc/manual_reboot() + if(server_status && reset_cooldown) + return 0 + for(var/obj/effect/nanomob/N in trap_spawns) + N.despawn() + for(var/obj/effect/nanomob/N in normal_spawns) + N.despawn() + server_status = 1 + reset_cooldown = 25 //25 controller cycle cooldown for manual restarts + return 1 + +/datum/controller/process/mob_hunt/proc/spawn_mob() + var/list/nanomob_types = subtypesof(/datum/mob_hunt) + var/datum/mob_hunt/mob_info = pick(nanomob_types) + new mob_info() + +/datum/controller/process/mob_hunt/proc/register_spawn(datum/mob_hunt/mob_info) + if(!mob_info) + return 0 + var/obj/effect/nanomob/new_mob = new /obj/effect/nanomob(mob_info.spawn_point, mob_info) + normal_spawns += new_mob + new_mob.reveal() + return 1 + +/datum/controller/process/mob_hunt/proc/register_trap(datum/mob_hunt/mob_info) + if(!mob_info) + return 0 + if(!mob_info.is_trap) + return register_spawn(mob_info) + var/obj/effect/nanomob/new_mob = new /obj/effect/nanomob(mob_info.spawn_point, mob_info) + trap_spawns += new_mob + new_mob.reveal() + if(trap_spawns.len > max_trap_spawns) + var/obj/effect/nanomob/old_trap = trap_spawns[1] + old_trap.despawn() + return 1 + +/datum/controller/process/mob_hunt/proc/start_check() + if(battle_turn) //somehow we got called mid-battle, so lets just stop now + return + if(red_terminal && red_terminal.ready && blue_terminal && blue_terminal.ready) + battle_turn = pick("Red", "Blue") + red_terminal.audible_message("Battle starting!", null, 5) + blue_terminal.audible_message("Battle starting!", null, 5) + if(battle_turn == "Red") + red_terminal.audible_message("Red Player's Turn!", null, 5) + else if(battle_turn == "Blue") + blue_terminal.audible_message("Blue Player's Turn!", null, 5) + +/datum/controller/process/mob_hunt/proc/launch_attack(team, raw_damage, datum/mob_type/attack_type) + if(!team || !raw_damage) + return + var/obj/machinery/computer/mob_battle_terminal/target = null + if(team == "Red") + target = blue_terminal + else if(team == "Blue") + target = red_terminal + else + return + target.receive_attack(raw_damage, attack_type) + +/datum/controller/process/mob_hunt/proc/end_battle(loser, surrender = 0) + var/obj/machinery/computer/mob_battle_terminal/winner_terminal = null + var/obj/machinery/computer/mob_battle_terminal/loser_terminal = null + if(loser == "Red") + loser_terminal = red_terminal + winner_terminal = blue_terminal + else if (loser == "Blue") + loser_terminal = blue_terminal + winner_terminal = red_terminal + battle_turn = null + winner_terminal.ready = 0 + loser_terminal.ready = 0 + if(surrender) //surrender doesn't give exp, to avoid people just farming exp without actually doing a battle + winner_terminal.audible_message("Your rival surrendered!", null, 2) + else + var/progress_message = winner_terminal.mob_info.gain_exp() + winner_terminal.audible_message("[winner_terminal.team] Player wins!", null, 5) + winner_terminal.audible_message(progress_message, null, 2) + +/datum/controller/process/mob_hunt/proc/end_turn() + red_terminal.updateUsrDialog() + blue_terminal.updateUsrDialog() + if(!battle_turn) + return + if(battle_turn == "Red") + battle_turn = "Blue" + blue_terminal.audible_message("Blue's turn.", null, 5) + else if(battle_turn == "Blue") + battle_turn = "Red" + blue_terminal.audible_message("Red's turn.", null, 5) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 0f4ad0eb47c..36b49643813 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -89,6 +89,8 @@ var/overflow_server_url var/forbid_singulo_possession = 0 + var/check_randomizer = 0 + //game_options.txt configs var/health_threshold_softcrit = 0 @@ -127,6 +129,10 @@ var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database var/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database + var/use_exp_tracking = 0 + var/use_exp_restrictions = 0 + var/use_exp_restrictions_admin_bypass = 0 + var/simultaneous_pm_warning_timeout = 100 var/assistant_maint = 0 //Do assistants get maint access? @@ -140,6 +146,7 @@ var/main_irc = "" var/admin_irc = "" var/admin_notify_irc = "" + var/cidrandomizer_irc = "" var/python_path = "" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix var/default_laws = 0 //Controls what laws the AI spawns with. @@ -240,6 +247,15 @@ if("use_age_restriction_for_antags") config.use_age_restriction_for_antags = 1 + if("use_exp_tracking") + config.use_exp_tracking = 1 + + if("use_exp_restrictions") + config.use_exp_restrictions = 1 + + if("use_exp_restrictions_admin_bypass") + config.use_exp_restrictions_admin_bypass = 1 + if("jobs_have_minimal_access") config.jobs_have_minimal_access = 1 @@ -405,6 +421,9 @@ if("forbid_singulo_possession") forbid_singulo_possession = 1 + if("check_randomizer") + check_randomizer = 1 + if("popup_admin_pm") config.popup_admin_pm = 1 @@ -472,6 +491,9 @@ if("admin_notify_irc") config.admin_notify_irc = value + if("cidrandomizer_irc") + config.cidrandomizer_irc = value + if("python_path") if(value) config.python_path = value diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index 3fe74ae04eb..027101df146 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -17,8 +17,7 @@ message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.") return - -/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Lighting","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote","Diseases","Fires","Mob","NPC AI","Shuttle","Timer","Weather","Space")) +/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Lighting","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote","Diseases","Fires","Mob","NPC AI","Shuttle","Timer","Weather","Space","Mob Hunt Server")) set category = "Debug" set name = "Debug Controller" set desc = "Debug the various periodic loop controllers for the game (be careful!)" @@ -100,6 +99,9 @@ if("Space") debug_variables(space_manager) feedback_add_details("admin_verb","DSpace") + if("Mob Hunt Server") + debug_variables(mob_hunt_server) + feedback_add_details("admin_verb","DMobHuntServer") message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") return diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 50595bb23a6..fcf1ded97cc 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -791,8 +791,8 @@ if(!(src in ticker.mode.cult)) ticker.mode.add_cultist(src) special_role = SPECIAL_ROLE_CULTIST - to_chat(current, "You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of Nar-Sie.") - to_chat(current, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") + to_chat(current, "You catch a glimpse of the Realm of [ticker.mode.cultdat.entity_name], [ticker.mode.cultdat.entity_title3]. You now see how flimsy the world is, you see that it should be open to the knowledge of [ticker.mode.cultdat.entity_name].") + to_chat(current, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve [ticker.mode.cultdat.entity_title2] above all else. Bring It back.") log_admin("[key_name(usr)] has culted [key_name(current)]") message_admins("[key_name_admin(usr)] has culted [key_name_admin(current)]") if("tome") @@ -1315,17 +1315,16 @@ ticker.mode.cult += src ticker.mode.update_cult_icons_added(src) special_role = SPECIAL_ROLE_CULTIST - to_chat(current, "You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of Nar-Sie.") - to_chat(current, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") + to_chat(current, "You catch a glimpse of the Realm of [ticker.mode.cultdat.entity_name], [ticker.mode.cultdat.entity_title2]. You now see how flimsy the world is, you see that it should be open to the knowledge of [ticker.mode.cultdat.entity_name].") + to_chat(current, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") var/datum/game_mode/cult/cult = ticker.mode if(istype(cult)) cult.memorize_cult_objectives(src) else - var/explanation = "Summon Nar-Sie via the use of the appropriate rune (Hell join self). It will only work if nine cultists stand on and around it." + var/explanation = "Summon [ticker.mode.cultdat.entity_name] via the use of the appropriate rune. It will only work if nine cultists stand on and around it." to_chat(current, "Objective #1: [explanation]") current.memory += "Objective #1: [explanation]
" - to_chat(current, "The convert rune is join blood self") - current.memory += "The convert rune is join blood self
" + var/mob/living/carbon/human/H = current if(istype(H)) diff --git a/code/datums/spells/construct_spells.dm b/code/datums/spells/construct_spells.dm index 8cbc46e2f03..8632b89df12 100644 --- a/code/datums/spells/construct_spells.dm +++ b/code/datums/spells/construct_spells.dm @@ -2,11 +2,14 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser charge_max = 1800 + action_icon_state = "lesserconstruct" + action_background_icon_state = "bg_cult" /obj/effect/proc_holder/spell/aoe_turf/conjure/floor name = "Floor Construction" desc = "This spell constructs a cult floor" - + action_icon_state = "floorconstruct" + action_background_icon_state = "bg_cult" school = "conjuration" charge_max = 20 clothes_req = 0 @@ -19,7 +22,8 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/wall name = "Lesser Construction" desc = "This spell constructs a cult wall" - + action_icon_state = "lesserconstruct" + action_background_icon_state = "bg_cult" school = "conjuration" charge_max = 100 clothes_req = 0 @@ -47,7 +51,8 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone name = "Summon Soulstone" desc = "This spell reaches into Nar-Sie's realm, summoning one of the legendary fragments across time and space" - + action_icon_state = "summonsoulstone" + action_background_icon_state = "bg_cult" school = "conjuration" charge_max = 3000 clothes_req = 0 @@ -57,25 +62,47 @@ summon_type = list(/obj/item/device/soulstone) +/obj/effect/proc_holder/spell/aoe_turf/conjure/pylon + name = "Cult Pylon" + desc = "This spell conjures a fragile crystal from Nar-Sie's realm. Makes for a convenient light source." + action_icon_state = "summonsoulstone" + action_background_icon_state = "bg_cult" + school = "conjuration" + charge_max = 200 + clothes_req = 0 + invocation = "none" + invocation_type = "none" + range = 0 + + summon_type = list(/obj/structure/cult/functional/pylon) + /obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall name = "Shield" desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire" - + action_icon_state = "cultforcewall" + action_background_icon_state = "bg_cult" school = "transmutation" charge_max = 300 clothes_req = 0 invocation = "none" invocation_type = "none" range = 0 - summon_type = list(/obj/effect/forcefield) + summon_type = list(/obj/effect/forcefield/cult) summon_lifespan = 200 +/obj/effect/forcefield/cult + desc = "That eerie looking obstacle seems to have been pulled from another dimension through sheer force" + name = "eldritch wall" + icon = 'icons/effects/effects.dmi' + icon_state = "m_shield_cult" + light_color = LIGHT_COLOR_PURE_RED /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift name = "Phase Shift" desc = "This spell allows you to pass through walls" - + action_icon_state = "phaseshift" + action_background_icon_state = "bg_cult" school = "transmutation" charge_max = 200 clothes_req = 0 @@ -91,7 +118,7 @@ /obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser name = "Lesser Magic Missile" desc = "This spell fires several, slow moving, magic projectiles at nearby targets." - + action_background_icon_state = "bg_cult" school = "evocation" charge_max = 400 clothes_req = 0 @@ -103,7 +130,8 @@ /obj/effect/proc_holder/spell/targeted/smoke/disable name = "Paralysing Smoke" desc = "This spell spawns a cloud of paralysing smoke." - + action_icon_state = "parasmoke" + action_background_icon_state = "bg_cult" school = "conjuration" charge_max = 200 clothes_req = 0 diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 83a344d8611..f64b914f3eb 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -148,17 +148,18 @@ return 1 /mob/living/forceMove(atom/destination) - stop_pulling() if(buckled) - buckled.unbuckle_mob(src,force=1) - // in lieu of "unbuckle_all_mobs" + addtimer(src, "check_buckled", 1, TRUE) if(buckled_mob) - unbuckle_mob(buckled_mob,force=1) + addtimer(buckled_mob, "check_buckled", 1, TRUE) + if(pulling) + addtimer(src, "check_pull", 1, TRUE) . = ..() if(client) reset_perspective(destination) update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall. + //called when src is thrown into hit_atom /atom/movable/proc/throw_impact(atom/hit_atom, var/speed) if(istype(hit_atom,/mob/living)) diff --git a/code/game/gamemodes/antag_hud.dm b/code/game/gamemodes/antag_hud.dm index 172c2c1e54c..4b290932e8e 100644 --- a/code/game/gamemodes/antag_hud.dm +++ b/code/game/gamemodes/antag_hud.dm @@ -10,8 +10,7 @@ CRASH("join_hud(): [M] ([M.type]) is not a mob!") if(M.mind.antag_hud && !slave) //note: please let this runtime if a mob has no mind, as mindless mobs shouldn't be getting antagged M.mind.antag_hud.leave_hud(M) - if(!ismask(M))//FUCK YOU MASK OF NARNAR! - add_to_hud(M) + add_to_hud(M) if(self_visible) add_hud_to(M) M.mind.antag_hud = src diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 63195a186ab..6a92052eed5 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -1,9 +1,8 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 +var/global/list/all_cults = list() /datum/game_mode var/list/datum/mind/cult = list() - var/list/allwords = list("travel","self","see","hell","blood","join","tech","destroy", "other", "hide") - /proc/iscultist(mob/living/M as mob) return istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.cult) @@ -22,8 +21,20 @@ var/mob/living/carbon/human/H = mind.current if(isloyal(H)) return 0 + if(issilicon(mind.current)) + return 0 //can't convert machines, that's ratvar's thing + if(isguardian(mind.current)) + var/mob/living/simple_animal/hostile/guardian/G = mind.current + if(!iscultist(G.summoner)) + return 0 //can't convert it unless the owner is converted return 1 +/proc/is_sacrifice_target(datum/mind/mind) + if(istype(ticker.mode.name, "cult")) + var/datum/game_mode/cult/cult_mode = ticker.mode + if(mind == cult_mode.sacrifice_target) + return 1 + return 0 /datum/game_mode/cult name = "cult" @@ -37,17 +48,37 @@ var/datum/mind/sacrifice_target = null var/finished = 0 - var/list/startwords = list("blood","join","self","hell") var/list/objectives = list() var/eldergod = 1 //for the summon god objective + var/demons_summoned = 0 var/acolytes_needed = 4 //for the survive objective - base number of acolytes, increased by 1 for every 10 players var/const/min_cultists_to_start = 3 var/const/max_cultists_to_start = 4 var/acolytes_survived = 0 + var/narsie_condition_cleared = 0 //allows Nar-Sie to be summonned during cult rounds. set to 1 once the cult reaches the second phase. + var/current_objective = 1 //equals the number of cleared objectives + 1 + var/prenarsie_objectives = 2 //how many objectives at most before the cult gets to summon narsie + var/list/bloody_floors = list() + var/spilltarget = 100 //how many floor tiles must be covered in blood to complete the bloodspill objective + var/convert_target = 0 //how many members the cult needs to reach to complete the convert objective + var/harvested = 0 + + var/list/sacrificed = list() //contains the mind of the sacrifice target ONCE the sacrifice objective has been completed + var/mass_convert = 0 //set to 1 if the convert objective has been accomplised once that round + var/spilled_blood = 0 //set to 1 if the bloodspill objective has been accomplised once that round + var/max_spilled_blood = 0 //highest quantity of blood covered tiles during the round + var/bonus = 0 //set to 1 if the cult has completed the bonus (third phase) objective (harvest, hijack, massacre) + + var/harvest_target = 10 + var/massacre_target = 5 + + var/escaped_shuttle = 0 + var/escaped_pod = 0 + var/survivors = 0 /datum/game_mode/cult/announce() to_chat(world, "The current game mode is - Cult!") @@ -55,16 +86,9 @@ /datum/game_mode/cult/pre_setup() - if(prob(50)) - objectives += "survive" - objectives += "sacrifice" - else - objectives += "eldergod" - objectives += "sacrifice" - if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs - + ..() var/list/cultists_possible = get_players_for_role(ROLE_CULTIST) for(var/cultists_number = 1 to max_cultists_to_start) @@ -92,10 +116,13 @@ for(var/datum/mind/cult_mind in cult) equip_cultist(cult_mind.current) - grant_runeword(cult_mind.current) + cult_mind.current.faction |= "cult" + var/datum/action/innate/cultcomm/C = new() + C.Grant(cult_mind.current) update_cult_icons_added(cult_mind) - to_chat(cult_mind.current, "\blue You are a member of the cult!") - memorize_cult_objectives(cult_mind) + to_chat(cult_mind.current, "You catch a glimpse of the Realm of [ticker.mode.cultdat.entity_name], [ticker.mode.cultdat.entity_title3]. You now see how flimsy the world is, you see that it should be open to the knowledge of [ticker.mode.cultdat.entity_name].") + + first_phase() ..() @@ -106,17 +133,19 @@ switch(objectives[obj_count]) if("survive") explanation = "Our knowledge must live on. Make sure at least [acolytes_needed] acolytes escape on the shuttle to spread their work on an another station." + if("convert") + explanation = "We must increase our influence before we can summon [ticker.mode.cultdat.entity_name], Convert [convert_target] crew members. Take it slowly to avoid raising suspicions." + if("bloodspill") + explanation = "We must prepare this place for [ticker.mode.cultdat.entity_title1]'s coming. Spill blood and gibs over [spilltarget] floor tiles." if("sacrifice") if(sacrifice_target) - explanation = "Sacrifice [sacrifice_target.current.real_name], the [sacrifice_target.assigned_role]. You will need the sacrifice rune (hell blood join) and three acolytes to do so." + explanation = "Sacrifice [sacrifice_target.current.real_name], the [sacrifice_target.assigned_role]. You will need the sacrifice rune and three acolytes to do so." else explanation = "Free objective." if("eldergod") - explanation = "Summon Nar-Sie via the use of the appropriate rune (Hell join self). It will only work if nine cultists stand on and around it." + explanation = "Summon [ticker.mode.cultdat.entity_name]. It will only work if nine cultists stand on and around it." to_chat(cult_mind.current, "Objective #[obj_count]: [explanation]") cult_mind.memory += "Objective #[obj_count]: [explanation]
" - to_chat(cult_mind.current, "The convert rune is join blood self") - cult_mind.memory += "The convert rune is join blood self
" /datum/game_mode/proc/equip_cultist(mob/living/carbon/human/mob) @@ -128,8 +157,6 @@ to_chat(mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") mob.mutations.Remove(CLUMSY) - add_cult_viewpoint(mob) // give them a viewpoint - var/obj/item/weapon/paper/talisman/supply/T = new(mob) var/list/slots = list ( "backpack" = slot_in_backpack, @@ -140,49 +167,25 @@ ) var/where = mob.equip_in_one_of_slots(T, slots) if(!where) - to_chat(mob, "Unfortunately, you weren't able to get a talisman. This is very bad and you should adminhelp immediately.") + to_chat(mob, "Unfortunately, you weren't able to get a talisman. This is very bad and you should adminhelp immediately.") else - to_chat(mob, "You have a talisman in your [where], one that will help you start the cult on this station. Use it well and remember - there are others.") + to_chat(mob, "You have a talisman in your [where], one that will help you start the cult on this station. Use it well and remember - there are others.") mob.update_icons() return 1 -/datum/game_mode/cult/grant_runeword(mob/living/carbon/human/cult_mob, var/word) - if(!word) - if(startwords.len > 0) - word=pick(startwords) - startwords -= word - return ..(cult_mob,word) - - -/datum/game_mode/proc/grant_runeword(mob/living/carbon/human/cult_mob, var/word) - if(!cultwords["travel"]) - runerandom() - if(!word) - word=pick(allwords) - var/wordexp = "[cultwords[word]] is [word]..." - to_chat(cult_mob, "\red [pick("You remember something from the dark teachings of your master","You hear a dark voice on the wind","Black blood oozes into your vision and forms into symbols","You have a vision of a [pick("crow","raven","vulture","parrot")] it squawks","You catch a brief glimmer of the otherside")]... [wordexp]") - cult_mob.mind.store_memory("You remember that [wordexp]", 0, 0) - - -/datum/game_mode/proc/add_cult_viewpoint(var/mob/target) - for(var/obj/cult_viewpoint/viewpoint in target) - return - var/obj/cult_viewpoint/viewpoint = new(target) - viewpoint.loc = target - return viewpoint - - /datum/game_mode/proc/add_cultist(datum/mind/cult_mind) //BASE if(!istype(cult_mind)) return 0 if(!(cult_mind in cult) && is_convertable_to_cult(cult_mind)) cult += cult_mind - add_cult_viewpoint(cult_mind.current) - update_cult_icons_added(cult_mind) + cult_mind.current.faction |= "cult" + var/datum/action/innate/cultcomm/C = new() + C.Grant(cult_mind.current) cult_mind.current.attack_log += "\[[time_stamp()]\] Has been converted to the cult!" if(jobban_isbanned(cult_mind.current, ROLE_CULTIST)) replace_jobbaned_player(cult_mind.current, ROLE_CULTIST) + update_cult_icons_added(cult_mind) return 1 @@ -195,41 +198,19 @@ /datum/game_mode/proc/remove_cultist(datum/mind/cult_mind, show_message = 1) if(cult_mind in cult) cult -= cult_mind - to_chat(cult_mind.current, "\red An unfamiliar white light flashes through your mind, cleansing the taint of the dark-one and the memories of your time as his servant with it.") + to_chat(cult_mind.current, "An unfamiliar white light flashes through your mind, cleansing the taint of the dark-one and the memories of your time as his servant with it.") + cult_mind.current.faction -= "cult" cult_mind.memory = "" cult_mind.special_role = null - // remove the cult viewpoint object - var/obj/viewpoint = getCultViewpoint(cult_mind.current) - qdel(viewpoint) - + for(var/datum/action/innate/cultcomm/C in cult_mind.current.actions) + qdel(C) update_cult_icons_removed(cult_mind) if(show_message) for(var/mob/M in viewers(cult_mind.current)) to_chat(M, "[cult_mind.current] looks like they just reverted to their old faith!") -/datum/game_mode/proc/add_cult_icon_to_spirit(mob/spirit/currentSpirit) - if(!istype(currentSpirit)) - return FALSE - if(currentSpirit.client) - var/datum/atom_hud/antag/maskhud = huds[ANTAG_HUD_CULT] - maskhud.join_hud(currentSpirit) - set_antag_hud(currentSpirit,"hudcultist") - - -/datum/game_mode/proc/remove_cult_icon_from_spirit(mob/spirit/currentSpirit) - if(!istype(currentSpirit)) - return FALSE - if(currentSpirit.client) - var/datum/atom_hud/antag/maskhud = huds[ANTAG_HUD_CULT] - maskhud.leave_hud(currentSpirit) - set_antag_hud(currentSpirit, null) - - /datum/game_mode/proc/update_cult_icons_added(datum/mind/cult_mind) - for(var/mob/spirit/currentSpirit in spirits) - add_cult_icon_to_spirit(currentSpirit,cult_mind) - var/datum/atom_hud/antag/culthud = huds[ANTAG_HUD_CULT] culthud.join_hud(cult_mind.current) set_antag_hud(cult_mind.current, "hudcultist") @@ -237,9 +218,6 @@ /datum/game_mode/proc/update_cult_icons_removed(datum/mind/cult_mind) - for(var/mob/spirit/currentSpirit in spirits) - remove_cult_icon_from_spirit(currentSpirit,cult_mind) - var/datum/atom_hud/antag/culthud = huds[ANTAG_HUD_CULT] culthud.leave_hud(cult_mind.current) set_antag_hud(cult_mind.current, null) @@ -259,9 +237,18 @@ cult_fail += check_survive() //the proc returns 1 if there are not enough cultists on the shuttle, 0 otherwise if(objectives.Find("eldergod")) cult_fail += eldergod //1 by default, 0 if the elder god has been summoned at least once + if(objectives.Find("slaughter")) + if(!demons_summoned) + cult_fail++ if(objectives.Find("sacrifice")) if(sacrifice_target && !(sacrifice_target in sacrificed)) //if the target has been sacrificed, ignore this step. otherwise, add 1 to cult_fail cult_fail++ + if(objectives.Find("convert")) + if(cult.len < convert_target) + cult_fail++ + if(objectives.Find("bloodspill")) + if(max_spilled_blood < spilltarget) + cult_fail++ return cult_fail //if any objectives aren't met, failure @@ -287,15 +274,16 @@ /datum/game_mode/cult/declare_completion() + bonus_check() if(!check_cult_victory()) feedback_set_details("round_end_result","win - cult win") feedback_set("round_end_result",acolytes_survived) - to_chat(world, "\red The cult wins! It has succeeded in serving its dark masters!") + to_chat(world, " The cult wins! It has succeeded in serving its dark masters!") else feedback_set_details("round_end_result","loss - staff stopped the cult") feedback_set("round_end_result",acolytes_survived) - to_chat(world, "\red The staff managed to stop the cult!") + to_chat(world, " The staff managed to stop the cult!") var/text = "Cultists escaped: [acolytes_survived]" @@ -324,11 +312,59 @@ feedback_add_details("cult_objective","cult_sacrifice|FAIL|GIBBED") if("eldergod") if(!eldergod) - explanation = "Summon Nar-Sie. Success!" + explanation = "Summon [ticker.mode.cultdat.entity_name]. Success!" feedback_add_details("cult_objective","cult_narsie|SUCCESS") else - explanation = "Summon Nar-Sie. Fail." + explanation = "Summon [ticker.mode.cultdat.entity_name]. Fail." feedback_add_details("cult_objective","cult_narsie|FAIL") + if("slaughter") + if(demons_summoned) + explanation = "Bring the Slaughter. Success!" + feedback_add_details("cult_objective","cult_demons|SUCCESS") + else + explanation = "Bring the Slaughter. Fail." + feedback_add_details("cult_objective","cult_demons|FAIL") + + if("convert")//convert half the crew + if(obj_count < objectives.len) + explanation = "Convert [convert_target] crewmembers ([cult.len] cultists at round end). Success!" + feedback_add_details("cult_objective","cult_convertion|SUCCESS") + else + explanation = "Convert [convert_target] crewmembers ([cult.len] total cultists). Fail!" + feedback_add_details("cult_objective","cult_convertion|FAIL") + + if("bloodspill")//cover a large portion of the station in blood + if(obj_count < objectives.len) + explanation = "Cover [spilltarget] tiles of the station in blood (The peak number of covered tiles was: [max_spilled_blood]). Success!" + feedback_add_details("cult_objective","cult_bloodspill|SUCCESS") + else + explanation = "Cover [spilltarget] tiles of the station in blood (The peak number of covered tiles was: [max_spilled_blood]). Fail!" + feedback_add_details("cult_objective","cult_bloodspill|FAIL") + + if("harvest") + if(harvested > harvest_target) + explanation = "Offer [harvest_target] humans for [ticker.mode.cultdat.entity_name]'s first meal of the day. ([harvested] eaten) Success!" + feedback_add_details("cult_objective","cult_harvest|SUCCESS") + else + explanation = "Offer [harvest_target] humans for [ticker.mode.cultdat.entity_name]'s first meal of the day. ([harvested] eaten) Fail!" + feedback_add_details("cult_objective","cult_harvest|FAIL") + + if("hijack") + if(!escaped_shuttle) + explanation = "Do not let a single non-cultist board the Escape Shuttle. ([escaped_shuttle] escaped on the shuttle) ([escaped_pod] escaped on pods) Success!" + feedback_add_details("cult_objective","cult_hijack|SUCCESS") + else + explanation = "Do not let a single non-cultist board the Escape Shuttle. ([escaped_shuttle] escaped on the shuttle) ([escaped_pod] escaped on pods) Fail!" + feedback_add_details("cult_objective","cult_hijack|FAIL") + + if("massacre") + if(survivors < massacre_target) + explanation = "Massacre the crew until less than [massacre_target] people are left on the station. ([survivors] humans left alive) Success!" + feedback_add_details("cult_objective","cult_massacre|SUCCESS") + else + explanation = "Massacre the crew until less than [massacre_target] people are left on the station. ([survivors] humans left alive) Fail!" + feedback_add_details("cult_objective","cult_massacre|FAIL") + text += "
Objective #[obj_count]: [explanation]" to_chat(world, text) diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm new file mode 100644 index 00000000000..de13c11d852 --- /dev/null +++ b/code/game/gamemodes/cult/cult_comms.dm @@ -0,0 +1,39 @@ +/datum/action/innate/cultcomm + name = "Communion" + button_icon_state = "cult_comms" + background_icon_state = "bg_cult" + check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS + +/datum/action/innate/cultcomm/IsAvailable() + if(!iscultist(owner)) + return 0 + return ..() + +/datum/action/innate/cultcomm/Activate() + var/input = stripped_input(usr, "Please choose a message to tell to the other acolytes.", "Voice of Blood", "") + if(!input || !IsAvailable()) + return + + cultist_commune(usr, input) + return + +/proc/cultist_commune(mob/living/user, message) + if(!message) + return + user.whisper("O bidai nabora se[pick("'","`")]sma!") + sleep(10) + if(!user) + return + user.whisper(message) + var/my_message + if(istype(user, /mob/living/simple_animal/slaughter/cult)) //Harbringers of the Slaughter + my_message = "Harbringer of the Slaughter: [message]" + else + my_message = "[(ishuman(user) ? "Acolyte" : "Construct")] [user]: [message]" + for(var/mob/M in mob_list) + if(iscultist(M)) + to_chat(M, my_message) + else if(M in dead_mob_list) + to_chat(M, " (F) [my_message] ") + + log_say("[user.real_name]/[user.key] : [message]") \ No newline at end of file diff --git a/code/game/gamemodes/cult/cult_datums.dm b/code/game/gamemodes/cult/cult_datums.dm new file mode 100644 index 00000000000..b08632f0359 --- /dev/null +++ b/code/game/gamemodes/cult/cult_datums.dm @@ -0,0 +1,144 @@ +//cult datums by FalseIncarnate + +/datum/cult_info + var/name = "Cult of Nar'Sie" + var/theme = "blood" + var/tome_icon = "tome" + //God Entity + var/entity_name = "Nar'Sie" + var/entity_title1 = "The Dark One" + var/entity_title2 = "The One Who Sees" + var/entity_title3 = "The Geometer of Blood" + var/entity_icon_state = "narsie" + + + //Builder Construct + var/artificer_name = "Artificer" + var/artificer_icon_state = "artificer" + var/artificer_dead_state = "shade_dead" + + //Behemoth Construct + var/behemoth_name = "Behemoth" + var/behemoth_icon_state = "behemoth" + var/behemoth_dead_state = "shade_dead" + + //Wraith Construct + var/wraith_name = "Wraith" + var/wraith_icon_state = "floating" + var/wraith_dead_state = "shade_dead" + + //Armored Construct + var/juggernaut_name = "Juggernaut" + var/juggernaut_icon_state = "behemoth" + var/juggernaut_dead_state = "shade_dead" + + //Harvester Construct + var/harvester_name = "Harvester" + var/harvester_icon_state = "harvester" + var/harvester_dead_state = "shade_dead" + + //Shade Spirit + var/shade_name = "Shade" + var/shade_icon_state = "shade2" + var/shade_dead_state = "shade_dead" + + //Turfs + var/cult_floor_icon_state = "cult" + var/cult_wall_icon_state = "cult" + +/datum/cult_info/fire + name = "Cult of Pyr'Kaeus" + theme = "fire" + tome_icon = "firetome" + + entity_name = "Pyr'Kaeus" + entity_title1 = "The Burning One" + entity_title2 = "The One Who Consumes" + entity_title3 = "The Harbinger of Fire" + entity_icon_state = "narbee" + + cult_wall_icon_state = "firecult" + cult_floor_icon_state = "cultfire" + + artificer_name = "Igniting Ember" + artificer_icon_state = "fireartificer" + + behemoth_name = "Devouring Hatred" + behemoth_icon_state = "firejuggernaut" + + wraith_name = "Living Flame" + wraith_icon_state = "firewraith" + + juggernaut_name = "Pyre Armor" + juggernaut_icon_state = "firejuggernaut" + + harvester_name = "Coal Seeker"//or nipple pincher... + harvester_icon_state = "fireharvester" + + shade_name = "Charred Soul" + shade_icon_state = "shade" + +/datum/cult_info/death + name = "Cult of Mortality" + theme = "death" + + entity_name = "The Reaper" + entity_title1 = "The Silent One" + entity_title2 = "The One Who Beckons" + entity_title3 = "The Ferryman of Oblivion" + + cult_wall_icon_state = "deathcult" + cult_floor_icon_state = "carpet-broken" + + artificer_name = "Boneshaper" + + behemoth_name = "Draugr" + behemoth_icon_state = "horror" + + wraith_name = "Wraith" + wraith_icon_state = "stand" + + juggernaut_name = "Wight" + juggernaut_icon_state = "horror" + + harvester_name = "Psychopomp" + + shade_name = "Banshee" + +/datum/cult_info/proc/get_name(var/type_to_name) + if(!type_to_name) + return + switch(type_to_name) + if("god") + return entity_name + if("behemoth") + return behemoth_name + if("builder") + return artificer_name + if("juggernaut") + return juggernaut_name + if("harvester") + return harvester_name + if("wraith") + return wraith_name + if("shade") + return shade_name + +/datum/cult_info/proc/get_icon(var/type_to_icon) + if(!type_to_icon) + return + switch(type_to_icon) + if("god") + return entity_icon_state + if("behemoth") + return behemoth_icon_state + if("builder") + return artificer_icon_state + if("juggernaut") + return juggernaut_icon_state + if("harvester") + return harvester_icon_state + if("wraith") + return wraith_icon_state + if("shade") + return shade_icon_state \ No newline at end of file diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 91147183ba1..edf0912c4d6 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -1,38 +1,67 @@ /obj/item/weapon/melee/cultblade name = "Cult Blade" - desc = "An arcane weapon wielded by the followers of Nar-Sie" + desc = "An arcane weapon wielded by the followers of a cult." icon_state = "cultblade" item_state = "cultblade" w_class = 4 force = 30 throwforce = 10 + sharp = 1 hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") /obj/item/weapon/melee/cultblade/attack(mob/living/target as mob, mob/living/carbon/human/user as mob) - if(iscultist(user)) - return ..() - else - user.Paralyse(5) - to_chat(user, "\red An unexplicable force powerfully repels the sword from [target]!") - var/organ = ((user.hand ? "l_":"r_") + "arm") - var/obj/item/organ/external/affecting = user.get_organ(organ) - if(affecting.take_damage(rand(force/2, force))) //random amount of damage between half of the blade's force and the full force of the blade. - user.UpdateDamageIcon() - return + if(!iscultist(user)) + user.Weaken(5) + user.unEquip(src, 1) + user.visible_message("A powerful force shoves [user] away from [target]!", \ + "\"You shouldn't play with sharp things. You'll poke someone's eye out.\"") + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.apply_damage(rand(force/2, force), BRUTE, pick("l_arm", "r_arm")) + else + user.adjustBruteLoss(rand(force/2,force)) + return + ..() -/obj/item/weapon/melee/cultblade/pickup(mob/living/user as mob) +/obj/item/weapon/melee/cultblade/pickup(mob/living/user) ..() if(!iscultist(user)) - to_chat(user, "\red An overwhelming feeling of dread comes over you as you pick up the cultist's sword. It would be wise to be rid of this blade quickly.") + to_chat(user, "\"I wouldn't advise that.\"") + to_chat(user, "An overwhelming sense of nausea overpowers you!") user.Dizzy(120) +/obj/item/weapon/melee/cultblade/dagger + name = "sacrificial dagger" + desc = "A strange dagger said to be used by sinister groups for \"preparing\" a corpse before sacrificing it to their dark gods." + icon = 'icons/obj/wizard.dmi' + icon_state = "render" + w_class = 2 + force = 15 + throwforce = 25 + var/cooldown = 0 + +/obj/item/weapon/melee/cultblade/dagger/afterattack(mob/living/target as mob, mob/living/carbon/human/user as mob) + ..() + var/mob/living/carbon/human/bleeder = target + if(!(cooldown > world.time) && ((bleeder.stat != DEAD) && !(bleeder.species.flags & NO_BLOOD))) + user.visible_message("The runes on the blade absorb the blood of [target]!") + bleeder.drip(5000) + cooldown = world.time + 2400 + +/obj/item/weapon/restraints/legcuffs/bola/cult + name = "runed bola" + desc = "A strong bola, bound with dark magic. Throw it to trip and slow your victim." + icon = 'icons/obj/items.dmi' + icon_state = "bola_cult" + breakouttime = 45 + weaken = 1 /obj/item/clothing/head/culthood name = "cult hood" icon_state = "culthood" - desc = "A hood worn by the followers of Nar-Sie." + desc = "A hood worn by the followers of a cult." flags_inv = HIDEFACE flags = HEADCOVERSEYES armor = list(melee = 30, bullet = 10, laser = 5, energy = 5, bomb = 0, bio = 0, rad = 0) @@ -44,14 +73,10 @@ icon_state = "cult_hoodalt" item_state = "cult_hoodalt" -/obj/item/clothing/suit/hooded/cultrobes/alt - icon_state = "cultrobesalt" - item_state = "cultrobesalt" - hoodtype = /obj/item/clothing/head/culthood/alt /obj/item/clothing/suit/hooded/cultrobes name = "cult robes" - desc = "A set of armored robes worn by the followers of Nar-Sie" + desc = "A set of armored robes worn by the followers of a cult." icon_state = "cultrobes" item_state = "cultrobes" body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS @@ -60,6 +85,11 @@ armor = list(melee = 50, bullet = 30, laser = 50, energy = 20, bomb = 25, bio = 10, rad = 0) flags_inv = HIDEJUMPSUIT +/obj/item/clothing/suit/hooded/cultrobes/alt + icon_state = "cultrobesalt" + item_state = "cultrobesalt" + hoodtype = /obj/item/clothing/head/culthood/alt + /obj/item/clothing/head/magus name = "magus helm" icon_state = "magus" @@ -81,7 +111,7 @@ /obj/item/clothing/head/helmet/space/cult name = "cult helmet" - desc = "A space worthy helmet used by the followers of Nar-Sie" + desc = "A space worthy helmet used by the followers of a cult." icon_state = "cult_helmet" item_state = "cult_helmet" armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 30, bio = 30, rad = 30) @@ -93,4 +123,211 @@ desc = "A bulky suit of armour, bristling with spikes. It looks space proof." w_class = 3 allowed = list(/obj/item/weapon/tome,/obj/item/weapon/melee/cultblade,/obj/item/weapon/tank) + slowdown = 1 armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 30, bio = 30, rad = 30) + +/obj/item/clothing/suit/hooded/cultrobes/cult_shield + name = "empowered cultist robe" + desc = "Empowered garb which creates a powerful shield around the user." + icon_state = "cult_armour" + item_state = "cult_armour" + w_class = 4 + armor = list(melee = 50, bullet = 40, laser = 50, energy = 30, bomb = 50, bio = 30, rad = 30) + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + allowed = list(/obj/item/weapon/tome,/obj/item/weapon/melee/cultblade) + var/current_charges = 3 + hoodtype = /obj/item/clothing/head/cult_hoodie + +/obj/item/clothing/head/cult_hoodie + name = "empowered cultist robe" + desc = "Empowered garb which creates a powerful shield around the user." + icon_state = "cult_hoodalt" + armor = list(melee = 50, bullet = 40, laser = 50, energy = 30, bomb = 50, bio = 30, rad = 30) + body_parts_covered = HEAD + flags_inv = HIDEFACE + flags = NODROP | HEADCOVERSEYES + +/obj/item/clothing/suit/hooded/cultrobes/cult_shield/equipped(mob/living/user, slot) + ..() + if(!iscultist(user)) + to_chat(user, "\"I wouldn't advise that.\"") + to_chat(user, "An overwhelming sense of nausea overpowers you!") + user.unEquip(src, 1) + user.Dizzy(30) + user.Weaken(5) + +/obj/item/clothing/suit/hooded/cultrobes/cult_shield/hit_reaction(mob/living/carbon/human/owner, attack_text, isinhands) + if(current_charges) + owner.visible_message("\The [attack_text] is deflected in a burst of blood-red sparks!") + current_charges-- + new /obj/effect/overlay/temp/cult/sparks(get_turf(owner)) + if(!current_charges) + owner.visible_message("The runed shield around [owner] suddenly disappears!") + owner.update_inv_wear_suit() + return 1 + return 0 + +/obj/item/clothing/suit/hooded/cultrobes/berserker + name = "flagellant's robes" + desc = "Blood-soaked robes infused with dark magic; allows the user to move at inhuman speeds, but at the cost of increased damage." + icon_state = "hardsuit-beserker" + item_state = "hardsuit-beserker" + flags_inv = HIDEJUMPSUIT + allowed = list(/obj/item/weapon/tome,/obj/item/weapon/melee/cultblade) + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + armor = list(melee = -50, bullet = -50, laser = -100, energy = -50, bomb = -50, bio = -50, rad = -50) + slowdown = -1 + hoodtype = /obj/item/clothing/head/berserkerhood + + +/obj/item/clothing/head/berserkerhood + name = "flagellant's robes" + desc = "Blood-soaked garb infused with dark magic; allows the user to move at inhuman speeds, but at the cost of increased damage." + icon_state = "culthood" + flags_inv = HIDEFACE + flags = HEADCOVERSEYES + armor = list(melee = -100, bullet = -100, laser = -100, energy = -100, bomb = -100, bio = -100, rad = -100) + +/obj/item/weapon/whetstone/cult + name = "eldritch whetstone" + desc = "A block, empowered by dark magic. Sharp weapons will be enhanced when used on the stone." + icon = 'icons/obj/cult.dmi' + icon_state = "cultstone" + used = 0 + increment = 5 + max = 40 + prefix = "darkened" + +/obj/item/weapon/reagent_containers/food/drinks/bottle/unholywater + name = "flask of unholy water" + desc = "Toxic to nonbelievers; this water renews and reinvigorates the faithful of a cult." + icon_state = "holyflask" + color = "#333333" + list_reagents = list("unholywater" = 40) + +/obj/item/clothing/glasses/night/cultblind + desc = "May the master guide you through the darkness and shield you from the light." + name = "zealot's blindfold" + icon_state = "blindfold" + item_state = "blindfold" + darkness_view = 8 + flash_protect = 1 + +/obj/item/clothing/glasses/night/cultblind/equipped(mob/user, slot) + ..() + if(!iscultist(user)) + to_chat(user, "\"You want to be blind, do you?\"") + user.unEquip(src, 1) + user.Dizzy(30) + user.Weaken(5) + user.EyeBlind(30) + +/obj/item/device/shuttle_curse + name = "cursed orb" + desc = "You peer within this smokey orb and glimpse terrible fates befalling the escape shuttle." + icon = 'icons/obj/projectiles.dmi' + icon_state ="bluespace" + color = "#ff0000" + var/static/curselimit = 0 + +/obj/item/device/shuttle_curse/attack_self(mob/user) + if(!iscultist(user)) + user.unEquip(src, 1) + user.Weaken(5) + to_chat(user, "A powerful force shoves you away from [src]!") + return + if(curselimit > 1) + to_chat(user, "We have exhausted our ability to curse the shuttle.") + return + if(shuttle_master.emergency.mode == SHUTTLE_CALL) + var/cursetime = 1800 + var/timer = shuttle_master.emergency.timeLeft(1) + cursetime + shuttle_master.emergency.setTimer(timer) + to_chat(user,"You shatter the orb! A dark essence spirals into the air, then disappears.") + playsound(user.loc, "sound/effects/Glassbr1.ogg", 50, 1) + qdel(src) + sleep(20) + var/global/list/curses + if(!curses) + curses = list("A fuel technician just slit his own throat and begged for death. The shuttle will be delayed by two minutes.", + "The shuttle's navigation programming was replaced by a file containing two words, IT COMES. The shuttle will be delayed by two minutes.", + "The shuttle's custodian tore out his guts and began painting strange shapes on the floor. The shuttle will be delayed by two minutes.", + "A shuttle engineer began screaming 'DEATH IS NOT THE END' and ripped out wires until an arc flash seared off her flesh. The shuttle will be delayed by two minutes.", + "A shuttle inspector started laughing madly over the radio and then threw herself into an engine turbine. The shuttle will be delayed by two minutes.", + "The shuttle dispatcher was found dead with bloody symbols carved into their flesh. The shuttle will be delayed by two minutes.", + "Steve repeatedly touched a lightbulb until his hands fell off. The shuttle will be delayed by two minutes.") + var/message = pick(curses) + command_announcement.Announce("[message]", "System Failure", 'sound/misc/notice1.ogg') + curselimit++ + +/obj/item/device/cult_shift + name = "veil shifter" + desc = "This relic teleports you forward a medium distance." + icon = 'icons/obj/cult.dmi' + icon_state ="shifter" + var/uses = 4 + +/obj/item/device/cult_shift/examine(mob/user) + . = ..() + if(uses) + to_chat(user, "It has [uses] uses remaining.") + else + to_chat(user, "It seems drained.") + +/obj/item/device/cult_shift/proc/handle_teleport_grab(turf/T, mob/user) + var/mob/living/carbon/C = user + if(C.pulling) + var/atom/movable/pulled = C.pulling + pulled.forceMove(T) + . = pulled + +/obj/item/device/cult_shift/attack_self(mob/user) + if(!uses || !iscarbon(user)) + to_chat(user, "\The [src] is dull and unmoving in your hands.") + return + if(!iscultist(user)) + user.unEquip(src, 1) + step(src, pick(alldirs)) + to_chat(user, "\The [src] flickers out of your hands, too eager to move!") + return + + var/outer_tele_radius = 9 + + var/mob/living/carbon/C = user + var/turf/mobloc = get_turf(C) + var/list/turfs = new/list() + for(var/turf/T in range(user, outer_tele_radius)) + if(!is_teleport_allowed(T)) + continue + if(get_dir(C, T) != C.dir) + continue + if(T == mobloc) + continue + if(istype(T, /turf/space)) + continue + if(T.x > world.maxx-outer_tele_radius || T.x < outer_tele_radius) + continue //putting them at the edge is dumb + if(T.y > world.maxy-outer_tele_radius || T.y < outer_tele_radius) + continue + + turfs += T + + if(turfs) + uses-- + var/turf/destination = pick(turfs) + if(uses <= 0) + icon_state ="shifter_drained" + playsound(mobloc, "sparks", 50, 1) + new /obj/effect/overlay/temp/cult/phase/out(mobloc) + + var/atom/movable/pulled = handle_teleport_grab(destination, C) + C.forceMove(destination) + if(pulled) + C.start_pulling(pulled) //forcemove resets pulls, so we need to re-pull + + new /obj/effect/overlay/temp/cult/phase(destination) + playsound(destination, 'sound/effects/phasein.ogg', 25, 1) + playsound(destination, "sparks", 50, 1) + + else + to_chat(C, "The veil cannot be torn here!") \ No newline at end of file diff --git a/code/game/gamemodes/cult/cult_objectives.dm b/code/game/gamemodes/cult/cult_objectives.dm new file mode 100644 index 00000000000..a84a83be688 --- /dev/null +++ b/code/game/gamemodes/cult/cult_objectives.dm @@ -0,0 +1,257 @@ +/datum/game_mode/cult/proc/blood_check() + max_spilled_blood = (max(bloody_floors.len,max_spilled_blood)) + if((objectives[current_objective] == "bloodspill") && (bloody_floors.len >= spilltarget) && !spilled_blood) + spilled_blood = 1 + additional_phase() + +/datum/game_mode/cult/proc/check_numbers() + if((objectives[current_objective] == "convert") && (cult.len >= convert_target) && !mass_convert) + mass_convert = 1 + additional_phase() + +/datum/game_mode/cult/proc/first_phase() + + var/new_objective = pick_objective() + + objectives += new_objective + + var/explanation + + switch(new_objective) + if("convert") + explanation = "We must increase our influence before we can summon [ticker.mode.cultdat.entity_name], Convert [convert_target] crew members. Take it slowly to avoid raising suspicions." + if("bloodspill") + spilltarget = 100 + rand(0,player_list.len * 3) + explanation = "We must prepare this place for [ticker.mode.cultdat.entity_title1]'s coming. Spill blood and gibs over [spilltarget] floor tiles." + if("sacrifice") + explanation = "We need to sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role], for his blood is the key that will lead our master to this realm. You will need 3 cultists around a Sacrifice rune to perform the ritual." + + for(var/datum/mind/cult_mind in cult) + to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]") + cult_mind.memory += "Objective #[current_objective]: [explanation]
" + +/datum/game_mode/cult/proc/bypass_phase() + + switch(objectives[current_objective]) + if("convert") + mass_convert = 1 + if("bloodspill") + spilled_blood = 1 + if("sacrifice") + sacrificed += sacrifice_target + additional_phase() + +/datum/game_mode/cult/proc/additional_phase() + current_objective++ + + message_admins("Picking a new Cult objective.") + var/new_objective = "eldergod" + //the idea here is that if the cult performs well, the should get more objectives before they can summon Nar-Sie. + if(cult.len >= 4)//if there are less than 4 remaining cultists, they get a free pass to the summon objective. + if(current_objective <= prenarsie_objectives) + var/list/unconvertables = get_unconvertables() + if(unconvertables.len <= (cult.len * 2))//if cultists are getting radically outnumbered, they get a free pass to the summon objective. + new_objective = pick_objective() + else + message_admins("There are over twice more unconvertables than there are cultists ([cult.len] cultists for [unconvertables.len]) unconvertables! Nar-Sie objective unlocked.") + log_admin("There are over twice more unconvertables than there are cultists ([cult.len] cultists for [unconvertables.len]) unconvertables! Nar-Sie objective unlocked.") + else + message_admins("The Cult has already completed [prenarsie_objectives] objectives! Nar-Sie objective unlocked.") + log_admin("The Cult has already completed [prenarsie_objectives] objectives! Nar-Sie objective unlocked.") + else + message_admins("There are less than 4 cultists! [ticker.mode.cultdat.entity_name] objective unlocked.") + log_admin("There are less than 4 cultists! [ticker.mode.cultdat.entity_name] objective unlocked.") + gtfo_phase() + + if(!sacrificed.len && (new_objective != "sacrifice")) + sacrifice_target = null + + if(new_objective == "eldergod") + second_phase() + return + else + objectives += new_objective + + var/explanation + + switch(new_objective) + if("convert") + explanation = "We must increase our influence before we can summon [ticker.mode.cultdat.entity_name]. Convert [convert_target] crew members. Take it slowly to avoid raising suspicions." + if("bloodspill") + spilltarget = 100 + rand(0,player_list.len * 3) + explanation = "We must prepare this place for [ticker.mode.cultdat.entity_title1]'s coming. Spread blood and gibs over [spilltarget] of the Station's floor tiles." + if("sacrifice") + explanation = "We need to sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role], for his blood is the key that will lead our master to this realm. You will need 3 cultists around a Sacrifice rune to perform the ritual." + + for(var/datum/mind/cult_mind in cult) + to_chat(cult_mind.current, "You and your acolytes have completed your task, but this place requires yet more preparation!") + to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]") + cult_mind.memory += "Objective #[current_objective]: [explanation]
" + + message_admins("New Cult Objective: [new_objective]") + log_admin("New Cult Objective: [new_objective]") + + blood_check()//in case there are already enough blood covered tiles when the objective is given. + +/datum/game_mode/cult/proc/gtfo_phase()//YOU HAD ONE JOB + var/explanation + objectives +="survive" + explanation = "Our knowledge must live on. Make sure at least [acolytes_needed] acolytes escape on the shuttle to spread their work on an another station." + for(var/datum/mind/cult_mind in cult) + to_chat(cult_mind.current, "You and your acolytes suddenly feel the urge to do your best, but survive!") + to_chat(cult_mind.current, "Objective Survive: [explanation]") + cult_mind.memory += "Objective Survive: [explanation]
" + + +/datum/game_mode/cult/proc/second_phase() + narsie_condition_cleared = 1 + var/explanation + + if(prob(40))//split the chance of this + objectives += "eldergod" + explanation = "Summon [ticker.mode.cultdat.entity_name] on the Station via the use of the Tear Reality rune." + else + objectives += "slaughter" + explanation = "Bring the Slaughter via the rune 'Bring forth the slaughter'." + + for(var/datum/mind/cult_mind in cult) + to_chat(cult_mind.current, "You and your acolytes have succeeded in preparing the station for the ultimate ritual!") + to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]") + cult_mind.memory += "Objective #[current_objective]: [explanation]
" + +/datum/game_mode/cult/proc/third_phase() + current_objective++ + + sleep(10) + + var/last_objective = pick_bonus_objective() + + objectives += last_objective + + var/explanation + + switch(last_objective) + if("harvest") + explanation = "[ticker.mode.cultdat.entity_title1] hungers for his first meal of this never-ending day. Offer him [harvest_target] humans in sacrifice." + if("hijack") + explanation = "[ticker.mode.cultdat.entity_name] wishes for his troops to start the assault on Centcom immediately. Hijack the escape shuttle and don't let a single non-cultist board it." + if("massacre") + explanation = "[ticker.mode.cultdat.entity_name] wants to watch you as you massacre the remaining humans on the station (until less than [massacre_target] humans are left alive)." + + for(var/datum/mind/cult_mind in cult) + to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]") + cult_mind.memory += "Objective #[current_objective]: [explanation]
" + + message_admins("Last Cult Objective: [last_objective]") + log_admin("Last Cult Objective: [last_objective]") + + +/datum/game_mode/cult/proc/pick_objective() + var/list/possible_objectives = list() + + if(!spilled_blood && (bloody_floors.len < spilltarget)) + possible_objectives |= "bloodspill" + + if(!sacrificed.len) + var/list/possible_targets = list() + for(var/mob/living/carbon/human/player in player_list) + if(is_secure_level(player.z)) //We can't sacrifice people that are on the centcom z-level + continue + if(player.mind && !is_convertable_to_cult(player.mind) && (player.stat != DEAD)) + possible_targets += player.mind + + if(!possible_targets.len) + //There are no living Unconvertables on the station. Looking for a Sacrifice Target among the ordinary crewmembers + for(var/mob/living/carbon/human/player in player_list) + if(is_secure_level(player.z)) //We can't sacrifice people that are on the centcom z-level + continue + if(player.mind && !(player.mind in cult) && (player.stat != DEAD))//make DAMN sure they are not dead + possible_targets += player.mind + + if(possible_targets.len > 0) + sacrifice_target = pick(possible_targets) + possible_objectives |= "sacrifice" + else + message_admins("Didn't find a suitable sacrifice target...what the hell? Shout at a coder.") + log_admin("Didn't find a suitable sacrifice target...what the hell? Shout at a coder.") + + if(!mass_convert) + var/living_crew = 0 + var/living_cultists = 0 + for(var/mob/living/L in player_list) + if(L.stat != DEAD) + if(L.mind in cult) + living_cultists++ + else + if(istype(L, /mob/living/carbon/human)) + living_crew++ + + var/total = living_crew + living_cultists + + if((living_cultists * 2) < total) + if(total < 15) + message_admins("There are [total] players, too little for the mass convert objective!") + log_admin("There are [total] players, too little for the mass convert objective!") + else if(total > 50) + message_admins("There are [total] players, too many for the mass convert objective!") + log_admin("There are [total] players, too many for the mass convert objective!") + else + possible_objectives |= "convert" + convert_target = round(total / 2) + + if(!possible_objectives.len)//No more possible objectives, time to summon Nar-Sie + message_admins("No suitable objectives left! Nar-Sie objective unlocked.") + log_admin("No suitable objectives left! Nar-Sie objective unlocked.") + var/lastbit + if(prob(50)) + lastbit = "eldergod" + else + lastbit = "slaughter" + return lastbit + else + return pick(possible_objectives) + +/datum/game_mode/cult/proc/pick_bonus_objective()//did we summon demons? TIME FOR THE BONUS STAGE + var/list/possible_objectives = list() + + var/living_crew = 0 + for(var/mob/living/carbon/C in player_list) + if(C.stat != DEAD) + if(!(C.mind in cult)) + var/turf/T = get_turf(C) + if(is_station_level(T.z)) //we're only interested in the remaining humans on the station + living_crew++ + + if(living_crew > 5) + possible_objectives |= "massacre" + + if(living_crew > 10) + possible_objectives |= "harvest" + + possible_objectives |= "hijack" //we need at least one objective guarranted to fire + + return pick(possible_objectives) + +/datum/game_mode/cult/proc/bonus_check() + switch(objectives[current_objective]) + if("harvest") + if(harvested >= harvest_target) + bonus = 1 + + if("hijack") + for(var/mob/living/L in player_list) + if(L.stat != DEAD && !(L.mind in cult)) + var/area/A = get_area(L) + if(is_type_in_list(A.loc, centcom_areas)) + escaped_shuttle++ + if(!escaped_shuttle) + bonus = 1 + + if("massacre") + for(var/mob/living/carbon/C in player_list) + if(C.stat != DEAD && !(C.mind in cult)) + var/turf/T = get_turf(C) + if(is_station_level(T.z)) //we're only interested in the remaining humans on the station + survivors++ + if(survivors < massacre_target) + bonus = 1 \ No newline at end of file diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm index 126601c31dd..72b5bfa292b 100644 --- a/code/game/gamemodes/cult/cult_structures.dm +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -1,14 +1,15 @@ +//Noncult /obj/structure/cult density = 1 anchored = 1 icon = 'icons/obj/cult.dmi' +//Noncult As we may have this on maps /obj/structure/cult/talisman name = "Altar" desc = "A bloodstained altar dedicated to Nar-Sie" icon_state = "talismanaltar" - /obj/structure/cult/forge name = "Daemon forge" desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie" @@ -21,22 +22,219 @@ light_range = 5 light_color = "#3e0000" - /obj/structure/cult/tome name = "Desk" desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl" icon_state = "tomealtar" -// luminosity = 5 -//sprites for this no longer exist -Pete -//(they were stolen from another game anyway) -/* -/obj/structure/cult/pillar - name = "Pillar" - desc = "This should not exist" - icon_state = "pillar" - icon = 'magic_pillar.dmi' -*/ +//Cult versions cuase fuck map conflicts +/obj/structure/cult/functional + var/cooldowntime = 0 + var/health = 100 + var/death_message = "The structure falls apart." //The message shown when the structure is destroyed + var/death_sound = 'sound/items/bikehorn.ogg' + var/heathen_message = "You're a huge nerd, go away. Also, a coder forgot to put a message here." + var/selection_title = "Oops" + var/selection_prompt = "Choose your weapon, nerdwad" + var/creation_delay = 2400 + var/list/choosable_items = list( + "A coder forgot to set this" = /obj/item/weapon/bananapeel + ) + var/creation_message = "A dank smoke comes out, and you pass out. When you come to, you notice a %ITEM%!" + +/obj/structure/cult/functional/proc/destroy_structure() + visible_message(death_message) + playsound(src, death_sound, 50, 1) + qdel(src) + +/obj/structure/cult/functional/examine(mob/user) + . = ..() + if(iscultist(user) && cooldowntime > world.time) + to_chat(user, "The magic in [src] is weak, it will be ready to use again in [getETA()].") + to_chat(user, "\The [src] is [anchored ? "":"not "]secured to the floor.") + +/obj/structure/cult/functional/attackby(obj/I, mob/user, params) + if(istype(I, /obj/item/weapon/tome) && iscultist(user)) + anchored = !anchored + to_chat(user, "You [anchored ? "":"un"]secure \the [src] [anchored ? "to":"from"] the floor.") + playsound(loc, 'sound/hallucinations/wail.ogg', 75, 1) + if(!anchored) + icon_state = "[initial(icon_state)]_off" + else + icon_state = initial(icon_state) + else + return ..() + +/obj/structure/cult/functional/attack_hand(mob/living/user) + if(!iscultist(user)) + to_chat(user, "[heathen_message]") + return + if(!anchored) + to_chat(user, "You need to anchor [src] to the floor with a tome first.") + return + if(cooldowntime > world.time) + to_chat(user, "The magic in [src] is weak, it will be ready to use again in [getETA()].") + return + var/choice = input(user, selection_prompt, selection_title) as null|anything in choosable_items + var/pickedtype = choosable_items[choice] + if(pickedtype && Adjacent(user) && src && !qdeleted(src) && !user.incapacitated() && cooldowntime <= world.time) + cooldowntime = world.time + creation_delay + var/obj/item/N = new pickedtype(get_turf(src)) + to_chat(user, replacetext("[creation_message]", "%ITEM%", "[N]")) + +/obj/structure/cult/functional/proc/getETA() + var/time = (cooldowntime - world.time)/600 + var/eta = "[round(time, 1)] minutes" + if(time <= 1) + time = (cooldowntime - world.time)*0.1 + eta = "[round(time, 1)] seconds" + return eta + +/obj/structure/cult/functional/talisman + name = "altar" + desc = "A bloodstained altar dedicated to a cult." + icon_state = "talismanaltar" + health = 150 //Sturdy + death_message = "The altar breaks into splinters, releasing a cascade of spirits into the air!" + death_sound = 'sound/effects/altar_break.ogg' + heathen_message = "There is a foreboding aura to the altar and you want nothing to do with it." + selection_prompt = "You study the rituals on the altar..." + selection_title = "Altar" + creation_message = "You kneel before the altar and your faith is rewarded with an %ITEM%!" + choosable_items = list("Eldritch Whetstone"= /obj/item/weapon/whetstone/cult, "Zealot's Blindfold" = /obj/item/clothing/glasses/night/cultblind, \ + "Flask of Unholy Water" = /obj/item/weapon/reagent_containers/food/drinks/bottle/unholywater, "Cultist Dagger" = /obj/item/weapon/melee/cultblade/dagger) + +/obj/structure/cult/functional/forge + name = "daemon forge" + desc = "A forge used in crafting the unholy weapons used by the armies of a cult." + icon_state = "forge" + health = 300 //Made of metal + death_message = "The forge falls apart, its lava cooling and winking away!" + death_sound = 'sound/effects/forge_destroy.ogg' + heathen_message = "Your hand feels like it's melting off as you try to touch the forge." + selection_prompt = "You study the schematics etched on the forge..." + selection_title = "Forge" + creation_message = "You work the forge as dark knowledge guides your hands, creating %ITEM%!" + choosable_items = list("Shielded Robe" = /obj/item/clothing/suit/hooded/cultrobes/cult_shield, "Flagellant's Robe" = /obj/item/clothing/suit/hooded/cultrobes/berserker, \ + "Cultist Hardsuit" = /obj/item/weapon/storage/box/cult) + + +/obj/structure/cult/functional/forge/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/G = I + if(!iscarbon(G.affecting)) + to_chat(user, "You may only dunk carbon-based creatures!") + return 0 + if(G.affecting == LAVA_PROOF) + to_chat(user, "Is immune to the lava!") + return 0 + if(G.affecting.stat == DEAD) + to_chat(user, "[G.affecting] is dead!") + return 0 + var/mob/living/carbon/human/C = G.affecting + C.visible_message("[user] dunks [C]'s face into [src]'s lava!", \ + "[user] dunks your face into [src]'s lava!") + if(!C.stat) + C.emote("scream") + user.changeNext_move(CLICK_CD_MELEE) + var/obj/item/organ/external/head/head = C.get_organ("head") + if(head) + C.apply_damage(30, BURN, "head") //30 fire damage because it's FUCKING LAVA + head.disfigure("burn") //Your face is unrecognizable because it's FUCKING LAVA + return 1 + +var/list/blacklisted_pylon_turfs = typecacheof(list( + /turf/simulated/floor/engine/cult, + /turf/space, + /turf/unsimulated/floor/lava, + /turf/unsimulated/floor/chasm, + /turf/simulated/wall, + )) + +/obj/structure/cult/functional/pylon + name = "pylon" + desc = "A floating crystal that slowly heals those faithful to a cult." + icon_state = "pylon" + light_range = 5 + light_color = "#3e0000" + health = 50 //Very fragile + death_message = "The pylon's crystal vibrates and glows fiercely before violently shattering!" + death_sound = 'sound/effects/pylon_shatter.ogg' + + var/heal_delay = 25 + var/last_heal = 0 + var/corrupt_delay = 50 + var/last_corrupt = 0 + +/obj/structure/cult/functional/pylon/attack_hand(mob/living/user)//override as it should not create anything + return + +/obj/structure/cult/functional/pylon/New() + processing_objects |= src + ..() + +/obj/structure/cult/functional/pylon/Destroy() + processing_objects.Remove(src) + return ..() + +/obj/structure/cult/functional/pylon/process() + if(!anchored) + return + if(last_heal <= world.time) + last_heal = world.time + heal_delay + for(var/mob/living/L in range(5, src)) + if(iscultist(L) || istype(L, /mob/living/simple_animal/shade) || istype(L, /mob/living/simple_animal/hostile/construct)) + if(L.health != L.maxHealth) + new /obj/effect/overlay/temp/heal(get_turf(src), "#960000") + if(ishuman(L)) + L.adjustBruteLoss(-1) + L.adjustFireLoss(-1) + L.updatehealth() + if(istype(L, /mob/living/simple_animal/shade) || istype(L, /mob/living/simple_animal/hostile/construct)) + var/mob/living/simple_animal/M = L + if(M.health < M.maxHealth) + M.adjustHealth(-1) + if(last_corrupt <= world.time) + var/list/validturfs = list() + var/list/cultturfs = list() + for(var/T in circleviewturfs(src, 5)) + if(istype(T, /turf/simulated/floor/engine/cult)) + cultturfs |= T + continue + if(is_type_in_typecache(T, blacklisted_pylon_turfs)) + continue + else + validturfs |= T + + last_corrupt = world.time + corrupt_delay + + var/turf/T = safepick(validturfs) + if(T) + T.ChangeTurf(/turf/simulated/floor/engine/cult) + else + var/turf/simulated/floor/engine/cult/F = safepick(cultturfs) + if(F) + new /obj/effect/overlay/temp/cult/turf/open/floor(F) + else + // Are we in space or something? No cult turfs or + // convertable turfs? + last_corrupt = world.time + corrupt_delay*2 + + + +/obj/structure/cult/functional/tome + name = "archives" + desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl." + icon_state = "tomealtar" + health = 125 //Slightly sturdy + death_message = "The desk breaks apart, its books falling to the floor." + death_sound = 'sound/effects/wood_break.ogg' + heathen_message = "What do you hope to seek?" + selection_prompt = "You flip through the black pages of the archives..." + selection_title = "Archives" + creation_message = "You invoke the dark magic of the tomes creating %ITEM%!" + choosable_items = list("Supply Talisman" = /obj/item/weapon/paper/talisman/supply/weak, "Shuttle Curse" = /obj/item/device/shuttle_curse, \ + "Veil Shifter" = /obj/item/device/cult_shift) /obj/effect/gateway name = "gateway" @@ -55,4 +253,18 @@ /obj/effect/gateway/Crossed(AM as mob|obj) spawn(0) return - return \ No newline at end of file + return + + +//Armor kit + +/obj/item/weapon/storage/box/cult + name = "Dark Forge Cache" + can_hold = list("/obj/item/clothing/suit/space/cult", "/obj/item/clothing/head/helmet/space/cult") + max_w_class = 3 + +/obj/item/weapon/storage/box/cult/New() + ..() + new /obj/item/clothing/suit/space/cult(src) + new /obj/item/clothing/head/helmet/space/cult(src) + return diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index 52f29f08f13..da0cdc79e94 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -1,700 +1,301 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -var/cultwords = list() -var/rune_to_english = list() -var/runedec = 0 -var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology", "self", "see", "other", "hide") - -/client/proc/check_words() // -- Urist - set category = "Admin" - set name = "Check Rune Words" - set desc = "Check the rune-word meaning" - - if(!check_rights(R_ADMIN)) - return - - if(!cultwords["travel"]) - runerandom() - for(var/word in engwords) - to_chat(usr, "[cultwords[word]] is [word]") - - log_and_message_admins("checked the rune words.") - feedback_add_details("admin_verb","CRW") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/proc/runerandom() //randomizes word meaning - var/list/runewords=list("ire","ego","nahlizet","certum","veri","jatkaa","mgar","balaq", "karazet", "geeri") ///"orkan" and "allaq" removed. - for(var/word in engwords) - var/runeword = pick(runewords) - cultwords[word] = runeword - rune_to_english[runeword] = word - runewords-=cultwords[word] - - -/obj/effect/rune - desc = "" - anchored = 1 - icon = 'icons/obj/rune.dmi' - icon_state = "1" - var/visibility = 0 - var/view_range = 7 - unacidable = 1 - layer = TURF_LAYER - - var/word1 - var/word2 - var/word3 -// Places these combos are mentioned: this file - twice in the rune code, once in imbued tome, once in tome's HTML runes.dm - in the imbue rune code. If you change a combination - dont forget to change it everywhere. - -// travel self [word] - Teleport to random [rune with word destination matching] -// travel other [word] - Portal to rune with word destination matching - kinda doesnt work. At least the icon. No idea why. -// see blood Hell - Create a new tome -// join blood self - Incorporate person over the rune into the group -// Hell join self - Summon TERROR -// destroy see technology - EMP rune -// travel blood self - Drain blood -// see Hell join - See invisible -// blood join Hell - Raise dead - -// hide see blood - Hide nearby runes -// blood see hide - Reveal nearby runes - The point of this rune is that its reversed obscure rune. So you always know the words to reveal the rune once oyu have obscured it. - -// Hell travel self - Leave your body and ghost around -// blood see travel - Manifest a ghost into a mortal body -// Hell tech join - Imbue a rune into a talisman -// Hell blood join - Sacrifice rune -// destroy travel self - Wall rune -// join other self - Summon cultist rune -// travel technology other - Freeing rune // other blood travel was freedom join other - -// hide other see - Deafening rune // was destroy see hear -// destroy see other - Blinding rune -// destroy see blood - BLOOD BOIL - -// self other technology - Communication rune //was other hear blood -// join hide technology - stun rune. Rune color: bright pink. - -/obj/effect/rune/New() - ..() - var/image/blood = image(loc = src) - blood.override = 1 - for(var/mob/living/silicon/ai/AI in player_list) - AI.client.images += blood - cult_viewpoints += src - poi_list |= src - -/obj/effect/rune/Destroy() - cult_viewpoints -= src - poi_list.Remove(src) - return ..() - -/obj/effect/rune/examine(mob/user) - ..(user) - if(!iscultist(user) && !isSpirit(user)) - to_chat(user, "A strange collection of symbols drawn in blood.") - return - if(!desc) - to_chat(user, "A spell circle drawn in blood. It reads: [word1] [word2] [word3].") - else - to_chat(user, "Explosive Runes inscription in blood. It reads: [desc].") - - -/obj/effect/rune/attackby(I as obj, user as mob, params) - if(istype(I, /obj/item/weapon/tome) && iscultist(user)) - to_chat(user, "You retrace your steps, carefully undoing the lines of the rune.") - qdel(src) - return - else if(istype(I, /obj/item/weapon/nullrod)) - to_chat(user, "\blue You disrupt the vile magic with the deadening field of \the [I]!") - qdel(src) - return - return - -// This is for the seer rune, so you don't get permanent ghost sight -/obj/effect/rune/Uncrossed(atom/movable/O) - if(isliving(O)) - var/mob/living/L = O - L.update_sight() - -/obj/effect/rune/proc/get_word_string() - if(word1 == cultwords["travel"]) - if(word2 == cultwords["self"]) - return "teleport" - if(word2 == cultwords["other"]) - return "itemport" - return "[rune_to_english[word1]]_[rune_to_english[word2]]_[rune_to_english[word3]]" - - -/obj/effect/rune - var/list/effect_dictionary = list( "teleport"=/obj/effect/rune/proc/teleportRune, - "itemport"=/obj/effect/rune/proc/itemportRune, - "see_blood_hell"=/obj/effect/rune/proc/tomesummon, - "hell_destroy_other"=/obj/effect/rune/proc/armor, - "join_blood_self"=/obj/effect/rune/proc/convert, - "hell_join_self"=/obj/effect/rune/proc/tearreality, - "destroy_see_technology"=/obj/effect/rune/proc/empRune, - "travel_blood_self"=/obj/effect/rune/proc/drain, - "see_hell_join"=/obj/effect/rune/proc/seer, - "blood_join_hell"=/obj/effect/rune/proc/raise, - "hide_see_blood"=/obj/effect/rune/proc/obscureRune, - "hell_travel_self"=/obj/effect/rune/proc/ajourney, - "blood_see_travel"=/obj/effect/rune/proc/manifest, - "hell_technology_join"=/obj/effect/rune/proc/talisman, - "hell_blood_join"=/obj/effect/rune/proc/sacrifice, - "blood_see_hide"=/obj/effect/rune/proc/revealrunesrune, - "destroy_travel_self"=/obj/effect/rune/proc/wall, - "travel_technology_other"=/obj/effect/rune/proc/freedom, - "join_other_self"=/obj/effect/rune/proc/cultsummon, - "hide_other_see"=/obj/effect/rune/proc/deafen, - "destroy_see_other"=/obj/effect/rune/proc/blind, - "destroy_see_blood"=/obj/effect/rune/proc/bloodboil, - "self_other_technology"=/obj/effect/rune/proc/communicate, - "join_hide_technology"=/obj/effect/rune/proc/runestun ) - -/obj/effect/rune/attack_hand(mob/living/user as mob) - if(!iscultist(user)) - to_chat(user, "You can't mouth the arcane scratchings without fumbling over them.") - return - if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle)) - to_chat(user, "You are unable to speak the words of the rune.") - return - if(user.silent) // checking if we've been muted somehow - to_chat(user, "You are unable to speak at all! You cannot say the words of the rune.") - if(!word1 || !word2 || !word3 || prob(user.getBrainLoss())) - return fizzle() - - var/word_string = get_word_string() - if(word_string in effect_dictionary) - cult_log("Rune of type [effect_dictionary[word_string]] activated by [key_name(user)].") - return call(src,effect_dictionary[word_string])() - return fizzle() - +#define CULT_ELDERGOD "eldergod" +#define CULT_SLAUGHTER "slaughter" /obj/effect/rune/proc/fizzle() if(istype(src,/obj/effect/rune)) usr.say(pick("Hakkrutju gopoenjim.", "Nherasai pivroiashan.", "Firjji prhiv mazenhor.", "Tanah eh wakantahe.", "Obliyae na oraie.", "Miyf hon vnor'c.", "Wakabai hij fen juswix.")) else usr.whisper(pick("Hakkrutju gopoenjim.", "Nherasai pivroiashan.", "Firjji prhiv mazenhor.", "Tanah eh wakantahe.", "Obliyae na oraie.", "Miyf hon vnor'c.", "Wakabai hij fen juswix.")) - for(var/mob/V in viewers(src)) + for (var/mob/V in viewers(src)) V.show_message("\red The markings pulse with a small burst of light, then fall dark.", 3, "\red You hear a faint fizzle.", 2) return /obj/effect/rune/proc/check_icon() - icon = get_uristrune_cult(word1, word2, word3) + icon = get_rune_cult(invocation) /obj/item/weapon/tome name = "arcane tome" + desc = "An old, dusty tome with frayed edges and a sinister-looking cover." icon_state ="tome" - throw_speed = 1 + throw_speed = 2 throw_range = 5 w_class = 2 - var/notedat = "" - var/tomedat = "" - var/list/words = list("ire" = "ire", "ego" = "ego", "nahlizet" = "nahlizet", "certum" = "certum", "veri" = "veri", "jatkaa" = "jatkaa", "balaq" = "balaq", "mgar" = "mgar", "karazet" = "karazet", "geeri" = "geeri") + var/scribereduct = 0 + var/canbypass = 0 //ADMINBUS - tomedat = {" - - - - -

The scriptures of Nar-Sie, The One Who Sees, The Geometer of Blood.

+/obj/item/weapon/tome/accursed + name = "accursed tome" + desc = "An arcane tome still empowered with a shadow of its former consecration." + scribereduct = 30 //faster because it's made by corrupting a bible - The book is written in an unknown dialect, there are lots of pictures of various complex geometric shapes. You find some notes in english that give you basic understanding of the many runes written in the book. The notes give you an understanding what the words for the runes should be. However, you do not know how to write all these words in this dialect.
- Below is the summary of the runes.
+/obj/item/weapon/tome/imbued //Admin-only tome, allows instant drawing of runes + name = "imbued arcane tome" + desc = "An arcane tome granted by the Geometer itself." + scribereduct = 50 + canbypass = 1 -

Contents

-

- Teleport self: Travel Self (word)
- Teleport other: Travel Other (word)
- Summon new tome: See Blood Hell
- Convert a person: Join Blood Self
- Summon Nar-Sie: Hell Join Self
- Disable technology: Destroy See Technology
- Drain blood: Travel Blood Self
- Raise dead: Blood Join Hell
- Hide runes: Hide See Blood
- Reveal hidden runes: Blood See Hide
- Leave your body: Hell travel self
- Ghost Manifest: Blood See Travel
- Imbue a talisman: Hell Technology Join
- Sacrifice: Hell Blood Join
- Create a wall: Destroy Travel Self
- Summon cultist: Join Other Self
- Free a cultist: Travel technology other
- Deafen: Hide Other See
- Blind: Destroy See Other
- Blood Boil: Destroy See Blood
- Communicate: Self Other Technology
- Stun: Join Hide Technology
- Summon Cultist Armor: Hell Destroy Other
- See Invisible: See Hell Join
-

-

Rune Descriptions

-

Teleport self

- Teleport rune is a special rune, as it only needs two words, with the third word being destination. Basically, when you have two runes with the same destination, invoking one will teleport you to the other one. If there are more than 2 runes, you will be teleported to a random one. Runes with different third words will create separate networks. You can imbue this rune into a talisman, giving you a great escape mechanism.
-

Teleport other

- Teleport other allows for teleportation for any movable object to another rune with the same third word. You need 3 cultists chanting the invocation for this rune to work.
-

Summon new tome

- Invoking this rune summons a new arcane tome. -

Convert a person

- This rune opens target's mind to the realm of Nar-Sie, which usually results in this person joining the cult. However, some people (mostly the ones who posess high authority) have strong enough will to stay true to their old ideals.
-

Summon Nar-Sie

- The ultimate rune. It summons the Avatar of Nar-Sie himself, tearing a huge hole in reality and consuming everything around it. Summoning it is the final goal of any cult.
-

Disable Technology

- Invoking this rune creates a strong electromagnetic pulse in a small radius, making it basically analogic to an EMP grenade. You can imbue this rune into a talisman, making it a decent defensive item.
-

Drain Blood

- This rune instantly heals you of some brute damage at the expense of a person placed on top of the rune. Whenever you invoke a drain rune, ALL drain runes on the station are activated, draining blood from anyone located on top of those runes. This includes yourself, though the blood you drain from yourself just comes back to you. This might help you identify this rune when studying words. One drain gives up to 25HP per each victim, but you can repeat it if you need more. Draining only works on living people, so you might need to recharge your "Battery" once its empty. Drinking too much blood at once might cause blood hunger.
-

Raise Dead

- This rune allows for the resurrection of any dead person. You will need a dead human body and a living human sacrifice. Make 2 raise dead runes. Put a living, awake human on top of one, and a dead body on the other one. When you invoke the rune, the life force of the living human will be transferred into the dead body, allowing a ghost standing on top of the dead body to enter it, instantly and fully healing it. Use other runes to ensure there is a ghost ready to be resurrected.
-

Hide runes

- This rune makes all nearby runes completely invisible. They are still there and will work if activated somehow, but you cannot invoke them directly if you do not see them.
-

Reveal runes

- This rune is made to reverse the process of hiding a rune. It reveals all hidden runes in a rather large area around it. -

Leave your body

- This rune gently rips your soul out of your body, leaving it intact. You can observe the surroundings as a ghost as well as communicate with other ghosts. Your body takes damage while you are there, so ensure your journey is not too long, or you might never come back.
-

Manifest a ghost

- Unlike the Raise Dead rune, this rune does not require any special preparations or vessels. Instead of using full lifeforce of a sacrifice, it will drain YOUR lifeforce. Stand on the rune and invoke it. If theres a ghost standing over the rune, it will materialise, and will live as long as you dont move off the rune or die. You can put a paper with a name on the rune to make the new body look like that person.
-

Imbue a talisman

- This rune allows you to imbue the magic of some runes into paper talismans. Create an imbue rune, then an appropriate rune beside it. Put an empty piece of paper on the imbue rune and invoke it. You will now have a one-use talisman with the power of the target rune. Using a talisman drains some health, so be careful with it. You can imbue a talisman with power of the following runes: summon tome, reveal, conceal, teleport, tisable technology, communicate, deafen, blind and stun.
-

Sacrifice

- Sacrifice rune allows you to sacrifice a living thing or a body to the Geometer of Blood. Monkeys and dead humans are the most basic sacrifices, they might or might not be enough to gain His favor. A living human is what a real sacrifice should be, however, you will need 3 people chanting the invocation to sacrifice a living person. -

Create a wall

- Invoking this rune solidifies the air above it, creating an an invisible wall. To remove the wall, simply invoke the rune again. -

Summon cultist

- This rune allows you to summon a fellow cultist to your location. The target cultist must be unhandcuffed ant not buckled to anything. You also need to have 3 people chanting at the rune to succesfully invoke it. Invoking it takes heavy strain on the bodies of all chanting cultists.
-

Free a cultist

- This rune unhandcuffs and unbuckles any cultist of your choice, no matter where he is. You need to have 3 people invoking the rune for it to work. Invoking it takes heavy strain on the bodies of all chanting cultists.
-

Deafen

- This rune temporarily deafens all non-cultists around you.
-

Blind

- This rune temporarily blinds all non-cultists around you. Very robust. Use together with the deafen rune to leave your enemies completely helpless.
-

Blood boil

- This rune boils the blood all non-cultists in visible range. The damage is enough to instantly critically hurt any person. You need 3 cultists invoking the rune for it to work. This rune is unreliable and may cause unpredicted effect when invoked. It also drains significant amount of your health when succesfully invoked.
-

Communicate

- Invoking this rune allows you to relay a message to all cultists on the station and nearby space objects. -

Stun

- Unlike other runes, this ons is supposed to be used in talisman form. When invoked directly, it simply releases some dark energy, briefly stunning everyone around. When imbued into a talisman, you can force all of its energy into one person, stunning him so hard he cant even speak. However, effect wears off rather fast.
-

Equip Armor

- When this rune is invoked, either from a rune or a talisman, it will equip the user with the armor of the followers of Nar-Sie. To use this rune to its fullest extent, make sure you are not wearing any form of headgear, armor, gloves or shoes, and make sure you are not holding anything in your hands.
-

See Invisible

- When invoked when standing on it, this rune allows the user to see the the world beyond as long as he does not move.
- - - "} +/obj/item/weapon/tome/New() + icon_state = ticker.mode.cultdat.tome_icon + ..() +/obj/item/weapon/tome/examine(mob/user) + ..() + if(iscultist(user) || user.stat == DEAD) + to_chat(user, "The scriptures of [ticker.mode.cultdat.entity_title3]. Allows the scribing of runes and access to the knowledge archives of the cult of [ticker.mode.cultdat.entity_name].") + to_chat(user, "Striking another cultist with it will purge holy water from them.") + to_chat(user, "Striking a noncultist, however, will sear their flesh.") - Topic(href,href_list[]) - if(src.loc == usr) - var/number = text2num(href_list["number"]) - if(usr.stat|| usr.restrained()) - return - switch(href_list["action"]) - if("clear") - words[words[number]] = words[number] - if("change") - words[words[number]] = input("Enter the translation for [words[number]]", "Word notes") in engwords - for(var/w in words) - if((words[w] == words[words[number]]) && (w != words[number])) - words[w] = w - notedat = {" -
Word translation notes
- [words[1]] is [words[words[1]]] Clear
- [words[2]] is [words[words[2]]] Clear
- [words[3]] is [words[words[3]]] Clear
- [words[4]] is [words[words[4]]] Clear
- [words[5]] is [words[words[5]]] Clear
- [words[6]] is [words[words[6]]] Clear
- [words[7]] is [words[words[7]]] Clear
- [words[8]] is [words[words[8]]] Clear
- [words[9]] is [words[words[9]]] Clear
- [words[10]] is [words[words[10]]] Clear
- "} - usr << browse("[notedat]", "window=notes") -// call(/obj/item/weapon/tome/proc/edit_notes)() - else - usr << browse(null, "window=notes") +/obj/item/weapon/tome/attack(mob/living/M, mob/living/user) + if(!istype(M)) + return + if(!iscultist(user)) + return ..() + if(iscultist(M)) + if(M.reagents && M.reagents.has_reagent("holywater")) //allows cultists to be rescued from the clutches of ordained religion + to_chat(user, "You remove the taint from [M].") + var/holy2unholy = M.reagents.get_reagent_amount("holywater") + M.reagents.del_reagent("holywater") + M.reagents.add_reagent("unholywater",holy2unholy) + add_logs(user, M, "smacked", src, " removing the holy water from them") + return + M.take_organ_damage(0, 15) //Used to be a random between 5 and 20 + playsound(M, 'sound/weapons/sear.ogg', 50, 1) + M.visible_message("[user] strikes [M] with the arcane tome!", \ + "[user] strikes you with the tome, searing your flesh!") + flick("tome_attack", src) + user.do_attack_animation(M) + add_logs(user, M, "smacked", src) + +/obj/item/weapon/tome/attack_self(mob/user) + if(!iscultist(user)) + to_chat(user, "[src] seems full of unintelligible shapes, scribbles, and notes. Is this some sort of joke?") + return + open_tome(user) + +/obj/item/weapon/tome/proc/open_tome(mob/user) + var/choice = alert(user,"You open the tome...",,"Scribe Rune","More Information","Cancel") + switch(choice) + if("More Information") + read_tome(user) + if("Scribe Rune") + scribe_rune(user) + if("Cancel") return +/obj/item/weapon/tome/proc/read_tome(mob/user) + var/text = list() + text += "
Archives of [ticker.mode.cultdat.entity_title1]



" + text += "A rune's name and effects can be revealed by examining the rune.<

" -// proc/edit_notes() FUCK IT. Cant get it to work properly. - K0000 -// to_chat(world, "its been called! [usr]") -// notedat = {" -//
Word translation notes
-// [words[1]] is [words[words[1]]] Clear
-// [words[2]] is [words[words[2]]] Clear
-// [words[3]] is [words[words[3]]] Clear
-// [words[4]] is [words[words[4]]] Clear
-// [words[5]] is [words[words[5]]] Clear
-// [words[6]] is [words[words[6]]] Clear
-// [words[7]] is [words[words[7]]] Clear
-// [words[8]] is [words[words[8]]] Clear
-// [words[9]] is [words[words[9]]] Clear
-// [words[10]] is [words[words[10]]] Clear
-// "} -// to_chat(usr, "whatev") -// usr << browse(null, "window=tank") + text += "Rite of Binding
This rune is one of the most important runes the cult has, being the only way to create new talismans. A blank sheet of paper must be on top of the rune. After \ + invoking it and choosing which talisman you desire, the paper will be converted, after some delay into a talisman.

" - attack(mob/living/M as mob, mob/living/user as mob) + text += "Teleport
This rune is unique in that it requires a keyword before the scribing can begin. When invoked, it will find any other Teleport runes; \ + If any are found, the user can choose which rune to send to. Upon activation, the rune teleports everything above it to the selected rune.

" - M.attack_log += text("\[[time_stamp()]\] Has had the [name] used on him by [key_name(user)]") - user.attack_log += text("\[[time_stamp()]\] Used [name] on [key_name(M)]") - msg_admin_attack("[key_name_admin(user)] used [name] on [key_name_admin(M)]") - if(!iscarbon(M)) - M.LAssailant = null - else - M.LAssailant = user - if(istype(M,/mob/dead)) - M.invisibility = 0 - user.visible_message( \ - "\red [user] drags the ghost to our plan of reality!", \ - "\red You drag the ghost to our plan of reality!" \ - ) - return - if(!istype(M)) - return - if(!iscultist(user)) - return ..() - if(iscultist(M)) - if(M.reagents && M.reagents.has_reagent("holywater")) //allows cultists to be rescued from the clutches of ordained religion - to_chat(user, "You remove the taint from [M].") - var/holy2unholy = M.reagents.get_reagent_amount("holywater") - M.reagents.del_reagent("holywater") - M.reagents.add_reagent("unholywater",holy2unholy) - add_logs(user, M, "smacked", src, " removing the holy water from them") - return - M.take_organ_damage(0,rand(5,20)) //really lucky - 5 hits for a crit - for(var/mob/O in viewers(M, null)) - O.show_message(text("[] beats [] with the arcane tome!", user, M), 1) - to_chat(M, "\red You feel searing heat inside!") + text += "Rite of Enlightenment
This rune is critical to the success of the cult. It will allow you to convert normal crew members into cultists. \ + To do this, simply place the crew member upon the rune and invoke it. This rune requires two invokers to use. If the target to be converted is loyalty-implanted or a certain assignment, they will \ + be unable to be converted. People [ticker.mode.cultdat.entity_title3] wishes sacrificed will also be ineligible for conversion, and anyone with a shielding presence like the null rod will not be converted.
\ + Successful conversions will produce a tome for the new cultist.

" + text += "Rite of Tribute
This rune is necessary to achieve your goals. Simply place any dead creature upon the rune and invoke it (this will not \ + target cultists!). If this creature has a mind, a soulstone will be created and the creature's soul transported to it. Sacrificing the dead can be done alone, but sacrificing living crew or your cult's target will require 3 cultists. \ + Soulstones used on construct shells will move that soul into a powerful construct of your choice.

" - attack_self(mob/living/user as mob) - usr = user - if(!usr.canmove || usr.stat || usr.restrained()) - return + text += "Rite of Resurrection
This rune requires two corpses. To perform the ritual, place the corpse you wish to revive onto \ + the rune and the offering body adjacent to it. When the rune is invoked, the body to be sacrificed will turn to dust, the life force flowing into the revival target. Assuming the target is not moved \ + within a few seconds, they will be brought back to life, healed of all ailments.

" - if(!cultwords["travel"]) - runerandom() - if(iscultist(user)) - var/C = 0 - for(var/obj/effect/rune/N in world) - C++ - if(!istype(user.loc,/turf)) - to_chat(user, "\red You do not have enough space to write a proper rune.") - return + text += "Rite of Disruption
Robotic lifeforms have time and time again been the downfall of fledgling cults. This rune may allow you to gain the upper \ + hand against these pests. By using the rune, a large electromagnetic pulse will be emitted from the rune's location. The size of the EMP will grow significantly for each additional adjacent cultist when the \ + rune is activated.

" + text += "Astral Communion
This rune is perhaps the most ingenious rune that is usable by a single person. Upon invoking the rune, the \ + user's spirit will be ripped from their body. In this state, the user's physical body will be locked in place to the rune itself - any attempts to move it will result in the rune pulling it back. \ + The body will also take constant damage while in this form, and may even die. The user's spirit will contain their consciousness, and will allow them to freely wander the station as a ghost. This may \ + also be used to commune with the dead.

" + text += "Rite of the Corporeal Shield
While simple, this rune serves an important purpose in defense and hindering passage. When invoked, the \ + rune will draw a small amount of life force from the user and make the space above the rune completely dense, rendering it impassable to all but the most complex means. The rune may be invoked again to \ + undo this effect and allow passage again.

" + text += "Rite of Joined Souls
This rune allows the cult to free other cultists with ease. When invoked, it will allow the user to summon a single cultist to the rune from \ + any location. It requires two invokers, and will damage each invoker slightly.

" - if(C>=26+runedec+ticker.mode.cult.len) //including the useless rune at the secret room, shouldn't count against the limit of 25 runes - Urist - alert("The cloth of reality can't take that much of a strain. Remove some runes first!") + text += "Blood Boil
When invoked, this rune will do a massive amount of damage to all non-cultist viewers, but it will also emit a small explosion upon invocation. \ + It requires three invokers.

" + + text += "Leeching
When invoked, this rune will transfer lifeforce from the victim to the invoker.

" + + text += "Rite of Spectral Manifestation
This rune allows you to summon spirits as humanoid fighters. When invoked, a spirit above the rune will be brought to life as a human, wearing nothing, that seeks only to serve you and [ticker.mode.cultdat.entity_title3]. \ + However, the spirit's link to reality is fragile - you must remain on top of the rune, and you will slowly take damage. Upon stepping off the rune, all summoned spirits will dissipate, dropping their items to the ground. You may manifest \ + multiple spirits with one rune, but you will rapidly take damage in doing so.

" + + text += "Ritual of Dimensional Rending
This rune is necessary to achieve your goals. On attempting to scribe it, it will produce shields around you and alert everyone you are attempting to scribe it; it takes a very long time to scribe, \ + and does massive damage to the one attempting to scribe it.
Invoking it requires 9 invokers and the sacrifice of a specific crewmember, and once invoked, will summon [ticker.mode.cultdat.entity_title3], [ticker.mode.cultdat.entity_name]. \ + This will complete your objectives.


" + + text += "Talisman of Teleportation
The talisman form of the Teleport rune will transport the invoker to a selected Teleport rune once.

" + + text += "Talisman of Fabrication
This talisman is the main way of creating construct shells. To use it, one must strike 30 sheets of metal with the talisman. The sheets will then be twisted into a construct shell, ready to recieve a soul to occupy it.

" + + text += "Talisman of Tome Summoning
This talisman will produce a single tome at your feet.

" + + text += "Talisman of Veiling/Revealing
This talisman will hide runes on its first use, and on the second, will reveal runes.

" + + text += "Talisman of Disguising
This talisman will permanently disguise all nearby runes as crayon runes.

" + + text += "Talisman of Electromagnetic Pulse
This talisman will EMP anything else nearby. It disappears after one use.

" + + text += "Talisman of Stunning
Attacking a target will knock them down for a long duration in addition to inhibiting their speech. \ + Robotic lifeforms will suffer the effects of a heavy electromagnetic pulse instead.

" + + text += "Talisman of Armaments
The Talisman of Arming will equip the user with armored robes, a backpack, an eldritch longsword, an empowered bola, and a pair of boots. Any items that cannot \ + be equipped will not be summoned. Attacking a fellow cultist with it will instead equip them.

" + + text += "Talisman of Horrors
The Talisman of Horror must be applied directly to the victim, it will shatter your victim's mind with visions of the endtimes that may incapitate them.

" + + text += "Talisman of Shackling
The Talisman of Shackling must be applied directly to the victim, it has 4 uses and cuffs victims with magic shackles that disappear when removed.

" + + text += "In addition to these runes, the cult has a small selection of equipment and constructs.

" + + text += "Equipment:

" + + text += "Cult Blade
Cult blades are sharp weapons that, notably, cannot be used by noncultists. These blades are produced by the Talisman of Arming.

" + + text += "Cult Bola
Cult bolas are strong bolas, useful for snaring targets. These bolas are produced by the Talisman of Arming.

" + + text += "Cult Robes
Cult robes are heavily armored robes. These robes are produced by the Talisman of Arming.

" + + text += "Soulstone
A soulstone is a simple piece of magic, produced either via the starter talisman or by sacrificing humans. Using it on an unconscious or dead human, or on a Shade, will trap their soul in the stone, allowing its use in construct shells. \ +
The soul within can also be released as a Shade by using it in-hand.

" + + text += "Construct Shell
A construct shell is useless on its own, but placing a filled soulstone within it allows you to produce your choice of a Wraith, a Juggernaut, or an Artificer. \ +
Each construct has uses, detailed below in Constructs. Construct shells can be produced via the starter talisman or the Rite of Fabrication.

" + + text += "Constructs:

" + + text += "Shade
While technically not a construct, the Shade is produced when released from a soulstone. It is quite fragile and has weak melee attacks, but is fully healed when recaptured by a soulstone.

" + + text += "Wraith
The Wraith is a fast, lethal melee attacker which can jaunt through walls. However, it is only slightly more durable than a shade.

" + + text += "Juggernaut
The Juggernaut is a slow, but durable, melee attacker which can produce temporary forcewalls. It will also reflect most lethal energy weapons.

" + + text += "Artificer
The Artificer is a weak and fragile construct, able to heal other constructs, produce more soulstones and construct shells, \ + construct fortifying cult walls and flooring, and finally, it can release a few indiscriminate stunning missiles.

" + + text += "Harvester
If you see one, know that you have done all you can and your life is void.

" + + var/text_string = jointext(text, null) + var/datum/browser/popup = new(user, "tome", "", 800, 600) + popup.set_content(text_string) + popup.open() + return 1 + +/obj/item/weapon/tome/proc/finale_runes_ok(mob/living/user, obj/effect/rune/rune_to_scribe) + + if(ticker.mode.name == "cult") + if(!canbypass == 1)//not an admin-tome, check things + var/datum/game_mode/cult/cult_mode = ticker.mode + if(!cult_mode.narsie_condition_cleared) + to_chat(user, "There is still more to do before unleashing [cult_mode.cultdat.entity_name] power!") + return 0 + if(!cult_mode.eldergod) + to_chat(user, "\"I am already here. There is no need to try to summon me now.\"") + return 0 + if(cult_mode.demons_summoned) + to_chat(user, "\"We are already here. There is no need to try to summon us now.\"") + return 0 + if(!(CULT_ELDERGOD in cult_mode.objectives) || !(CULT_SLAUGHTER in cult_mode.objectives)) + to_chat(user, "[cult_mode.cultdat.entity_name]'s power does not wish to be unleashed!") + return 0 + var/confirm_final = alert(user, "This is the FINAL step to summon your dietys power, it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No") + if(confirm_final == "No") + to_chat(user, "You decide to prepare further before scribing the rune.") return else - switch(alert("You open the tome",,"Read it","Scribe a rune", "Notes")) //Fuck the "Cancel" option. Rewrite the whole tome interface yourself if you want it to work better. And input() is just ugly. - K0000 - if("Cancel") - return - if("Read it") - if(usr.get_active_hand() != src) - return - user << browse("[tomedat]", "window=Arcane Tome") - return - if("Notes") - if(usr.get_active_hand() != src) - return - notedat = {" -
Word translation notes
- [words[1]] is [words[words[1]]] Clear
- [words[2]] is [words[words[2]]] Clear
- [words[3]] is [words[words[3]]] Clear
- [words[4]] is [words[words[4]]] Clear
- [words[5]] is [words[words[5]]] Clear
- [words[6]] is [words[words[6]]] Clear
- [words[7]] is [words[words[7]]] Clear
- [words[8]] is [words[words[8]]] Clear
- [words[9]] is [words[words[9]]] Clear
- [words[10]] is [words[words[10]]] Clear
- "} -// call(/obj/item/weapon/tome/proc/edit_notes)() - user << browse("[notedat]", "window=notes") - return - if(usr.get_active_hand() != src) - return + return 1 + else//the game mode is not cult..but we ARE a cultist...ALL ON THE ADMINBUS + if(!canbypass == 1)//not an admin-tome, check things + var/confirm_final = alert(user, "This is the FINAL step to summon your dietys power, it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No") + if(confirm_final == "No") + to_chat(user, "You decide to prepare further before scribing the rune.") + return 0 + else + return 1 - var/list/dictionary = list ( - "convert" = list("join","blood","self"), - "wall" = list("destroy","travel","self"), - "blood boil" = list("destroy","see","blood"), - "blood drain" = list("travel","blood","self"), - "raise dead" = list("blood","join","hell"), - "summon narsie" = list("hell","join","self"), - "communicate" = list("self","other","technology"), - "emp" = list("destroy","see","technology"), - "manifest" = list("blood","see","travel"), - "summon tome" = list("see","blood","hell"), - "see invisible" = list("see","hell","join"), - "hide" = list("hide","see","blood"), - "reveal" = list("blood","see","hide"), - "astral journey" = list("hell","travel","self"), - "imbue" = list("hell","technology","join"), - "sacrifice" = list("hell","blood","join"), - "summon cultist" = list("join","other","self"), - "free cultist" = list("travel","technology","other"), - "deafen" = list("hide","other","see"), - "blind" = list("destroy","see","other"), - "stun" = list("join","hide","technology"), - "armor" = list("hell","destroy","other"), - "teleport" = list("travel","self"), - "teleport other" = list("travel","other") - ) - - var/list/english = list() - - var/list/scribewords = list("none") - - for(var/entry in words) - if(words[entry] != entry) - english += list(words[entry] = entry) - - for(var/entry in dictionary) - var/list/required = dictionary[entry] - if(length(english&required) == required.len) - scribewords += entry - - var/chosen_rune = null - - if(usr) - chosen_rune = input ("Choose a rune to scribe.") in scribewords - if(!chosen_rune) +/obj/item/weapon/tome/proc/scribe_rune(mob/living/user) + var/turf/runeturf = get_turf(user) + var/chosen_keyword + var/obj/effect/rune/rune_to_scribe + var/entered_rune_name + var/list/possible_runes = list() + var/list/shields = list() + if(locate(/obj/effect/rune) in runeturf) + to_chat(user, "There is already a rune here.") + return + for(var/T in subtypesof(/obj/effect/rune) - /obj/effect/rune/malformed) + var/obj/effect/rune/R = T + if(initial(R.cultist_name)) + possible_runes.Add(initial(R.cultist_name)) //This is to allow the menu to let cultists select runes by name rather than by object path. I don't know a better way to do this + if(!possible_runes.len) + return + entered_rune_name = input(user, "Choose a rite to scribe.", "Sigils of Power") as null|anything in possible_runes + if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated()) + return + for(var/T in typesof(/obj/effect/rune)) + var/obj/effect/rune/R = T + if(initial(R.cultist_name) == entered_rune_name) + rune_to_scribe = R + if(initial(R.req_keyword)) + var/the_keyword = stripped_input(usr, "Please enter a keyword for the rune.", "Enter Keyword", "") + if(!the_keyword) return - if(chosen_rune == "none") - to_chat(user, "\red You decide against scribing a rune, perhaps you should take this time to study your notes.") - return - if(chosen_rune == "teleport") - dictionary[chosen_rune] += input ("Choose a destination word") in english - if(chosen_rune == "teleport other") - dictionary[chosen_rune] += input ("Choose a destination word") in english + chosen_keyword = the_keyword + break + if(!rune_to_scribe) + return + runeturf = get_turf(user) //we may have moved. adjust as needed... + if(locate(/obj/effect/rune) in runeturf) + to_chat(user, "There is already a rune here.") + return + if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated()) + return + if(ispath(rune_to_scribe, /obj/effect/rune/narsie) || ispath(rune_to_scribe, /obj/effect/rune/slaughter))//may need to change this - Fethas + if(finale_runes_ok(user,rune_to_scribe)) + command_announcement.Announce("Figments from an eldritch god are being summoned somwhere on the station from an unknown dimension. Disrupt the ritual at all costs!","Central Command Higher Dimensionsal Affairs", 'sound/AI/spanomalies.ogg') + for(var/B in spiral_range_turfs(1, user, 1)) + var/turf/T = B + var/obj/machinery/shield/N = new(T) + N.name = "Rune-Scriber's Shield" + N.desc = "A potent shield summoned by cultists to protect them while they prepare the final ritual" + N.icon_state = "shield-cult" + N.health = 60 + shields |= N - if(usr.get_active_hand() != src) - return - - for(var/mob/V in viewers(src)) - V.show_message("\red [user] slices open a finger and begins to chant and paint symbols on the floor.", 3, "\red You hear chanting.", 2) - to_chat(user, "\red You slice open one of your fingers and begin drawing a rune on the floor whilst chanting the ritual that binds your life essence with the dark arcane energies flowing through the surrounding world.") - user.take_overall_damage((rand(9)+1)/10) // 0.1 to 1.0 damage - if(do_after(user, 50, target = user)) - if(usr.get_active_hand() != src) - return - var/mob/living/carbon/human/H = user - var/obj/effect/rune/R = new /obj/effect/rune(user.loc) - to_chat(user, "\red You finish drawing the arcane markings of the Geometer.") - var/list/required = dictionary[chosen_rune] - R.word1 = english[required[1]] - R.word2 = english[required[2]] - R.word3 = english[required[3]] - R.check_icon() - R.blood_DNA = list() - R.blood_DNA[H.dna.unique_enzymes] = H.dna.b_type - R.add_hiddenprint(H) - return - else - to_chat(user, "The book seems full of illegible scribbles. Is this a joke?") - return - - attackby(obj/item/weapon/tome/T as obj, mob/living/user as mob, params) - if(istype(T, /obj/item/weapon/tome)) // sanity check to prevent a runtime error - switch(alert("Copy the runes from your tome?",,"Copy", "Cancel")) - if("cancel") - return - // var/list/nearby = viewers(1,src) //- Fuck this as well. No clue why this doesnt work. -K0000 - // if(T.loc != user) - // return - // for(var/mob/M in nearby) - // if(M == user) - for(var/entry in words) - words[entry] = T.words[entry] - to_chat(user, "You copy the translation notes from your tome.") - - - examine(mob/user) - if(!iscultist(user)) - to_chat(user, "An old, dusty tome with frayed edges and a sinister looking cover.") - else - to_chat(user, "The scriptures of Nar-Sie, The One Who Sees, The Geometer of Blood. Contains the details of every ritual his followers could think of. Most of these are useless, though.") - -/obj/item/weapon/tome/imbued //admin tome, spawns working runes without waiting - w_class = 2 - var/cultistsonly = 1 - attack_self(mob/user as mob) - if(src.cultistsonly && !iscultist(usr)) - return - if(!cultwords["travel"]) - runerandom() - if(user) - var/r - if(!istype(user.loc,/turf)) - to_chat(user, "\red You do not have enough space to write a proper rune.") - var/list/runes = list("teleport", "itemport", "tome", "armor", "convert", "tear in reality", "emp", "drain", "seer", "raise", "obscure", "reveal", "astral journey", "manifest", "imbue talisman", "sacrifice", "wall", "freedom", "cultsummon", "deafen", "blind", "bloodboil", "communicate", "stun") - r = input("Choose a rune to scribe", "Rune Scribing") in runes //not cancellable. - var/obj/effect/rune/R = new /obj/effect/rune - if(istype(user, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - R.blood_DNA = list() - R.blood_DNA[H.dna.unique_enzymes] = H.dna.b_type - switch(r) - if("teleport") - var/list/words = list("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "balaq", "mgar", "karazet", "geeri") - var/beacon - if(usr) - beacon = input("Select the last rune", "Rune Scribing") in words - R.word1=cultwords["travel"] - R.word2=cultwords["self"] - R.word3=beacon - R.loc = user.loc - R.check_icon() - if("itemport") - var/list/words = list("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "balaq", "mgar", "karazet", "geeri") - var/beacon - if(usr) - beacon = input("Select the last rune", "Rune Scribing") in words - R.word1=cultwords["travel"] - R.word2=cultwords["other"] - R.word3=beacon - R.loc = user.loc - R.check_icon() - if("tome") - R.word1=cultwords["see"] - R.word2=cultwords["blood"] - R.word3=cultwords["hell"] - R.loc = user.loc - R.check_icon() - if("armor") - R.word1=cultwords["hell"] - R.word2=cultwords["destroy"] - R.word3=cultwords["other"] - R.loc = user.loc - R.check_icon() - if("convert") - R.word1=cultwords["join"] - R.word2=cultwords["blood"] - R.word3=cultwords["self"] - R.loc = user.loc - R.check_icon() - if("tear in reality") - R.word1=cultwords["hell"] - R.word2=cultwords["join"] - R.word3=cultwords["self"] - R.loc = user.loc - R.check_icon() - if("emp") - R.word1=cultwords["destroy"] - R.word2=cultwords["see"] - R.word3=cultwords["technology"] - R.loc = user.loc - R.check_icon() - if("drain") - R.word1=cultwords["travel"] - R.word2=cultwords["blood"] - R.word3=cultwords["self"] - R.loc = user.loc - R.check_icon() - if("seer") - R.word1=cultwords["see"] - R.word2=cultwords["hell"] - R.word3=cultwords["join"] - R.loc = user.loc - R.check_icon() - if("raise") - R.word1=cultwords["blood"] - R.word2=cultwords["join"] - R.word3=cultwords["hell"] - R.loc = user.loc - R.check_icon() - if("obscure") - R.word1=cultwords["hide"] - R.word2=cultwords["see"] - R.word3=cultwords["blood"] - R.loc = user.loc - R.check_icon() - if("astral journey") - R.word1=cultwords["hell"] - R.word2=cultwords["travel"] - R.word3=cultwords["self"] - R.loc = user.loc - R.check_icon() - if("manifest") - R.word1=cultwords["blood"] - R.word2=cultwords["see"] - R.word3=cultwords["travel"] - R.loc = user.loc - R.check_icon() - if("imbue talisman") - R.word1=cultwords["hell"] - R.word2=cultwords["technology"] - R.word3=cultwords["join"] - R.loc = user.loc - R.check_icon() - if("sacrifice") - R.word1=cultwords["hell"] - R.word2=cultwords["blood"] - R.word3=cultwords["join"] - R.loc = user.loc - R.check_icon() - if("reveal") - R.word1=cultwords["blood"] - R.word2=cultwords["see"] - R.word3=cultwords["hide"] - R.loc = user.loc - R.check_icon() - if("wall") - R.word1=cultwords["destroy"] - R.word2=cultwords["travel"] - R.word3=cultwords["self"] - R.loc = user.loc - R.check_icon() - if("freedom") - R.word1=cultwords["travel"] - R.word2=cultwords["technology"] - R.word3=cultwords["other"] - R.loc = user.loc - R.check_icon() - if("cultsummon") - R.word1=cultwords["join"] - R.word2=cultwords["other"] - R.word3=cultwords["self"] - R.loc = user.loc - R.check_icon() - if("deafen") - R.word1=cultwords["hide"] - R.word2=cultwords["other"] - R.word3=cultwords["see"] - R.loc = user.loc - R.check_icon() - if("blind") - R.word1=cultwords["destroy"] - R.word2=cultwords["see"] - R.word3=cultwords["other"] - R.loc = user.loc - R.check_icon() - if("bloodboil") - R.word1=cultwords["destroy"] - R.word2=cultwords["see"] - R.word3=cultwords["blood"] - R.loc = user.loc - R.check_icon() - if("communicate") - R.word1=cultwords["self"] - R.word2=cultwords["other"] - R.word3=cultwords["technology"] - R.loc = user.loc - R.check_icon() - if("stun") - R.word1=cultwords["join"] - R.word2=cultwords["hide"] - R.word3=cultwords["technology"] - R.loc = user.loc - R.check_icon() + var/mob/living/carbon/human/H = user + var/dam_zone = pick("head", "chest", "groin", "l_arm", "l_hand", "r_arm", "r_hand", "l_leg", "l_foot", "r_leg", "r_foot") + var/obj/item/organ/external/affecting = H.get_organ(ran_zone(dam_zone)) + user.visible_message("[user] cuts open their \The [affecting] and begins writing in their own blood!", "You slice open your [affecting] and begin drawing a sigil of [ticker.mode.cultdat.entity_title3].") + user.apply_damage(initial(rune_to_scribe.scribe_damage), BRUTE , affecting) + if(!do_after(user, initial(rune_to_scribe.scribe_delay)-scribereduct, target = get_turf(user))) + for(var/V in shields) + var/obj/machinery/shield/S = V + if(S && !qdeleted(S)) + qdel(S) + return + if(locate(/obj/effect/rune) in runeturf) + to_chat(user, "There is already a rune here.") + return + user.visible_message("[user] creates a strange circle in their own blood.", \ + "You finish drawing the arcane markings of [ticker.mode.cultdat.entity_title3].") + for(var/V in shields) + var/obj/machinery/shield/S = V + if(S && !qdeleted(S)) + qdel(S) + var/obj/effect/rune/R = new rune_to_scribe(runeturf, chosen_keyword) + R.blood_DNA = list() + R.blood_DNA[H.dna.unique_enzymes] = H.dna.b_type + R.add_hiddenprint(H) + to_chat(user, "The [lowertext(initial(rune_to_scribe.cultist_name))] rune [initial(rune_to_scribe.cultist_desc)]") diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 533da29f7cd..63baec609b7 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -1,1046 +1,1003 @@ -var/list/sacrificed = list() +/var/list/sacrificed = list() +var/list/non_revealed_runes = (subtypesof(/obj/effect/rune) - /obj/effect/rune/malformed) - -/////////////////////////////////////////FIRST RUNE -/obj/effect/rune/proc/teleportRune() - return teleport(src.word3) - -/obj/effect/rune/proc/teleport(var/key) - var/mob/living/user = usr - var/allrunesloc[] - allrunesloc = new/list() - var/index = 0 -// var/tempnum = 0 - for(var/obj/effect/rune/R in world) - if(R == src) - continue - if(R.word1 == cultwords["travel"] && R.word2 == cultwords["self"] && R.word3 == key && is_teleport_allowed(R.z)) - index++ - allrunesloc.len = index - allrunesloc[index] = R.loc - if(index >= 5) - to_chat(user, "\red You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric") - if(istype(user, /mob/living)) - user.take_overall_damage(5, 0) - qdel(src) - if(allrunesloc && index != 0) - if(istype(src,/obj/effect/rune)) - user.say("Sas[pick("'","`")]so c'arta forbici!")//Only you can stop auto-muting - else - user.whisper("Sas[pick("'","`")]so c'arta forbici!") - user.visible_message("\red [user] disappears in a flash of red light!", \ - "\red You feel as your body gets dragged through the dimension of Nar-Sie!", \ - "\red You hear a sickening crunch and sloshing of viscera.") - user.loc = allrunesloc[rand(1,index)] - return - if(istype(src,/obj/effect/rune)) - return fizzle() //Use friggin manuals, Dorf, your list was of zero length. - else - call(/obj/effect/rune/proc/fizzle)() - return - -/obj/effect/rune/proc/itemportRune() - return itemport(src.word3) -/obj/effect/rune/proc/itemport(var/key) -// var/allrunesloc[] -// allrunesloc = new/list() -// var/index = 0 -// var/tempnum = 0 - var/culcount = 0 - var/runecount = 0 - var/obj/effect/rune/IP = null - var/mob/living/user = usr - for(var/obj/effect/rune/R in world) - if(R == src) - continue - if(R.word1 == cultwords["travel"] && R.word2 == cultwords["other"] && R.word3 == key) - IP = R - runecount++ - if(runecount >= 2) - to_chat(user, "\red You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric") - if(istype(user, /mob/living)) - user.take_overall_damage(5, 0) - qdel(src) - for(var/mob/living/carbon/C in orange(1,src)) - if(iscultist(C) && !C.stat) - culcount++ - if(culcount>=3) - user.say("Sas[pick("'","`")]so c'arta forbici tarem!") - user.visible_message("\red You feel air moving from the rune - like as it was swapped with somewhere else.", \ - "\red You feel air moving from the rune - like as it was swapped with somewhere else.", \ - "\red You smell ozone.") - for(var/obj/O in src.loc) - if(!O.anchored) - O.loc = IP.loc - for(var/mob/M in src.loc) - M.loc = IP.loc - return - - return fizzle() - - -/////////////////////////////////////////SECOND RUNE - -/obj/effect/rune/proc/tomesummon() - if(istype(src,/obj/effect/rune)) - usr.say("N[pick("'","`")]ath reth sh'yro eth d'raggathnor!") - else - usr.whisper("N[pick("'","`")]ath reth sh'yro eth d'raggathnor!") - usr.visible_message("\red Rune disappears with a flash of red light, and in its place now a book lies.", \ - "\red You are blinded by the flash of red light! After you're able to see again, you see that now instead of the rune there's a book.", \ - "\red You hear a pop and smell ozone.") - if(istype(src,/obj/effect/rune)) - new /obj/item/weapon/tome(src.loc) - else - new /obj/item/weapon/tome(usr.loc) - qdel(src) - return - - - -/////////////////////////////////////////THIRD RUNE - -/obj/effect/rune/proc/convert() - for(var/mob/living/carbon/M in src.loc) - if(iscultist(M)) - continue - if(M.stat==2) - continue - usr.say("Mah[pick("'","`")]weyh pleggh at e'ntrath!") - M.visible_message("\red [M] writhes in pain as the markings below him glow a bloody red.", \ - "\red AAAAAAHHHH!.", \ - "\red You hear an anguished scream.") - cult_log("[key_name(usr)] tried to convert [key_name(M)]") - if(is_convertable_to_cult(M.mind)) - ticker.mode.add_cultist(M.mind) - M.mind.special_role = SPECIAL_ROLE_CULTIST - to_chat(M, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.") - to_chat(M, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") - return 1 - else - to_chat(M, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.") - to_chat(M, "And you were able to force it out of your mind. You now know the truth, there's something horrible out there, stop it and its minions at all costs.") - return 0 - - return fizzle() - - - -/////////////////////////////////////////FOURTH RUNE - -/obj/effect/rune/proc/tearreality() - var/cultist_count = 0 - for(var/mob/M in range(1,src)) - if(iscultist(M) && !M.stat) - M.say("Tok-lyr rqa'nap g[pick("'","`")]lt-ulotf!") - cultist_count += 1 - if(cultist_count >= 9) - cult_log("THE CULT HAS SUMMONED NAR'SIE. GGNORE") - new /obj/singularity/narsie/large(src.loc) - if(ticker.mode.name == "cult") - ticker.mode:eldergod = 0 - return - else - return fizzle() - -/////////////////////////////////////////FIFTH RUNE -/obj/effect/rune/proc/empRune() - emp(src.loc,3) - -/obj/effect/rune/proc/emp(var/U,var/range_red) //range_red - var which determines by which number to reduce the default emp range, U is the source loc, needed because of talisman emps which are held in hand at the moment of using and that apparently messes things up -- Urist - if(istype(src,/obj/effect/rune)) - usr.say("Ta'gh fara[pick("'","`")]qha fel d'amar det!") - else - usr.whisper("Ta'gh fara[pick("'","`")]qha fel d'amar det!") - playsound(U, 'sound/items/Welder2.ogg', 25, 1) - var/turf/T = get_turf(U) - if(T) - T.hotspot_expose(700,125) - var/rune = src // detaching the proc - in theory - empulse(U, (range_red - 2), range_red) - qdel(rune) - return - -/////////////////////////////////////////SIXTH RUNE - -/obj/effect/rune/proc/drain() - var/drain = 0 - for(var/obj/effect/rune/R in world) - if(R.word1==cultwords["travel"] && R.word2==cultwords["blood"] && R.word3==cultwords["self"]) - for(var/mob/living/carbon/D in R.loc) - if(D.stat!=2) - cult_log("[key_name(usr)] has drained blood from [key_name(D)]") - var/bdrain = rand(1,25) - to_chat(D, "\red You feel weakened.") - D.take_overall_damage(bdrain, 0) - drain += bdrain - if(!drain) - return fizzle() - usr.say ("Yu[pick("'","`")]gular faras desdae. Havas mithum javara. Umathar uf'kal thenar!") - usr.visible_message("\red Blood flows from the rune into [usr]!", \ - "\red The blood starts flowing from the rune and into your frail mortal body. You feel... empowered.", \ - "\red You hear a liquid flowing.") - var/mob/living/user = usr - if(user.bhunger) - user.bhunger = max(user.bhunger-2*drain,0) - if(drain>=50) - user.visible_message("\red [user]'s eyes give off eerie red glow!", \ - "\red ...but it wasn't nearly enough. You crave, crave for more. The hunger consumes you from within.", \ - "\red You hear a heartbeat.") - user.bhunger += drain - src = user - spawn() - for(,user.bhunger>0,user.bhunger--) - sleep(50) - user.take_overall_damage(3, 0) - return - user.heal_organ_damage(drain%5, 0) - drain-=drain%5 - for(,drain>0,drain-=5) - sleep(2) - user.heal_organ_damage(5, 0) - return - - - - - - -/////////////////////////////////////////SEVENTH RUNE - -/obj/effect/rune/proc/seer() - if(usr.loc==src.loc) - // No. Bad cultcode. Bad. - var/mob/living/carbon/human/H = usr - if(usr.seer==1) - usr.say("Rash'tla sektath mal[pick("'","`")]zua. Zasan therium viortia.") - to_chat(usr, "\red The world beyond fades from your vision.") - usr.see_invisible = SEE_INVISIBLE_LIVING - usr.seer = 0 - else if(usr.see_invisible!=SEE_INVISIBLE_LIVING) - to_chat(usr, "\red The world beyond flashes your eyes but disappears quickly, as if something is disrupting your vision.") - usr.see_invisible = SEE_INVISIBLE_OBSERVER - usr.seer = 0 - else - usr.say("Rash'tla sektath mal[pick("'","`")]zua. Zasan therium vivira. Itonis al'ra matum!") - to_chat(usr, "\red The world beyond opens to your eyes.") - usr.see_invisible = SEE_INVISIBLE_OBSERVER - usr.seer = 1 - H.update_sight() - return - return fizzle() - -/////////////////////////////////////////EIGHTH RUNE - -/obj/effect/rune/proc/raise() - var/mob/living/carbon/human/corpse_to_raise - var/mob/living/carbon/human/body_to_sacrifice - - var/is_sacrifice_target = 0 - for(var/mob/living/carbon/human/M in src.loc) - if(M.stat == DEAD) - if(ticker.mode.name == "cult" && M.mind == ticker.mode:sacrifice_target) - is_sacrifice_target = 1 - else - corpse_to_raise = M - if(M.key) - M.ghostize(1) //kick them out of their body - break - if(!corpse_to_raise) - if(is_sacrifice_target) - to_chat(usr, "\red The Geometer of blood wants this mortal for himself.") - return fizzle() - - - is_sacrifice_target = 0 - find_sacrifice: - for(var/obj/effect/rune/R in world) - if(R.word1==cultwords["blood"] && R.word2==cultwords["join"] && R.word3==cultwords["hell"]) - for(var/mob/living/carbon/human/N in R.loc) - if(ticker.mode.name == "cult" && N.mind && N.mind == ticker.mode:sacrifice_target) - is_sacrifice_target = 1 - else - if(N.stat!= DEAD) - body_to_sacrifice = N - break find_sacrifice - - if(!body_to_sacrifice) - if(is_sacrifice_target) - to_chat(usr, "\red The Geometer of blood wants that corpse for himself.") - else - to_chat(usr, "\red The sacrifical corpse is not dead. You must free it from this world of illusions before it may be used.") - return fizzle() - - var/mob/dead/observer/ghost - for(var/mob/dead/observer/O in loc) - if(!O.client) continue - if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue - ghost = O - break - - if(!ghost) - to_chat(usr, "\red You require a restless spirit which clings to this world. Beckon their prescence with the sacred chants of Nar-Sie.") - return fizzle() - - corpse_to_raise.revive() - - corpse_to_raise.key = ghost.key //the corpse will keep its old mind! but a new player takes ownership of it (they are essentially possessed) - //This means, should that player leave the body, the original may re-enter - usr.say("Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!") - corpse_to_raise.visible_message("\red [corpse_to_raise]'s eyes glow with a faint red as he stands up, slowly starting to breathe again.", \ - "\red Life... I'm alive again...", \ - "\red You hear a faint, slightly familiar whisper.") - body_to_sacrifice.visible_message("\red [body_to_sacrifice] is torn apart, a black smoke swiftly dissipating from his remains!", \ - "\red You feel as your blood boils, tearing you apart.", \ - "\red You hear a thousand voices, all crying in pain.") - body_to_sacrifice.gib() - -// if(ticker.mode.name == "cult") -// ticker.mode:add_cultist(corpse_to_raise.mind) -// else -// ticker.mode.cult |= corpse_to_raise.mind - - to_chat(corpse_to_raise, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.") - to_chat(corpse_to_raise, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") - return - - - - - -/////////////////////////////////////////NINETH RUNE - -/obj/effect/rune/proc/obscureRune() - return obscure(4) -/obj/effect/rune/proc/obscure(var/rad) - var/S=0 - for(var/obj/effect/rune/R in orange(rad,src)) - if(R!=src) - R.invisibility=INVISIBILITY_OBSERVER - S=1 - if(S) - if(istype(src,/obj/effect/rune)) - usr.say("Kla[pick("'","`")]atu barada nikt'o!") - for(var/mob/V in viewers(src)) - V.show_message("\red The rune turns into gray dust, veiling the surrounding runes.", 3) - qdel(src) - else - usr.whisper("Kla[pick("'","`")]atu barada nikt'o!") - to_chat(usr, "\red Your talisman turns into gray dust, veiling the surrounding runes.") - for(var/mob/V in orange(1,src)) - if(V!=usr) - V.show_message("\red Dust emanates from [usr]'s hands for a moment.", 3) - - return - if(istype(src,/obj/effect/rune)) - return fizzle() - else - call(/obj/effect/rune/proc/fizzle)() - return - -/////////////////////////////////////////TENTH RUNE - -/obj/effect/rune/proc/ajourney() //some bits copypastaed from admin tools - Urist - if(usr.loc==src.loc) - var/mob/living/carbon/human/L = usr - usr.say("Fwe[pick("'","`")]sh mah erl nyag r'ya!") - usr.visible_message("\red [usr]'s eyes glow blue as \he freezes in place, absolutely motionless.", \ - "\red The shadow that is your spirit separates itself from your body. You are now in the realm beyond. While this is a great sight, being here strains your mind and body. Hurry...", \ - "\red You hear only complete silence for a moment.") - usr.ghostize(1) - L.ajourn = 1 - while(L) - if(L.key) - L.ajourn=0 - return - else - L.take_organ_damage(10, 0) - sleep(100) - return fizzle() - - - - -/////////////////////////////////////////ELEVENTH RUNE - -/obj/effect/rune/proc/manifest() - var/obj/effect/rune/this_rune = src - src = null - if(usr.loc!=this_rune.loc) - return this_rune.fizzle() - var/mob/dead/observer/ghost - for(var/mob/dead/observer/O in this_rune.loc) - if(!O.client) continue - if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue - ghost = O - break - if(!ghost) - return this_rune.fizzle() - if(jobban_isbanned(ghost, ROLE_CULTIST) || jobban_isbanned(ghost,"Syndicate")) - return this_rune.fizzle() - - usr.say("Gal'h'rfikk harfrandid mud[pick("'","`")]gib!") - var/mob/living/carbon/human/dummy/D = new(this_rune.loc) - usr.visible_message("\red A shape forms in the center of the rune. A shape of... a man.", \ - "\red A shape forms in the center of the rune. A shape of... a man.", \ - "\red You hear liquid flowing.") - D.real_name = "Unknown" - var/chose_name = 0 - for(var/obj/item/weapon/paper/P in this_rune.loc) - if(P.info) - D.real_name = copytext(P.info, findtext(P.info,">")+1, findtext(P.info,"<",2) ) - chose_name = 1 - break - if(!chose_name) - D.real_name = "[pick(first_names_male)] [pick(last_names)]" - D.universal_speak = 1 - D.status_flags &= ~GODMODE - - D.key = ghost.key - - if(ticker.mode.name == "cult") - ticker.mode:add_cultist(D.mind) - else - ticker.mode.cult+=D.mind - - D.mind.special_role = SPECIAL_ROLE_CULTIST - to_chat(D, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.") - to_chat(D, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.") - - var/mob/living/user = usr - while(this_rune && user && user.stat==CONSCIOUS && user.client && user.loc==this_rune.loc) - user.take_organ_damage(1, 0) - sleep(30) - if(D) - D.visible_message("\red [D] slowly dissipates into dust and bones.", \ - "\red You feel pain, as bonds formed between your soul and this homunculus break.", \ - "\red You hear faint rustle.") - D.dust() - return - - - - - -/////////////////////////////////////////TWELFTH RUNE - -/obj/effect/rune/proc/talisman()//only hide, emp, teleport, deafen, blind and tome runes can be imbued atm - var/obj/item/weapon/paper/newtalisman - var/unsuitable_newtalisman = 0 - for(var/obj/item/weapon/paper/P in src.loc) - if(!P.info) - newtalisman = P - break - else - unsuitable_newtalisman = 1 - if(!newtalisman) - if(unsuitable_newtalisman) - to_chat(usr, "\red The blank is tainted. It is unsuitable.") - return fizzle() - - var/obj/effect/rune/imbued_from - var/obj/item/weapon/paper/talisman/T - for(var/obj/effect/rune/R in orange(1,src)) - if(R==src) - continue - if(R.word1==cultwords["travel"] && R.word2==cultwords["self"]) //teleport - T = new(src.loc) - T.imbue = "[R.word3]" - T.info = "[R.word3]" - imbued_from = R - break - if(R.word1==cultwords["see"] && R.word2==cultwords["blood"] && R.word3==cultwords["hell"]) //tome - T = new(src.loc) - T.imbue = "newtome" - imbued_from = R - break - if(R.word1==cultwords["destroy"] && R.word2==cultwords["see"] && R.word3==cultwords["technology"]) //emp - T = new(src.loc) - T.imbue = "emp" - imbued_from = R - break - if(R.word1==cultwords["blood"] && R.word2==cultwords["see"] && R.word3==cultwords["destroy"]) //conceal - T = new(src.loc) - T.imbue = "conceal" - imbued_from = R - break - if(R.word1==cultwords["hell"] && R.word2==cultwords["destroy"] && R.word3==cultwords["other"]) //armor - T = new(src.loc) - T.imbue = "armor" - imbued_from = R - break - if(R.word1==cultwords["blood"] && R.word2==cultwords["see"] && R.word3==cultwords["hide"]) //reveal - T = new(src.loc) - T.imbue = "revealrunes" - imbued_from = R - break - if(R.word1==cultwords["hide"] && R.word2==cultwords["other"] && R.word3==cultwords["see"]) //deafen - T = new(src.loc) - T.imbue = "deafen" - imbued_from = R - break - if(R.word1==cultwords["destroy"] && R.word2==cultwords["see"] && R.word3==cultwords["other"]) //blind - T = new(src.loc) - T.imbue = "blind" - imbued_from = R - break - if(R.word1==cultwords["self"] && R.word2==cultwords["other"] && R.word3==cultwords["technology"]) //communicate - T = new(src.loc) - T.imbue = "communicate" - imbued_from = R - break - if(R.word1==cultwords["join"] && R.word2==cultwords["hide"] && R.word3==cultwords["technology"]) //stun - T = new(src.loc) - T.imbue = "runestun" - imbued_from = R - break - if(imbued_from) - for(var/mob/V in viewers(src)) - V.show_message("\red The runes turn into dust, which then forms into an arcane image on the paper.", 3) - usr.say("H'drak v[pick("'","`")]loso, mir'kanas verbot!") - qdel(imbued_from) - qdel(newtalisman) - else - return fizzle() - -/////////////////////////////////////////THIRTEENTH RUNE - -/obj/effect/rune/proc/mend() - var/mob/living/user = usr - src = null - user.say("Uhrast ka'hfa heldsagen ver[pick("'","`")]lot!") - user.take_overall_damage(200, 0) - runedec+=10 - user.visible_message("\red [user] keels over dead, his blood glowing blue as it escapes his body and dissipates into thin air.", \ - "\red In the last moment of your humble life, you feel an immense pain as fabric of reality mends... with your blood.", \ - "\red You hear faint rustle.") - for(,user.stat==2) - sleep(600) - if(!user) - return - runedec-=10 - return - - -/////////////////////////////////////////FOURTEETH RUNE - -// returns 0 if the rune is not used. returns 1 if the rune is used. -/obj/effect/rune/proc/communicate() - . = 1 // Default output is 1. If the rune is deleted it will return 1 - var/input = stripped_input(usr, "Please choose a message to tell to the other acolytes.", "Voice of Blood", "") - if(!input) - if(istype(src)) - fizzle() - return 0 - else - return 0 - - // record this - //cult_log("[key_name(usr,0)] says: [input]") - - - var/F = investigate_subject2file("cult") - if(!F) - return 0 - to_chat(F, "[time2text(world.timeofday,"hh:mm")] \ref[usr] ([usr.x],[usr.y],[usr.z]) || [usr] communicates: [input]
") - - var/obj/cult_viewpoint/vp = getCultViewpoint(usr) - if(!vp) - return 0 - - var/displayName = vp.get_display_name() - var/cultName = vp.get_cult_name() - - if(istype(src,/obj/effect/rune)) - usr.say("O bidai nabora se[pick("'","`")]sma!") - else - usr.whisper("O bidai nabora se[pick("'","`")]sma!") - - if(istype(src,/obj/effect/rune)) - usr.say("[input]") - else - usr.whisper("[input]") - - log_say("Cult Message: [key_name(usr)]: [input]") - for(var/datum/mind/H in ticker.mode.cult) - if(H.current) - to_chat(H.current, "[cultName]: [input]") - - for(var/mob/spirit/spirit in spirits) - to_chat(spirit, "[displayName]: [input]") - - - for(var/mob/dead/observer/G in player_list) - G.show_message("[displayName] ([cultName]) ([ghost_follow_link(usr, ghost=G)]): [input]") - - qdel(src) - return 1 - -/////////////////////////////////////////FIFTEENTH RUNE - -/obj/effect/rune/proc/sacrifice() - var/list/mob/living/carbon/human/cultsinrange = list() - var/list/mob/living/carbon/human/victims = list() - for(var/mob/living/carbon/human/V in src.loc)//Checks for non-cultist humans to sacrifice - if(ishuman(V)) - if(!(iscultist(V))) - victims += V//Checks for cult status and mob type - for(var/obj/item/I in src.loc)//Checks for MMIs/brains/Intellicards - if(istype(I,/obj/item/organ/internal/brain)) - var/obj/item/organ/internal/brain/B = I - victims += B.brainmob - else if(istype(I,/obj/item/device/mmi)) - var/obj/item/device/mmi/B = I - victims += B.brainmob - else if(istype(I,/obj/item/device/aicard)) - for(var/mob/living/silicon/ai/A in I) - victims += A - for(var/mob/living/carbon/C in orange(1,src)) - if(iscultist(C) && !C.stat) - cultsinrange += C - C.say("Barhah hra zar[pick("'","`")]garis!") - for(var/mob/H in victims) - if(ticker.mode.name == "cult") - if(H.mind == ticker.mode:sacrifice_target) - if(cultsinrange.len >= 3) - sacrificed += H.mind - if(isrobot(H)) - H.dust()//To prevent the MMI from remaining - else - H.gib() - to_chat(usr, "\red The Geometer of Blood accepts this sacrifice, your objective is now complete.") - else - to_chat(usr, "\red Your target's earthly bonds are too strong. You need more cultists to succeed in this ritual.") - else - if(cultsinrange.len >= 3) - if(H.stat !=2) - if(prob(80)) - to_chat(usr, "\red The Geometer of Blood accepts this sacrifice.") - ticker.mode:grant_runeword(usr) - else - to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") - to_chat(usr, "\red However, this soul was not enough to gain His favor.") - if(isrobot(H)) - H.dust()//To prevent the MMI from remaining - else - H.gib() - else - if(prob(40)) - to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") - ticker.mode:grant_runeword(usr) - else - to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") - to_chat(usr, "\red However, a mere dead body is not enough to satisfy Him.") - if(isrobot(H)) - H.dust()//To prevent the MMI from remaining - else - H.gib() - else - if(H.stat !=2) - to_chat(usr, "\red The victim is still alive, you will need more cultists chanting for the sacrifice to succeed.") - else - if(prob(40)) - to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") - ticker.mode:grant_runeword(usr) - else - to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") - to_chat(usr, "\red However, a mere dead body is not enough to satisfy Him.") - if(isrobot(H)) - H.dust()//To prevent the MMI from remaining - else - H.gib() - else - if(cultsinrange.len >= 3) - if(H.stat !=2) - if(prob(80)) - to_chat(usr, "\red The Geometer of Blood accepts this sacrifice.") - ticker.mode:grant_runeword(usr) - else - to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") - to_chat(usr, "\red However, this soul was not enough to gain His favor.") - if(isrobot(H)) - H.dust()//To prevent the MMI from remaining - else - H.gib() - else - if(prob(40)) - to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") - ticker.mode:grant_runeword(usr) - else - to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") - to_chat(usr, "\red However, a mere dead body is not enough to satisfy Him.") - if(isrobot(H)) - H.dust()//To prevent the MMI from remaining - else - H.gib() - else - if(H.stat !=2) - to_chat(usr, "\red The victim is still alive, you will need more cultists chanting for the sacrifice to succeed.") - else - if(prob(40)) - to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") - ticker.mode:grant_runeword(usr) - else - to_chat(usr, "\red The Geometer of blood accepts this sacrifice.") - to_chat(usr, "\red However, a mere dead body is not enough to satisfy Him.") - if(isrobot(H)) - H.dust()//To prevent the MMI from remaining - else - H.gib() - -/////////////////////////////////////////SIXTEENTH RUNE - -/obj/effect/rune/proc/revealrunesrune() - revealrunes(src) - -/obj/effect/rune/proc/revealrunes(var/obj/W as obj) - var/go=0 - var/rad - var/S=0 - if(istype(W,/obj/effect/rune)) - rad = 6 - go = 1 - if(istype(W,/obj/item/weapon/paper/talisman)) - rad = 4 - go = 1 - if(istype(W,/obj/item/weapon/storage/bible)) - rad = 1 - go = 1 - if(go) - for(var/obj/effect/rune/R in orange(rad,src)) - if(R!=src) - R:visibility=15 - S=1 - if(S) - if(istype(W,/obj/item/weapon/storage/bible)) - to_chat(usr, "\red Arcane markings suddenly glow from underneath a thin layer of dust!") - return - if(istype(W,/obj/effect/rune)) - usr.say("Nikt[pick("'","`")]o barada kla'atu!") - for(var/mob/V in viewers(src)) - V.show_message("\red The rune turns into red dust, reveaing the surrounding runes.", 3) - qdel(src) - return - if(istype(W,/obj/item/weapon/paper/talisman)) - usr.whisper("Nikt[pick("'","`")]o barada kla'atu!") - to_chat(usr, "\red Your talisman turns into red dust, revealing the surrounding runes.") - for(var/mob/V in orange(1,usr.loc)) - if(V!=usr) - V.show_message("\red Red dust emanates from [usr]'s hands for a moment.", 3) - return - return - if(istype(W,/obj/effect/rune)) - return fizzle() - if(istype(W,/obj/item/weapon/paper/talisman)) - call(/obj/effect/rune/proc/fizzle)() - return - -/////////////////////////////////////////SEVENTEENTH RUNE - -/obj/effect/rune/proc/wall() - usr.say("Khari[pick("'","`")]d! Eske'te tannin!") - src.density = !src.density - var/mob/living/user = usr - user.take_organ_damage(2, 0) - if(src.density) - to_chat(usr, "\red Your blood flows into the rune, and you feel that the very space over the rune thickens.") - else - to_chat(usr, "\red Your blood flows into the rune, and you feel as the rune releases its grasp on space.") - return - -/////////////////////////////////////////EIGHTTEENTH RUNE - -/obj/effect/rune/proc/freedom() - var/mob/living/user = usr - var/list/mob/living/carbon/cultists = new - for(var/datum/mind/H in ticker.mode.cult) - if(istype(H.current,/mob/living/carbon)) - cultists+=H.current - var/list/mob/living/carbon/users = new - for(var/mob/living/carbon/C in orange(1,src)) - if(iscultist(C) && !C.stat) - users+=C - if(users.len>=3) - var/mob/living/carbon/cultist = input("Choose the one who you want to free", "Followers of Geometer") as null|anything in (cultists - users) - if(!cultist) - return fizzle() - if(cultist == user) //just to be sure. - return - if(!(cultist.buckled || \ - cultist.handcuffed || \ - istype(cultist.wear_mask, /obj/item/clothing/mask/muzzle) || \ - (istype(cultist.loc, /obj/structure/closet)&&cultist.loc:welded) || \ - (istype(cultist.loc, /obj/structure/closet/secure_closet)&&cultist.loc:locked) || \ - (istype(cultist.loc, /obj/machinery/dna_scannernew)&&cultist.loc:locked) \ - )) - to_chat(user, "\red The [cultist] is already free.") - return - cultist.buckled = null - if(cultist.handcuffed) - cultist.handcuffed.loc = cultist.loc - cultist.handcuffed = null - cultist.update_handcuffed() - if(cultist.legcuffed) - cultist.legcuffed.loc = cultist.loc - cultist.legcuffed = null - cultist.update_inv_legcuffed() - if(istype(cultist.wear_mask, /obj/item/clothing/mask/muzzle)) - cultist.unEquip(cultist.wear_mask) - if(istype(cultist.loc, /obj/structure/closet)&&cultist.loc:welded) - cultist.loc:welded = 0 - if(istype(cultist.loc, /obj/structure/closet/secure_closet)&&cultist.loc:locked) - cultist.loc:locked = 0 - if(istype(cultist.loc, /obj/machinery/dna_scannernew)&&cultist.loc:locked) - cultist.loc:locked = 0 - for(var/mob/living/carbon/C in users) - user.take_overall_damage(15, 0) - C.say("Khari[pick("'","`")]d! Gual'te nikka!") - qdel(src) - return fizzle() - -/////////////////////////////////////////NINETEENTH RUNE - -/obj/effect/rune/proc/cultsummon() - var/mob/living/user = usr - var/list/mob/living/carbon/cultists = new - for(var/datum/mind/H in ticker.mode.cult) - if(istype(H.current,/mob/living/carbon)) - cultists+=H.current - var/list/mob/living/carbon/users = new - for(var/mob/living/carbon/C in orange(1,src)) - if(iscultist(C) && !C.stat) - users+=C - if(users.len>=3) - var/mob/living/carbon/cultist = input("Choose the one who you want to summon", "Followers of Geometer") as null|anything in (cultists - user) - if(!cultist) - return fizzle() - if(cultist == user) //just to be sure. - return - if(cultist.buckled || cultist.handcuffed || (!isturf(cultist.loc) && !istype(cultist.loc, /obj/structure/closet))) - to_chat(user, "\red You cannot summon the [cultist], for his shackles of blood are strong") - return fizzle() - cultist.loc = src.loc - cultist.lying = 1 - cultist.regenerate_icons() - for(var/mob/living/carbon/human/C in orange(1,src)) - if(iscultist(C) && !C.stat) - C.say("N'ath reth sh'yro eth d[pick("'","`")]rekkathnor!") - C.take_overall_damage(25, 0) - user.visible_message("\red Rune disappears with a flash of red light, and in its place now a body lies.", \ - "\red You are blinded by the flash of red light! After you're able to see again, you see that now instead of the rune there's a body.", \ - "\red You hear a pop and smell ozone.") - qdel(src) - return fizzle() - -/////////////////////////////////////////TWENTIETH RUNES - -/obj/effect/rune/proc/deafen() - if(istype(src,/obj/effect/rune)) - var/affected = 0 - for(var/mob/living/carbon/C in range(7,src)) - if(iscultist(C)) - continue - var/obj/item/weapon/nullrod/N = locate() in C - if(N) - continue - C.AdjustEarDeaf(50) - C.show_message("\red The world around you suddenly becomes quiet.", 3) - affected++ - if(prob(1)) - C.disabilities |= DEAF - if(affected) - usr.say("Sti[pick("'","`")] kaliedir!") - to_chat(usr, "\red The world becomes quiet as the deafening rune dissipates into fine dust.") - qdel(src) - else - return fizzle() - else - var/affected = 0 - for(var/mob/living/carbon/C in range(7,usr)) - if(iscultist(C)) - continue - var/obj/item/weapon/nullrod/N = locate() in C - if(N) - continue - C.AdjustEarDeaf(30) - //talismans is weaker. - C.show_message("\red The world around you suddenly becomes quiet.", 3) - affected++ - if(affected) - usr.whisper("Sti[pick("'","`")] kaliedir!") - to_chat(usr, "\red Your talisman turns into gray dust, deafening everyone around.") - for(var/mob/V in orange(1,src)) - if(!(iscultist(V))) - V.show_message("\red Dust flows from [usr]'s hands for a moment, and the world suddenly becomes quiet..", 3) - return - -/obj/effect/rune/proc/blind() - if(istype(src,/obj/effect/rune)) - var/affected = 0 - for(var/mob/living/carbon/C in viewers(src)) - if(iscultist(C)) - continue - var/obj/item/weapon/nullrod/N = locate() in C - if(N) - continue - C.AdjustEyeBlurry(50) - C.AdjustEyeBlind(20) - if(prob(5)) - C.BecomeNearsighted() - if(prob(10)) - C.BecomeBlind() - C.show_message("\red Suddenly you see red flash that blinds you.", 3) - affected++ - if(affected) - usr.say("Sti[pick("'","`")] kaliesin!") - to_chat(usr, "\red The rune flashes, blinding those who not follow the Nar-Sie, and dissipates into fine dust.") - qdel(src) - else - return fizzle() - else - var/affected = 0 - for(var/mob/living/carbon/C in view(2,usr)) - if(iscultist(C)) - continue - var/obj/item/weapon/nullrod/N = locate() in C - if(N) - continue - C.AdjustEyeBlurry(30) - C.AdjustEyeBlind(10) - //talismans is weaker. - affected++ - C.show_message("\red You feel a sharp pain in your eyes, and the world disappears into darkness..", 3) - if(affected) - usr.whisper("Sti[pick("'","`")] kaliesin!") - to_chat(usr, "\red Your talisman turns into gray dust, blinding those who not follow the Nar-Sie.") - return - - -/obj/effect/rune/proc/bloodboil() //cultists need at least one DANGEROUS rune. Even if they're all stealthy. /* - var/list/mob/living/carbon/cultists = new - for(var/datum/mind/H in ticker.mode.cult) - if(istype(H.current,/mob/living/carbon)) - cultists+=H.current +This file contains runes. +Runes are used by the cult to cause many different effects and are paramount to their success. +They are drawn with an arcane tome in blood, and are distinguishable to cultists and normal crew by examining. +Fake runes can be drawn in crayon to fool people. +Runes can either be invoked by one's self or with many different cultists. Each rune has a specific incantation that the cultists will say when invoking it. +To draw a rune, use an arcane tome. */ - var/culcount = 0 //also, wording for it is old wording for obscure rune, which is now hide-see-blood. -// var/list/cultboil = list(cultists-usr) //and for this words are destroy-see-blood. - for(var/mob/living/carbon/C in orange(1,src)) - if(iscultist(C) && !C.stat) - culcount++ - if(culcount>=3) - for(var/mob/living/carbon/M in viewers(usr)) - if(iscultist(M)) - continue - var/obj/item/weapon/nullrod/N = locate() in M - if(N) - continue - cult_log("Blood Boil damaged [key_name(M)].") - M.take_overall_damage(51,51) - to_chat(M, "\red Your blood boils!") - if(prob(5)) - spawn(5) - M.gib() - for(var/obj/effect/rune/R in view(src)) - if(prob(10)) - explosion(R.loc, -1, 0, 1, 5) - for(var/mob/living/carbon/human/C in orange(1,src)) - if(iscultist(C) && !C.stat) - C.say("Dedo ol[pick("'","`")]btoh!") - C.take_overall_damage(15, 0) + +/obj/effect/rune + name = "rune" + var/cultist_name = "basic rune" + desc = "An odd collection of symbols drawn in what seems to be blood." + var/cultist_desc = "a basic rune with no function." //This is shown to cultists who examine the rune in order to determine its true purpose. + anchored = 1 + icon = 'icons/obj/rune.dmi' + icon_state = "1" + var/visibility = 0 + var/view_range = 7 + unacidable = 1 + layer = TURF_LAYER + + var/invocation = "Aiy ele-mayo!" //This is said by cultists when the rune is invoked. + var/req_cultists = 1 //The amount of cultists required around the rune to invoke it. If only 1, any cultist can invoke it. + var/rune_in_use = 0 // Used for some runes, this is for when you want a rune to not be usable when in use. + + var/scribe_delay = 50 //how long the rune takes to create + var/scribe_damage = 0.1 //how much damage you take doing it + + var/allow_excess_invokers = 0 //if we allow excess invokers when being invoked + var/construct_invoke = 1 //if constructs can invoke it + + var/req_keyword = 0 //If the rune requires a keyword - go figure amirite + var/keyword //The actual keyword for the rune + + +/obj/effect/rune/New(loc, set_keyword) + ..() + if(set_keyword) + keyword = set_keyword + check_icon() + var/image/blood = image(loc = src) + blood.override = 1 + for(var/mob/living/silicon/ai/AI in player_list) + AI.client.images += blood + +/obj/effect/rune/examine(mob/user) + ..() + if(iscultist(user) || user.stat == DEAD) //If they're a cultist or a ghost, tell them the effects + to_chat(user, "Name: [cultist_name]") + to_chat(user, "Effects: [capitalize(cultist_desc)]") + to_chat(user, "Required Acolytes: [req_cultists]") + if(req_keyword && keyword) + to_chat(user, "Keyword: [keyword]") + +/obj/effect/rune/attackby(obj/I, mob/user, params) + if(istype(I, /obj/item/weapon/tome) && iscultist(user)) + to_chat(user, "You carefully erase the [lowertext(cultist_name)] rune.") qdel(src) - else - return fizzle() - return - -// WIP rune, I'll wait for Rastaf0 to add limited blood. - -/obj/effect/rune/proc/burningblood() - var/culcount = 0 - for(var/mob/living/carbon/C in orange(1,src)) - if(iscultist(C) && !C.stat) - culcount++ - if(culcount >= 5) - for(var/obj/effect/rune/R in world) - if(R.blood_DNA == src.blood_DNA) - for(var/mob/living/M in orange(2,R)) - M.take_overall_damage(0,15) - if(R.invisibility>M.see_invisible) - to_chat(M, "\red Aargh it burns!") - else - to_chat(M, "\red Rune suddenly ignites, burning you!") - var/turf/T = get_turf(R) - T.hotspot_expose(700,125) - for(var/obj/effect/decal/cleanable/blood/B in world) - if(B.blood_DNA == src.blood_DNA) - for(var/mob/living/M in orange(1,B)) - M.take_overall_damage(0,5) - to_chat(M, "\red Blood suddenly ignites, burning you!") - var/turf/T = get_turf(B) - T.hotspot_expose(700,125) - qdel(B) + return + else if(istype(I, /obj/item/weapon/nullrod)) + if(iscultist(user))//cultist..what are doing..cultist..staph... + user.drop_item() + user.visible_message("[I] suddenly glows with white light, forcing [user] to drop it in pain!", \ + "[I] suddenly glows with a white light that sears your hand, forcing you to drop it!") + return + to_chat(user,"You disrupt the magic of [src] with [I].") qdel(src) - -////////// Rune 24 (counting burningblood, which kinda doesnt work yet.) - -/obj/effect/rune/proc/runestun(var/mob/living/T as mob) - if(istype(src,/obj/effect/rune)) ///When invoked as rune, flash and stun everyone around. - usr.say("Fuu ma[pick("'","`")]jin!") - for(var/mob/living/L in viewers(src)) - - if(iscarbon(L)) - var/mob/living/carbon/C = L - C.flash_eyes() - if(C.stuttering < 1 && (!(HULK in C.mutations))) - C.stuttering = 1 - C.Weaken(1) - C.Stun(1) - C.show_message("\red The rune explodes in a bright flash.", 3) - - else if(issilicon(L)) - var/mob/living/silicon/S = L - S.Weaken(5) - S.show_message("\red BZZZT... The rune has exploded in a bright flash.", 3) - qdel(src) - else ///When invoked as talisman, stun and mute the target mob. - usr.say("Dream sign ''Evil sealing talisman'[pick("'","`")]!") - var/obj/item/weapon/nullrod/N = locate() in T - if(N) - for(var/mob/O in viewers(T, null)) - O.show_message(text("[] invokes a talisman at [], but they are unaffected!", usr, T), 1) - else - for(var/mob/O in viewers(T, null)) - O.show_message(text("[] invokes a talisman at []", usr, T), 1) - - if(issilicon(T)) - T.Weaken(10) - - else if(iscarbon(T)) - var/mob/living/carbon/C = T - C.flash_eyes() - if(!(HULK in C.mutations)) - C.AdjustSilence(15) - C.Weaken(10) - C.Stun(10) return -/////////////////////////////////////////TWENTY-FIFTH RUNE - -/obj/effect/rune/proc/armor() - var/mob/living/carbon/human/user = usr - if(istype(src,/obj/effect/rune)) - usr.say("N'ath reth sh'yro eth d[pick("'","`")]raggathnor!") +/obj/effect/rune/attack_hand(mob/living/user) + if(!iscultist(user)) + to_chat(user, "You aren't able to understand the words of [src].") + return + var/list/invokers = can_invoke(user) + if(invokers.len >= req_cultists) + invoke(invokers) else - usr.whisper("N'ath reth sh'yro eth d[pick("'","`")]raggathnor!") - usr.visible_message("\red The rune disappears with a flash of red light, and a set of armor appears on [usr]...", \ - "\red You are blinded by the flash of red light! After you're able to see again, you see that you are now wearing a set of armor.") + fail_invoke(user) - user.equip_to_slot_or_del(new /obj/item/clothing/suit/hooded/cultrobes/alt(user), slot_wear_suit) - user.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult(user), slot_shoes) - user.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/cultpack(user), slot_back) - //the above update their overlay icons cache but do not call update_icons() - //the below calls update_icons() at the end, which will update overlay icons by using the (now updated) cache - user.put_in_hands(new /obj/item/weapon/melee/cultblade(user)) //put in hands or on floor +/obj/effect/rune/attack_animal(mob/living/simple_animal/M) + if(istype(M, /mob/living/simple_animal/shade) || istype(M, /mob/living/simple_animal/hostile/construct)) + if(construct_invoke || !iscultist(M)) //if you're not a cult construct we want the normal fail message + attack_hand(M) + else + to_chat(M, "You are unable to invoke the rune!") + +/obj/effect/rune/proc/talismanhide() //for talisman of revealing/hiding + visible_message("[src] fades away.") + invisibility = INVISIBILITY_OBSERVER + alpha = 100 //To help ghosts distinguish hidden runes + +/obj/effect/rune/proc/talismanreveal() //for talisman of revealing/hiding + invisibility = 0 + visible_message("[src] suddenly appears!") + alpha = initial(alpha) + +/obj/effect/rune/proc/talismanfake() //for rune disguising + var/runenum = pick(1,2,3,4,5,6) + visible_message("[src] takes on a waxy apperance!") + icon = 'icons/effects/crayondecal.dmi' + icon_state = "rune[runenum]" + color = rgb(255, 0, 0) + +/* +There are a few different procs each rune runs through when a cultist activates it. +can_invoke() is called when a cultist activates the rune with an empty hand. If there are multiple cultists, this rune determines if the required amount is nearby. +invoke() is the rune's actual effects. +fail_invoke() is called when the rune fails, via not enough people around or otherwise. Typically this just has a generic 'fizzle' effect. +structure_check() searches for nearby cultist structures required for the invocation. Proper structures are pylons, forges, archives, and altars. +*/ + +/obj/effect/rune/proc/can_invoke(var/mob/living/user) + //This proc determines if the rune can be invoked at the time. If there are multiple required cultists, it will find all nearby cultists. + var/list/invokers = list() //people eligible to invoke the rune + var/list/chanters = list() //people who will actually chant the rune when passed to invoke() + if(user) + chanters |= user + invokers |= user + if(req_cultists > 1 || allow_excess_invokers) + for(var/mob/living/L in range(1, src)) + if(iscultist(L)) + if(L == user) + continue + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(!H.can_speak()) + continue + if(L.stat) + continue + invokers |= L + if(invokers.len >= req_cultists) + if(allow_excess_invokers) + chanters |= invokers + else + invokers -= user + shuffle(invokers) + for(var/i in 0 to req_cultists) + var/L = pick_n_take(invokers) + chanters |= L + return chanters + +/obj/effect/rune/proc/invoke(var/list/invokers) + //This proc contains the effects of the rune as well as things that happen afterwards. If you want it to spawn an object and then delete itself, have both here. + if(invocation) + for(var/M in invokers) + var/mob/living/L = M + L.say(invocation) + L.changeNext_move(CLICK_CD_MELEE)//THIS IS WHY WE CAN'T HAVE NICE THINGS + do_invoke_glow() + +/obj/effect/rune/proc/do_invoke_glow() + var/oldtransform = transform + spawn(0) //animate is a delay, we want to avoid being delayed + animate(src, transform = matrix()*2, alpha = 0, time = 5) //fade out + animate(transform = oldtransform, alpha = 255, time = 0) + +/obj/effect/rune/proc/fail_invoke(var/mob/living/user) + //This proc contains the effects of a rune if it is not invoked correctly, through either invalid wording or not enough cultists. By default, it's just a basic fizzle. + visible_message("The markings pulse with a small flash of red light, then fall dark.") + spawn(0) //animate is a delay, we want to avoid being delayed + animate(src, color = rgb(255, 0, 0), time = 0) + animate(src, color = initial(color), time = 5) + +//Malformed Rune: This forms if a rune is not drawn correctly. Invoking it does nothing but hurt the user. +/obj/effect/rune/malformed + cultist_name = "malformed rune" + cultist_desc = "a senseless rune written in gibberish. No good can come from invoking this." + invocation = "Ra'sha yoka!" + +/obj/effect/rune/malformed/invoke(var/list/invokers) + ..() + for(var/M in invokers) + var/mob/living/L = M + to_chat(M, "You feel your life force draining. [ticker.mode.cultdat.entity_title3] is displeased.") + L.apply_damage(30, BRUTE) qdel(src) + +/mob/proc/null_rod_check() //The null rod, if equipped, will protect the holder from the effects of most runes + var/obj/item/weapon/nullrod/N = locate() in src + if(N) + return N + return 0 + +//Rite of Binding: A paper on top of the rune to a talisman. +/obj/effect/rune/imbue + cultist_name = "Rite of Binding" + cultist_desc = "transforms paper into powerful magic talismans." + invocation = "H'drak v'loso, mir'kanas verbot!" + icon_state = "3" + +/obj/effect/rune/imbue/invoke(var/list/invokers) + var/mob/living/user = invokers[1] //the first invoker is always the user + var/turf/T = get_turf(src) + var/list/papers_on_rune = list() + var/entered_talisman_name + var/obj/item/weapon/paper/talisman/talisman_type + var/list/possible_talismans = list() + for(var/obj/item/weapon/paper/P in T) + if(!P.info) + papers_on_rune.Add(P) + if(!papers_on_rune.len) + to_chat(user, "There must be a blank paper on top of [src]!") + fail_invoke() + log_game("Talisman Creation rune failed - no blank papers on rune") + return + if(rune_in_use) + to_chat(user, "[src] can only support one ritual at a time!") + fail_invoke() + log_game("Talisman Creation rune failed - already in use") + return + var/obj/item/weapon/paper/paper_to_imbue = pick(papers_on_rune) + for(var/I in subtypesof(/obj/item/weapon/paper/talisman) - /obj/item/weapon/paper/talisman/malformed - /obj/item/weapon/paper/talisman/supply - /obj/item/weapon/paper/talisman/supply/weak) + var/obj/item/weapon/paper/talisman/J = I + var/talisman_cult_name = initial(J.cultist_name) + if(talisman_cult_name) + possible_talismans[talisman_cult_name] = J //This is to allow the menu to let cultists select talismans by name + entered_talisman_name = input(user, "Choose a talisman to imbue.", "Talisman Choices") as null|anything in possible_talismans + talisman_type = possible_talismans[entered_talisman_name] + if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated() || rune_in_use || !talisman_type) + return + ..() + visible_message("Dark power begins to channel into the paper!.") + rune_in_use = 1 + if(!do_after(user, 100, target = get_turf(user))) + rune_in_use = 0 + return + new talisman_type(get_turf(src)) + visible_message("[src] glows with power, and bloody images form themselves on [paper_to_imbue].") + qdel(paper_to_imbue) + rune_in_use = 0 + +var/list/teleport_runes = list() +/obj/effect/rune/teleport + cultist_name = "Teleport" + cultist_desc = "warps everything above it to another chosen teleport rune." + invocation = "Sas'so c'arta forbici!" + icon_state = "2" + req_keyword = 1 + var/listkey + +/obj/effect/rune/teleport/New(loc, set_keyword) + ..() + var/area/A = get_area(src) + var/locname = initial(A.name) + listkey = set_keyword ? "[set_keyword] [locname]":"[locname]" + teleport_runes += src + +/obj/effect/rune/teleport/Destroy() + teleport_runes -= src + return ..() + +/obj/effect/rune/teleport/invoke(var/list/invokers) + var/mob/living/user = invokers[1] //the first invoker is always the user + var/list/potential_runes = list() + var/list/teleportnames = list() + var/list/duplicaterunecount = list() + for(var/R in teleport_runes) + var/obj/effect/rune/teleport/T = R + var/resultkey = T.listkey + if(resultkey in teleportnames) + duplicaterunecount[resultkey]++ + resultkey = "[resultkey] ([duplicaterunecount[resultkey]])" + else + teleportnames.Add(resultkey) + duplicaterunecount[resultkey] = 1 + if(T != src && is_level_reachable(T.z)) + potential_runes[resultkey] = T + + if(!potential_runes.len) + to_chat(user, "There are no valid runes to teleport to!") + log_game("Teleport rune failed - no other teleport runes") + fail_invoke() + return + + if(!is_level_reachable(user.z)) + to_chat(user, "You are not in the right dimension!") + log_game("Teleport rune failed - user in away mission") + fail_invoke() + return + + var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked + var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to? + if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated() || !actual_selected_rune) + fail_invoke() + return + + var/turf/T = get_turf(src) + var/movedsomething = 0 + var/moveuserlater = 0 + for(var/atom/movable/A in T) + if(A == user) + moveuserlater = 1 + movedsomething = 1 + continue + if(!A.anchored) + movedsomething = 1 + A.forceMove(get_turf(actual_selected_rune)) + if(movedsomething) + ..() + visible_message("There is a sharp crack of inrushing air, and everything above the rune disappears!") + to_chat(user, "You[moveuserlater ? "r vision blurs, and you suddenly appear somewhere else":" send everything above the rune away"].") + if(moveuserlater) + user.forceMove(get_turf(actual_selected_rune)) + else + fail_invoke() + + +//Rite of Enlightenment: Converts a normal crewmember to the cult. Faster for every cultist nearby. +/obj/effect/rune/convert + cultist_name = "Rite of Enlightenment" + cultist_desc = "converts a normal crewmember on top of it to the cult. Does not work on loyalty-implanted crew." + invocation = "Mah'weyh pleggh at e'ntrath!" + icon_state = "3" + req_cultists = 2 + +/obj/effect/rune/convert/do_invoke_glow() return + +/obj/effect/rune/convert/invoke(var/list/invokers) + var/list/convertees = list() + var/turf/T = get_turf(src) + for(var/mob/living/M in T.contents) + if(!iscultist(M) && !isloyal(M)) + convertees.Add(M) + if(!convertees.len) + fail_invoke() + log_game("Convert rune failed - no eligible convertees") + return + var/mob/living/new_cultist = pick(convertees) + if(!is_convertable_to_cult(new_cultist.mind) || new_cultist.null_rod_check()) + for(var/M in invokers) + to_chat(M, "Something is shielding [new_cultist]'s mind!") + if(is_sacrifice_target(new_cultist.mind)) + to_chat(M, "\"I desire this one for myself. SACRIFICE THEM!\"") + fail_invoke() + log_game("Convert rune failed - convertee could not be converted") + return + ..() + new_cultist.visible_message("[new_cultist] writhes in pain as the markings below them glow a bloody red!", \ + "AAAAAAAAAAAAAA-") + ticker.mode.add_cultist(new_cultist.mind, 1) + new /obj/item/weapon/tome(get_turf(src)) + new_cultist.mind.special_role = "Cultist" + to_chat(new_cultist, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \ + and something evil takes root.") + to_chat(new_cultist, "Assist your new compatriots in their dark dealings. Your goal is theirs, and theirs is yours. You serve [ticker.mode.cultdat.entity_title3] above all else. Bring it back.\ + ") + +//Rite of Tribute: Sacrifices a crew member to Nar-Sie. Places them into a soul shard if they're in their body. +/obj/effect/rune/sacrifice + cultist_name = "Rite of Tribute" + cultist_desc = "sacrifices a crew member to your god. May place them into a soul shard if their spirit remains in their body." + icon_state = "3" + allow_excess_invokers = 1 + invocation = "Barhah hra zar'garis!" + rune_in_use = 0 + +/obj/effect/rune/sacrifice/New() + ..() + cultist_desc = "sacrifices a crew member to [ticker.mode.cultdat.entity_title3]. May place them into a soul shard if their spirit remains in their body." + +/obj/effect/rune/sacrifice/invoke(var/list/invokers) + if(rune_in_use) + return + rune_in_use = 1 + var/mob/living/user = invokers[1] //the first invoker is always the user + var/turf/T = get_turf(src) + var/list/possible_targets = list() + for(var/mob/living/M in T.contents) + if(M.mind) + if(M.mind in sacrificed) + continue + if(!iscultist(M)) + possible_targets.Add(M) + var/mob/offering + if(possible_targets.len > 1) //If there's more than one target, allow choice + offering = input(user, "Choose an offering to sacrifice.", "Unholy Tribute") as null|anything in possible_targets + if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated()) + return + else if(possible_targets.len) //Otherwise, if there's a target at all, pick the only one + offering = possible_targets[possible_targets.len] + if(!offering) + rune_in_use = 0 + return + if(((ishuman(offering) || isrobot(offering)) && offering.stat != DEAD) || is_sacrifice_target(offering.mind)) //Requires three people to sacrifice living targets + if(invokers.len < 3) + for(var/M in invokers) + to_chat(M, "[offering] is too greatly linked to the world! You need three acolytes!") + fail_invoke() + log_game("Sacrifice rune failed - not enough acolytes and target is living") + rune_in_use = 0 + return + visible_message("[src] pulses blood red!") + color = rgb(126, 23, 23) + ..() + sac(invokers, offering) + color = initial(color) + +/obj/effect/rune/sacrifice/proc/sac(var/list/invokers, mob/living/T) + var/sacrifice_fulfilled + if(T) + if(istype(T, /mob/living/simple_animal/pet/corgi)) + for(var/M in invokers) + var/mob/living/L = M + to_chat(L, "\"Even I have standards, such as they are!\"") + if(L.reagents) + L.reagents.add_reagent("hell_water", 2) + if(T.mind) + sacrificed.Add(T.mind) + if(is_sacrifice_target(T.mind)) + sacrifice_fulfilled = 1 + new /obj/effect/overlay/temp/cult/sac(loc) + for(var/M in invokers) + if(sacrifice_fulfilled) + to_chat(M, "\"Yes! This is the one I desire! You have done well.\"") + else + if(ishuman(T) || isrobot(T)) + to_chat(M, "\"I accept this sacrifice.\"") + else + to_chat(M, "\"I accept this meager sacrifice.\"") + if(T.mind) + var/obj/item/device/soulstone/stone = new /obj/item/device/soulstone(get_turf(src)) + stone.invisibility = INVISIBILITY_MAXIMUM //so it's not picked up during transfer_soul() + if(!stone.transfer_soul("VICTIM", T, usr)) //If it cannot be added + qdel(stone) + if(stone) + stone.invisibility = 0 + if(!T) + rune_in_use = 0 + return + if(isrobot(T)) + playsound(T, 'sound/effects/EMPulse.ogg', 100, 1) + T.dust() //To prevent the MMI from remaining + else + playsound(T, 'sound/magic/Disintegrate.ogg', 100, 1) + T.gib() + rune_in_use = 0 + +//Ritual of Dimensional Rending: Calls forth the avatar of Nar-Sie upon the station. +/obj/effect/rune/narsie + cultist_name = "Tear Reality (God)" + cultist_desc = "tears apart dimensional barriers, calling forth your god. Requires 9 invokers." + invocation = "TOK-LYR RQA-NAP G'OLT-ULOFT!!" + req_cultists = 9 + icon = 'icons/effects/96x96.dmi' + color = rgb(125,23,23) + icon_state = "rune_large" + pixel_x = -32 //So the big ol' 96x96 sprite shows up right + pixel_y = -32 + mouse_opacity = 1 //we're huge and easy to click + scribe_delay = 450 //how long the rune takes to create + scribe_damage = 40.1 //how much damage you take doing it + var/used + +/obj/effect/rune/narsie/New() + ..() + cultist_name = "Summon [ticker.mode.cultdat.entity_name]" + cultist_desc = "tears apart dimensional barriers, calling forth [ticker.mode.cultdat.entity_title3]. Requires 9 invokers." + + +/obj/effect/rune/narsie/check_icon() + return + +/obj/effect/rune/narsie/talismanhide() //can't hide this, and you wouldn't want to + return + +/obj/effect/rune/narsie/invoke(var/list/invokers) + if(used) + return + var/mob/living/user = invokers[1] + if(istype(ticker.mode.name, "cult")) + var/datum/game_mode/cult/cult_mode = ticker.mode + if(!is_station_level(user.z)) + message_admins("[key_name_admin(user)] tried to summon Nar-Sie off station") + for(var/M in invokers) + var/mob/living/L = M + to_chat(L, "\"YOUR SOUL BURNS WITH YOUR ARROGANCE!!!\"") + if(L.reagents) + L.reagents.add_reagent("hell_water", 10) + L.Weaken(7) + L.Stun(7) + fail_invoke() + log_game("Summon Nar-Sie rune failed - off station Z level") + return + if(!cult_mode.eldergod) + for(var/M in invokers) + to_chat(M, "[ticker.mode.cultdat.entity_name] is already on this plane!") + log_game("Summon Nar-Sie rune failed - already summoned") + return + //BEGIN THE SUMMONING + used = 1 + color = rgb(255, 0, 0) + ..() + world << 'sound/effects/dimensional_rend.ogg' + to_chat(world, "The veil... is... TORN!!!--") + icon_state = "rune_large_distorted" + var/turf/T = get_turf(src) + sleep(40) + new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed + cult_mode.eldergod = 0 + +/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal. + if((istype(I, /obj/item/weapon/tome) && iscultist(user))) + user.visible_message("[user.name] begins erasing the [src]...", "You begin erasing the [src]...") + if(do_after(user, 50, target = src)) //Prevents accidental erasures. + log_game("Summon Narsie rune erased by [key_name(user)] with a tome") + message_admins("[key_name_admin(user)] erased a Narsie rune with a tome") + ..() + return + else + if(istype(I, /obj/item/weapon/nullrod)) //Begone foul magiks. You cannot hinder me. + log_game("Summon Narsie rune erased by [key_name(user)] using a null rod") + message_admins("[key_name_admin(user)] erased a Narsie rune with a null rod") + ..() + return + + + +/obj/effect/rune/slaughter + cultist_name = "Call Forth The Slaughter (Demons)" + cultist_desc = "Calls forth the doom of a eldrtich being. Three slaughter demons will appear to wreak havoc on the station." + invocation = null + req_cultists = 9 + color = rgb(125,23,23) + scribe_delay = 450 + scribe_damage = 40.1 //how much damage you take doing it + icon = 'icons/effects/96x96.dmi' + icon_state = "rune_large" + pixel_x = -32 + pixel_y = -32 + + var/used = 0 + +/obj/effect/rune/slaughter/check_icon() + return + +/obj/effect/rune/slaughter/talismanhide() //can't hide this, and you wouldn't want to + return + +/obj/effect/rune/slaughter/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal. + if((istype(I, /obj/item/weapon/tome) && iscultist(user))) + user.visible_message("[user.name] begins erasing the [src]...", "You begin erasing the [src]...") + if(do_after(user, 50, target = src)) //Prevents accidental erasures. + log_game("Summon demon rune erased by [key_name(user)] with a tome") + message_admins("[key_name_admin(user)] erased a demon rune with a tome") + ..() + return + else + if(istype(I, /obj/item/weapon/nullrod)) //Begone foul magiks. You cannot hinder me. + log_game("Summon demon rune erased by [key_name(user)] using a null rod") + message_admins("[key_name_admin(user)] erased a demon rune with a null rod") + ..() + return + + +/obj/effect/rune/slaughter/invoke(var/list/invokers) + if(used) + return + var/mob/living/user = invokers[1] + if(istype(ticker.mode.name, "cult")) + var/datum/game_mode/cult/cult_mode = ticker.mode + if(!(CULT_SLAUGHTER in cult_mode.objectives)) + message_admins("[key_name_admin(user)] tried to summon demons when the objective was wrong") + for(var/M in invokers) + var/mob/living/L = M + to_chat(L, "\"YOUR SOUL BURNS WITH YOUR ARROGANCE!!!\"") + if(L.reagents) + L.reagents.add_reagent("hell_water", 10) + L.Weaken(7) + L.Stun(7) + fail_invoke() + log_game("Summon Demons rune failed - improper objective") + return + if(!is_station_level(user.z)) + message_admins("[key_name_admin(user)] tried to summon demons off station") + for(var/M in invokers) + var/mob/living/L = M + to_chat(L, "\"YOUR SOUL BURNS WITH YOUR ARROGANCE!!!\"") + if(L.reagents) + L.reagents.add_reagent("hell_water", 10) + L.Weaken(7) + L.Stun(7) + fail_invoke() + log_game("Summon demons rune failed - off station Z level") + return + if(cult_mode.demons_summoned) + for(var/M in invokers) + to_chat(M, "Demons are already on this plane!") + log_game("Summon Demons rune failed - already summoned") + return + //BEGIN THE SLAUGHTER + used = 1 + for(var/mob/living/M in range(1,src)) + if(iscultist(M)) + M.say("TOK-LYR RQA-NAP SHA-NEX!!") + world << 'sound/effects/dimensional_rend.ogg' + to_chat(world, "A hellish cacaphony bombards from all around as something awful tears through the world...") + icon_state = "rune_large_distorted" + sleep(55) + to_chat(world, "\"LIBREATE TE EX INFERIS!\"")//Fethas note:I COULDN'T HELP IT OKAY?! + visible_message("[src] melts away into blood, and three horrific figures emerge from within!") + var/turf/T = get_turf(src) + new /mob/living/simple_animal/slaughter/cult(T) + new /mob/living/simple_animal/slaughter/cult(T, pick(NORTH, EAST, SOUTH, WEST)) + new /mob/living/simple_animal/slaughter/cult(T, pick(NORTHEAST, SOUTHEAST, NORTHWEST, SOUTHWEST)) + cult_mode.demons_summoned = 1 + shuttle_master.emergency.request(null, 0.5,null) + cult_mode.third_phase() + qdel(src) + + +//Rite of Resurrection: Requires two corpses. Revives one and gibs the other. +/obj/effect/rune/raise_dead + cultist_name = "Rite of Resurrection" + cultist_desc = "requires two corpses, one on the rune and one adjacent to the rune. The one on the rune is brought to life, the other is turned to ash." + invocation = null //Depends on the name of the user - see below + icon_state = "1" + +/obj/effect/rune/raise_dead/invoke(var/list/invokers) + var/turf/T = get_turf(src) + var/mob/living/mob_to_sacrifice + var/mob/living/mob_to_revive + var/list/potential_sacrifice_mobs = list() + var/list/potential_revive_mobs = list() + var/mob/living/user = invokers[1] + if(rune_in_use) + return + for(var/mob/living/M in orange(1,src)) + if(M.stat == DEAD && !iscultist(M)) + potential_sacrifice_mobs.Add(M) + if(!potential_sacrifice_mobs.len) + to_chat(user, "There are no eligible sacrifices nearby!") + log_game("Raise Dead rune failed - no catalyst corpse") + return + mob_to_sacrifice = input(user, "Choose a corpse to sacrifice.", "Corpse to Sacrifice") as null|anything in potential_sacrifice_mobs + if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated() || !mob_to_revive || !mob_to_sacrifice || rune_in_use) + return + for(var/mob/living/M in T.contents) + if(M.stat == DEAD) + potential_revive_mobs.Add(M) + if(!potential_revive_mobs.len) + to_chat(user, "There is no eligible revival target on the rune!") + log_game("Raise Dead rune failed - no corpse to revived") + return + mob_to_revive = input(user, "Choose a corpse to revive.", "Corpse to Revive") as null|anything in potential_revive_mobs + if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated() || rune_in_use) + return + if(!in_range(mob_to_sacrifice,src)) + to_chat(user, "The sacrificial target has been moved!") + fail_invoke() + log_game("Raise Dead rune failed - catalyst corpse moved") + return + if(!(mob_to_revive in T.contents)) + to_chat(user, "The corpse to revive has been moved!") + fail_invoke() + log_game("Raise Dead rune failed - revival target moved") + return + if(mob_to_sacrifice.stat != DEAD) + to_chat(user, "The sacrificial target must be dead!") + fail_invoke() + log_game("Raise Dead rune failed - catalyst corpse is not dead") + return + rune_in_use = 1 + if(user.name == "Herbert West") + user.say("To life, to life, I bring them!") + else + user.say("Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!") + ..() + mob_to_sacrifice.visible_message("[mob_to_sacrifice]'s body rises into the air, connected to [mob_to_revive] by a glowing tendril!") + mob_to_revive.Beam(mob_to_sacrifice,icon_state="sendbeam",icon='icons/effects/effects.dmi',time=20) + sleep(20) + if(!mob_to_sacrifice || !in_range(mob_to_sacrifice, src)) + mob_to_sacrifice.visible_message("[mob_to_sacrifice] disintegrates into a pile of bones") + return + mob_to_sacrifice.dust() + if(!mob_to_revive || mob_to_revive.stat != DEAD) + visible_message("The glowing tendril snaps against the rune with a shocking crack.") + rune_in_use = 0 + return + mob_to_revive.revive() //This does remove disabilities and such, but the rune might actually see some use because of it! + to_chat(mob_to_revive, "\"PASNAR SAVRAE YAM'TOTH. Arise.\"") + mob_to_revive.visible_message("[mob_to_revive] draws in a huge breath, red light shining from their eyes.", \ + "You awaken suddenly from the void. You're alive!") + rune_in_use = 0 + + +/obj/effect/rune/raise_dead/fail_invoke() + ..() + for(var/mob/living/M in range(1,src)) + if(M.stat == DEAD) + M.visible_message("[M] twitches.") + + +//Rite of Disruption: Emits an EMP blast. +/obj/effect/rune/emp + cultist_name = "Rite of Disruption" + cultist_desc = "emits a large electromagnetic pulse, increasing in size for each cultist invoking it, hindering electronics and disabling silicons." + invocation = "Ta'gh fara'qha fel d'amar det!" + icon_state = "5" + allow_excess_invokers = 1 + +/obj/effect/rune/emp/invoke(var/list/invokers) + var/turf/E = get_turf(src) + ..() + visible_message("[src] glows blue for a moment before vanishing.") + switch(invokers.len) + if(1 to 2) + playsound(E, 'sound/items/Welder2.ogg', 25, 1) + for(var/M in invokers) + to_chat(M, "You feel a minute vibration pass through you...") + if(3 to 6) + playsound(E, 'sound/effects/EMPulse.ogg', 50, 1) + for(var/M in invokers) + to_chat(M, "Your hair stands on end as a shockwave eminates from the rune!") + if(7 to INFINITY) + playsound(E, 'sound/effects/EMPulse.ogg', 100, 1) + for(var/M in invokers) + var/mob/living/L = M + to_chat(L, "You chant in unison and a colossal burst of energy knocks you backward!") + L.Weaken(2) + qdel(src) //delete before pulsing because it's a delay reee + empulse(E, 9*invokers.len, 12*invokers.len) // Scales now, from a single room to most of the station depending on # of chanters + +//Rite of Astral Communion: Separates one's spirit from their body. They will take damage while it is active. +/obj/effect/rune/astral + cultist_name = "Astral Communion" + cultist_desc = "severs the link between one's spirit and body. This effect is taxing and one's physical body will take damage while this is active." + invocation = "Fwe'sh mah erl nyag r'ya!" + icon_state = "6" + rune_in_use = 0 //One at a time, please! + construct_invoke = 0 + var/mob/living/affecting = null + +/obj/effect/rune/astral/examine(mob/user) + ..() + if(affecting) + to_chat(user, "A translucent field encases [user] above the rune!") + +/obj/effect/rune/astral/can_invoke(mob/living/user) + if(rune_in_use) + to_chat(user, "[src] cannot support more than one body!") + log_game("Astral Communion rune failed - more than one user") + return list() + var/turf/T = get_turf(src) + if(!user in T.contents) + to_chat(user, "You must be standing on top of [src]!") + log_game("Astral Communion rune failed - user not standing on rune") + return list() + return ..() + +/obj/effect/rune/astral/invoke(var/list/invokers) + var/mob/living/user = invokers[1] + ..() + var/turf/T = get_turf(src) + rune_in_use = 1 + affecting = user + user.color = "#7e1717" + user.visible_message("[user] freezes statue-still, glowing an unearthly red.", \ + "You see what lies beyond. All is revealed. While this is a wondrous experience, your physical form will waste away in this state. Hurry...") + user.ghostize(1) + while(user) + if(!affecting) + visible_message("[src] pulses gently before falling dark.") + affecting = null //In case it's assigned to a number or something + rune_in_use = 0 + return + affecting.apply_damage(1, BRUTE) + if(!(user in T.contents)) + user.visible_message("A spectral tendril wraps around [user] and pulls them back to the rune!") + Beam(user,icon_state="drainbeam",icon='icons/effects/effects.dmi',time=2) + user.forceMove(get_turf(src)) //NO ESCAPE :^) + if(user.key) + user.visible_message("[user] slowly relaxes, the glow around them dimming.", \ + "You are re-united with your physical form. [src] releases its hold over you.") + user.color = initial(user.color) + user.Weaken(3) + rune_in_use = 0 + affecting = null + user.update_sight() + return + if(user.stat == UNCONSCIOUS) + if(prob(10)) + var/mob/dead/observer/G = user.get_ghost() + if(G) + to_chat(G, "You feel the link between you and your body weakening... you must hurry!") + if(user.stat == DEAD) + user.color = initial(user.color) + rune_in_use = 0 + affecting = null + var/mob/dead/observer/G = user.get_ghost() + if(G) + to_chat(G, "You suddenly feel your physical form pass on. [src]'s exertion has killed you!") + return + sleep(10) + rune_in_use = 0 + + +//Rite of the Corporeal Shield: When invoked, becomes solid and cannot be passed. Invoke again to undo. +/obj/effect/rune/wall + cultist_name = "Rite of the Corporeal Shield" + cultist_desc = "when invoked, makes an invisible wall to block passage. Can be invoked again to reverse this." + invocation = "Khari'd! Eske'te tannin!" + icon_state = "1" + +/obj/effect/rune/wall/examine(mob/user) + ..() + if(density) + to_chat(user, "There is a barely perceptible shimmering of the air above [src].") + +/obj/effect/rune/wall/invoke(var/list/invokers) + var/mob/living/user = invokers[1] + ..() + density = !density + user.visible_message("[user] places their hands on [src], and [density ? "the air above it begins to shimmer" : "the shimmer above it fades"].", \ + "You channel your life energy into [src], [density ? "preventing" : "allowing"] passage above it.") + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.apply_damage(2, BRUTE, pick("l_arm", "r_arm")) + + +//Rite of Joined Souls: Summons a single cultist. +/obj/effect/rune/summon + cultist_name = "Rite of Joined Souls" + cultist_desc = "summons a single cultist to the rune. Requires 2 invokers." + invocation = "N'ath reth sh'yro eth d'rekkathnor!" + req_cultists = 2 + allow_excess_invokers = 1 + icon_state = "5" + +/obj/effect/rune/summon/invoke(var/list/invokers) + var/mob/living/user = invokers[1] + var/list/cultists = list() + for(var/datum/mind/M in ticker.mode.cult) + if(!(M.current in invokers) && M.current.stat != DEAD) + cultists |= M.current + var/mob/living/cultist_to_summon = input(user, "Who do you wish to call to [src]?", "Followers of [ticker.mode.cultdat.entity_title3]") as null|anything in cultists + if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated()) + return + if(!cultist_to_summon) + to_chat(user, "You require a summoning target!") + fail_invoke() + log_game("Summon Cultist rune failed - no target") + return + if(!iscultist(cultist_to_summon)) + to_chat(user, "[cultist_to_summon] is not a follower of [ticker.mode.cultdat.entity_title3]!") + fail_invoke() + log_game("Summon Cultist rune failed - no target") + return + if(!is_level_reachable(cultist_to_summon.z)) + to_chat(user, "[cultist_to_summon] is not in our dimension!") + fail_invoke() + log_game("Summon Cultist rune failed - target in away mission") + return + cultist_to_summon.visible_message("[cultist_to_summon] suddenly disappears in a flash of red light!", \ + "Overwhelming vertigo consumes you as you are hurled through the air!") + ..() + visible_message("A foggy shape materializes atop [src] and solidifes into [cultist_to_summon]!") + user.apply_damage(10, BRUTE, "head") + cultist_to_summon.forceMove(get_turf(src)) + qdel(src) + +//Rite of Boiling Blood: Deals extremely high amounts of damage to non-cultists nearby +/obj/effect/rune/blood_boil + cultist_name = "Boil Blood" + cultist_desc = "boils the blood of non-believers who can see the rune, dealing extreme amounts of damage. Requires 3 invokers." + invocation = "Dedo ol'btoh!" + icon_state = "4" + construct_invoke = 0 + req_cultists = 3 + +/obj/effect/rune/blood_boil/do_invoke_glow() + return + +/obj/effect/rune/blood_boil/invoke(var/list/invokers) + ..() + var/turf/T = get_turf(src) + visible_message("[src] briefly bubbles before exploding!") + for(var/mob/living/carbon/C in viewers(T)) + if(!iscultist(C)) + var/obj/item/weapon/nullrod/N = C.null_rod_check() + if(N) + to_chat(C, "\The [N] suddenly burns hotly before returning to normal!") + continue + to_chat(C, "Your blood boils in your veins!") + C.take_overall_damage(45,45) + C.Stun(7) + for(var/M in invokers) + var/mob/living/L = M + L.apply_damage(15, BRUTE, pick("l_arm", "r_arm")) + to_chat(L,"[src] saps your strength!") + qdel(src) + explosion(T, -1, 0, 1, 5) + +//Deals brute damage to all targets on the rune and heals the invoker for each target drained. +/obj/effect/rune/leeching + cultist_name = "Drain Life" + cultist_desc = "drains the life of all targets on the rune, restoring life to the user." + invocation = "Yu'gular faras desdae. Umathar uf'kal thenar!" + icon_state = "3" + +/obj/effect/rune/leeching/can_invoke(mob/living/user) + if(world.time <= user.next_move) + return list() + var/turf/T = get_turf(src) + var/list/potential_targets = list() + for(var/mob/living/carbon/M in T.contents - user) + if(M.stat != DEAD) + potential_targets += M + if(!potential_targets.len) + to_chat(user, "There must be at least one valid target on the rune!") + log_game("Leeching rune failed - no valid targets") + return list() + return ..() + +/obj/effect/rune/leeching/invoke(var/list/invokers) + var/mob/living/user = invokers[1] + user.changeNext_move(CLICK_CD_MELEE) + ..() + var/turf/T = get_turf(src) + for(var/mob/living/carbon/M in T.contents - user) + if(M.stat != DEAD) + var/drained_amount = rand(10,20) + M.apply_damage(drained_amount, BRUTE, "chest") + user.adjustBruteLoss(-drained_amount) + to_chat(M, "You feel extremely weak.") + user.Beam(T,icon_state="drainbeam",icon='icons/effects/effects.dmi',time=5) + user.visible_message("Blood flows from the rune into [user]!", \ + "Blood flows into you, healing your wounds and revitalizing your spirit.") + + +//Rite of Spectral Manifestation: Summons a ghost on top of the rune as a cultist human with no items. User must stand on the rune at all times, and takes damage for each summoned ghost. +/obj/effect/rune/manifest + cultist_name = "Rite of Spectral Manifestation" + cultist_desc = "manifests a spirit as a servant of your god. The invoker must not move from atop the rune, and will take damage for each summoned spirit." + invocation = "Gal'h'rfikk harfrandid mud'gib!" //how the fuck do you pronounce this + icon_state = "6" + construct_invoke = 0 + color = rgb(200, 0, 0) + +/obj/effect/rune/manifest/New(loc) + ..() + cultist_desc = "manifests a spirit as a servant of [ticker.mode.cultdat.entity_title3]. The invoker must not move from atop the rune, and will take damage for each summoned spirit." + + notify_ghosts("Manifest rune created in [get_area(src)].", 'sound/effects/ghost2.ogg', source = src) + +/obj/effect/rune/manifest/can_invoke(mob/living/user) + if(!(user in get_turf(src))) + to_chat(user,"You must be standing on [src]!") + fail_invoke() + log_game("Manifest rune failed - user not standing on rune") + return list() + var/list/ghosts_on_rune = list() + for(var/mob/dead/observer/O in get_turf(src)) + if(O.client && !jobban_isbanned(O, ROLE_CULTIST)) + ghosts_on_rune |= O + if(!ghosts_on_rune.len) + to_chat(user, "There are no spirits near [src]!") + fail_invoke() + log_game("Manifest rune failed - no nearby ghosts") + return list() + return ..() + +/obj/effect/rune/manifest/invoke(var/list/invokers) + var/mob/living/user = invokers[1] + var/list/ghosts_on_rune = list() + for(var/mob/dead/observer/O in get_turf(src)) + if(O.client && !jobban_isbanned(O, ROLE_CULTIST)) + ghosts_on_rune |= O + var/mob/dead/observer/ghost_to_spawn = pick(ghosts_on_rune) + var/mob/living/carbon/human/new_human = new(get_turf(src)) + new_human.real_name = ghost_to_spawn.real_name + new_human.alpha = 150 //Makes them translucent + ..() + visible_message("A cloud of red mist forms above [src], and from within steps... a man.") + to_chat(user, "Your blood begins flowing into [src]. You must remain in place and conscious to maintain the forms of those summoned. This will hurt you slowly but surely...") + var/obj/machinery/shield/N = new(get_turf(src)) + N.name = "Invoker's Shield" + N.desc = "A weak shield summoned by cultists to protect them while they carry out delicate rituals" + N.color = "red" + N.health = 20 + N.mouse_opacity = 0 + new_human.key = ghost_to_spawn.key + ticker.mode.add_cultist(new_human.mind, 0) + to_chat(new_human, "You are a servant of [ticker.mode.cultdat.entity_title3]. You have been made semi-corporeal by the cult of [ticker.mode.cultdat.entity_name], and you are to serve them at all costs.") + + while(user in get_turf(src)) + if(user.stat) + break + user.apply_damage(0.1, BRUTE) + sleep(3) + + qdel(N) + if(new_human) + new_human.visible_message("[new_human] suddenly dissolves into bones and ashes.", \ + "Your link to the world fades. Your form breaks apart.") + for(var/obj/I in new_human) + new_human.unEquip(I) + new_human.dust() \ No newline at end of file diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm index 4f4cd137b80..1d0ac22c81c 100644 --- a/code/game/gamemodes/cult/talisman.dm +++ b/code/game/gamemodes/cult/talisman.dm @@ -1,255 +1,405 @@ /obj/item/weapon/paper/talisman icon_state = "paper_talisman" - var/imbue = null - var/uses = 0 + var/cultist_name = "talisman" + var/cultist_desc = "A basic talisman. It serves no purpose." + var/invocation = "Naise meam!" info = "


" + var/uses = 1 + var/health_cost = 0 //The amount of health taken from the user when invoking the talisman - attack_self(mob/living/user as mob) - if(iscultist(user)) - var/delete = 1 - switch(imbue) - if("newtome") - call(/obj/effect/rune/proc/tomesummon)() - if("armor") - call(/obj/effect/rune/proc/armor)() - if("emp") - call(/obj/effect/rune/proc/emp)(usr.loc,3) - if("conceal") - call(/obj/effect/rune/proc/obscure)(2) - if("revealrunes") - call(/obj/effect/rune/proc/revealrunes)(src) - if("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "balaq", "mgar", "karazet", "geeri") - call(/obj/effect/rune/proc/teleport)(imbue) - if("communicate") - //If the user cancels the talisman this var will be set to 0 - delete = call(/obj/effect/rune/proc/communicate)() - if("deafen") - call(/obj/effect/rune/proc/deafen)() - if("blind") - call(/obj/effect/rune/proc/blind)() - if("runestun") - to_chat(user, "\red To use this talisman, attack your target directly.") - return - if("supply") - supply() - user.take_organ_damage(5, 0) - if(src && src.imbue!="supply" && src.imbue!="runestun") - if(delete) - qdel(src) - return - else - to_chat(user, "You see strange symbols on the paper. Are they supposed to mean something?") - return +/obj/item/weapon/paper/talisman/examine(mob/user) + if(iscultist(user) || user.stat == DEAD) + to_chat(user, "Name: [cultist_name]") + to_chat(user, "Effect: [cultist_desc]") + to_chat(user, "Uses Remaining: [uses]") + else + to_chat(user, "You see strange symbols on the paper. Are they supposed to mean something?") - - attack(mob/living/carbon/T as mob, mob/living/user as mob) - if(iscultist(user)) - if(imbue == "runestun") - user.take_organ_damage(5, 0) - call(/obj/effect/rune/proc/runestun)(T) - qdel(src) - else - ..() ///If its some other talisman, use the generic attack code, is this supposed to work this way? - else - ..() - - - proc/supply(var/key) - if(!src.uses) - qdel(src) - return - - var/dat = "There are [src.uses] bloody runes on the parchment.
" - dat += "Please choose the chant to be imbued into the fabric of reality.
" - dat += "
" - dat += "N'ath reth sh'yro eth d'raggathnor! - Allows you to summon a new arcane tome.
" - dat += "Sas'so c'arta forbici! - Allows you to move to a rune with the same last word.
" - dat += "Ta'gh fara'qha fel d'amar det! - Allows you to destroy technology in a short range.
" - dat += "Kla'atu barada nikt'o! - Allows you to conceal the runes you placed on the floor.
" - dat += "O bidai nabora se'sma! - Allows you to coordinate with others of your cult.
" - dat += "Fuu ma'jin - Allows you to stun a person by attacking them with the talisman.
" - dat += "Sa tatha najin - Allows you to summon armoured robes and an unholy blade
" - dat += "Kal om neth - Summons a soul stone
" - dat += "Da A'ig Osk - Summons a construct shell for use with captured souls. It is too large to carry on your person.
" - usr << browse(dat, "window=id_com;size=350x200") +/obj/item/weapon/paper/talisman/attack_self(mob/living/user) + if(!iscultist(user)) + to_chat(user, "You see strange symbols on the paper. Are they supposed to mean something?") return + if(invoke(user)) + uses-- + if(uses <= 0) + user.drop_item() + qdel(src) +/obj/item/weapon/paper/talisman/proc/invoke(mob/living/user, successfuluse = 1) + . = successfuluse + if(successfuluse) //if the calling whatever says we succeed, do the fancy stuff + if(invocation) + user.whisper(invocation) + if(health_cost && iscarbon(user)) + var/mob/living/carbon/C = user + C.apply_damage(health_cost, BRUTE, pick("l_arm", "r_arm")) - Topic(href, href_list) - if(!src) return - if(usr.stat || usr.restrained() || !in_range(src, usr)) return - - if(href_list["rune"]) - if(istype(usr, /mob/living/carbon/human)) - var/mob/living/carbon/human/M = usr - - switch(href_list["rune"]) - if("newtome") - - var/obj/item/weapon/paper/talisman/T = new(M) - T.imbue = "newtome" - - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - - var/where = M.equip_in_one_of_slots(T, slots) - if(!where) - to_chat(M, "You need a space in your backpack, pocket or hand for the new paper.") - else - to_chat(M, "The [href_list["rune"]] talisman in your [where]") - M.update_icons() - src.uses-- - supply() - - - if("teleport") - var/obj/item/weapon/paper/talisman/T = new(M) - T.imbue = "[pick("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "balaq", "mgar", "karazet", "geeri", "orkan", "allaq")]" - T.info = "[T.imbue]" - - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - - var/where = M.equip_in_one_of_slots(T, slots) - if(!where) - to_chat(M, "You need a space in your backpack, pocket or hand for the new paper.") - else - to_chat(M, "The [href_list["rune"]] talisman in your [where]") - M.update_icons() - src.uses-- - supply() - - if("emp") - var/obj/item/weapon/paper/talisman/T = new(M) - T.imbue = "emp" - - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - - var/where = M.equip_in_one_of_slots(T, slots) - if(!where) - to_chat(M, "You need a space in your backpack, pocket or hand for the new paper.") - else - to_chat(M, "The [href_list["rune"]] talisman in your [where]") - M.update_icons() - src.uses-- - supply() - - if("conceal") - var/obj/item/weapon/paper/talisman/T = new(M) - T.imbue = "conceal" - - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - - var/where = M.equip_in_one_of_slots(T, slots) - if(!where) - to_chat(M, "You need a space in your backpack, pocket or hand for the new paper.") - else - to_chat(M, "The [href_list["rune"]] talisman in your [where]") - M.update_icons() - src.uses-- - supply() - - if("communicate") - var/obj/item/weapon/paper/talisman/T = new(M) - T.imbue = "communicate" - - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - - var/where = M.equip_in_one_of_slots(T, slots) - if(!where) - to_chat(M, "You need a space in your backpack, pocket or hand for the new paper.") - else - to_chat(M, "The [href_list["rune"]] talisman in your [where]") - M.update_icons() - src.uses-- - supply() - - if("runestun") - var/obj/item/weapon/paper/talisman/T = new(M) - T.imbue = "runestun" - - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - - var/where = M.equip_in_one_of_slots(T, slots) - if(!where) - to_chat(M, "You need a space in your backpack, pocket or hand for the new paper.") - else - to_chat(M, "The [href_list["rune"]] talisman in your [where]") - M.update_icons() - src.uses-- - supply() - - if("armor") - var/obj/item/weapon/paper/talisman/T = new(M) - T.imbue = "armor" - - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - - var/where = M.equip_in_one_of_slots(T, slots) - if(!where) - to_chat(M, "You need a space in your backpack, pocket or hand for the new paper.") - else - to_chat(M, "The [href_list["rune"]] talisman in your [where]") - M.update_icons() - src.uses-- - supply() - - if("soulstone") - new /obj/item/device/soulstone(get_turf(usr)) - src.uses-- - supply() - if("construct") - new /obj/structure/constructshell(get_turf(usr)) - src.uses-- - supply() - else - return - - - - return +//Malformed Talisman: If something goes wrong. +/obj/item/weapon/paper/talisman/malformed + cultist_name = "malformed talisman" + cultist_desc = "A talisman with gibberish scrawlings. No good can come from invoking this." + invocation = "Ra'sha yoka!" +/obj/item/weapon/paper/talisman/malformed/invoke(mob/living/user, successfuluse = 1) + to_chat(user, "You feel a pain in your head. [ticker.mode.cultdat.entity_title3] is displeased.") + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.apply_damage(10, BRUTE, "head") +//Supply Talisman: Has a few unique effects. Granted only to starter cultists. /obj/item/weapon/paper/talisman/supply - imbue = "supply" - uses = 5 \ No newline at end of file + cultist_name = "Supply Talisman" + cultist_desc = "A multi-use talisman that can create various objects. Intended to increase the cult's strength early on." + invocation = null + uses = 3 + +/obj/item/weapon/paper/talisman/supply/invoke(mob/living/user, successfuluse = 1) + var/dat = list() + dat += "There are [uses] bloody runes on the parchment.
" + dat += "Please choose the chant to be imbued into the fabric of reality.
" + dat += "
" + dat += "N'ath reth sh'yro eth d'raggathnor! - Summons an arcane tome, used to scribe runes and communicate with other cultists.
" + dat += "Sas'so c'arta forbici! - Allows you to move to a selected teleportation rune.
" + dat += "Ta'gh fara'qha fel d'amar det! - Allows you to destroy technology in a short range.
" + dat += "Fuu ma'jin! - Allows you to stun a person by attacking them with the talisman.
" + dat += "Kla'atu barada nikt'o! - Two use talisman, first use makes all nearby runes invisible, second use reveals nearby hidden runes.
" + dat += "Kal'om neth! - Summons a soul stone, used to capure the spirits of dead or dying humans.
" + dat += "Daa'ig osk! - Summons a construct shell for use with soulstone-captured souls. It is too large to carry on your person.
" + var/datum/browser/popup = new(user, "talisman", "", 400, 400) + popup.set_content(jointext(dat, "")) + popup.open() + return 0 + +/obj/item/weapon/paper/talisman/supply/Topic(href, href_list) + if(src) + if(usr.stat || usr.restrained() || !in_range(src, usr)) + return + if(href_list["rune"]) + switch(href_list["rune"]) + if("newtome") + var/obj/item/weapon/tome/T = new(usr) + usr.put_in_hands(T) + if("teleport") + var/obj/item/weapon/paper/talisman/teleport/T = new(usr) + usr.put_in_hands(T) + if("emp") + var/obj/item/weapon/paper/talisman/emp/T = new(usr) + usr.put_in_hands(T) + if("runestun") + var/obj/item/weapon/paper/talisman/stun/T = new(usr) + usr.put_in_hands(T) + if("soulstone") + var/obj/item/device/soulstone/T = new(usr) + usr.put_in_hands(T) + if("construct") + new /obj/structure/constructshell(get_turf(usr)) + if("veiling") + var/obj/item/weapon/paper/talisman/true_sight/T = new(usr) + usr.put_in_hands(T) + uses-- + if(uses <= 0) + if(iscarbon(usr)) + var/mob/living/carbon/C = usr + C.drop_item() + visible_message("[src] crumbles to dust.") + qdel(src) + +/obj/item/weapon/paper/talisman/supply/weak + uses = 2 + +//Rite of Translocation: Same as rune +/obj/item/weapon/paper/talisman/teleport + cultist_name = "Talisman of Teleportation" + cultist_desc = "A single-use talisman that will teleport a user to a random rune of the same keyword." + invocation = "Sas'so c'arta forbici!" + health_cost = 5 + +/obj/item/weapon/paper/talisman/teleport/invoke(mob/living/user, successfuluse = 1) + var/list/potential_runes = list() + var/list/teleportnames = list() + var/list/duplicaterunecount = list() + for(var/R in teleport_runes) + var/obj/effect/rune/teleport/T = R + var/resultkey = T.listkey + if(resultkey in teleportnames) + duplicaterunecount[resultkey]++ + resultkey = "[resultkey] ([duplicaterunecount[resultkey]])" + else + teleportnames.Add(resultkey) + duplicaterunecount[resultkey] = 1 + potential_runes[resultkey] = T + + if(!potential_runes.len) + to_chat(user, "There are no valid runes to teleport to!") + log_game("Teleport talisman failed - no other teleport runes") + return ..(user, 0) + + if(!is_level_reachable(user.z)) + to_chat(user, "You are not in the right dimension!") + log_game("Teleport talisman failed - user in away mission") + return ..(user, 0) + + var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked + var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to? + if(!actual_selected_rune) + return ..(user, 0) + user.visible_message("Dust flows from [user]'s hand, and they disappear in a flash of red light!", \ + "You speak the words of the talisman and find yourself somewhere else!") + user.forceMove(get_turf(actual_selected_rune)) + return ..() + + +/obj/item/weapon/paper/talisman/summon_tome + cultist_name = "Talisman of Tome Summoning" + cultist_desc = "A one-use talisman that will call an untranslated tome from the archives of a cult." + invocation = "N'ath reth sh'yro eth d'raggathnor!" + health_cost = 1 + +/obj/item/weapon/paper/talisman/summon_tome/invoke(mob/living/user, successfuluse = 1) + . = ..() + user.visible_message("[user]'s hand glows red for a moment.", \ + "You speak the words of the talisman!") + new /obj/item/weapon/tome(get_turf(user)) + user.visible_message("A tome appears at [user]'s feet!", \ + "An arcane tome materializes at your feet.") + +/obj/item/weapon/paper/talisman/true_sight + cultist_name = "Talisman of Veiling" + cultist_desc = "A multi-use talisman that hides nearby runes. On its second use, will reveal nearby runes." + invocation = "Kla'atu barada nikt'o!" + health_cost = 1 + uses = 2 + var/revealing = FALSE //if it reveals or not + +/obj/item/weapon/paper/talisman/true_sight/invoke(mob/living/user, successfuluse = 1) + . = ..() + if(!revealing) + user.visible_message("Thin grey dust falls from [user]'s hand!", \ + "You speak the words of the talisman, hiding nearby runes.") + invocation = "Nikt'o barada kla'atu!" + revealing = TRUE + for(var/obj/effect/rune/R in range(3,user)) + R.talismanhide() + else + user.visible_message("A flash of light shines from [user]'s hand!", \ + "You speak the words of the talisman, revealing nearby runes.") + for(var/obj/effect/rune/R in range(3,user)) + R.talismanreveal() + +//Rite of False Truths: Same as rune +/obj/item/weapon/paper/talisman/make_runes_fake + cultist_name = "Talisman of Disguising" + cultist_desc = "A talisman that will make nearby runes appear fake." + invocation = "By'o nar'nar!" + +/obj/item/weapon/paper/talisman/make_runes_fake/invoke(mob/living/user, successfuluse = 1) + . = ..() + user.visible_message("Dust flows from [user]s hand.", \ + "You speak the words of the talisman, making nearby runes appear fake.") + for(var/obj/effect/rune/R in orange(6,user)) + R.talismanfake() + R.desc = "A rune drawn in crayon." + + +//Rite of Disruption: Weaker than rune +/obj/item/weapon/paper/talisman/emp + cultist_name = "Talisman of Electromagnetic Pulse" + cultist_desc = "A talisman that will cause a moderately-sized electromagnetic pulse." + invocation = "Ta'gh fara'qha fel d'amar det!" + health_cost = 5 + +/obj/item/weapon/paper/talisman/emp/invoke(mob/living/user, successfuluse = 1) + . = ..() + user.visible_message("[user]'s hand flashes a bright blue!", \ + "You speak the words of the talisman, emitting an EMP blast.") + empulse(src, 4, 8) + + +//Rite of Disorientation: Stuns and inhibit speech on a single target for quite some time +/obj/item/weapon/paper/talisman/stun + cultist_name = "Talisman of Stunning" + cultist_desc = "A talisman that will stun and inhibit speech on a single target. To use, attack target directly." + invocation = "Dream sign:Evil sealing talisman!" + health_cost = 10 + +/obj/item/weapon/paper/talisman/stun/invoke(mob/living/user, successfuluse = 0) + if(successfuluse) //if we're forced to be successful(we normally aren't) then do the normal stuff + return ..() + if(iscultist(user)) + to_chat(user, "To use this talisman, attack the target directly.") + else + to_chat(user, "You see strange symbols on the paper. Are they supposed to mean something?") + return 0 + +/obj/item/weapon/paper/talisman/stun/attack(mob/living/target, mob/living/user, successfuluse = 1) + if(iscultist(user)) + invoke(user, 1) + user.visible_message("[user] holds up [src], which explodes in a flash of red light!", \ + "You stun [target] with the talisman!") + var/obj/item/weapon/nullrod/N = locate() in target + if(N) + target.visible_message("[target]'s holy weapon absorbs the talisman's light!", \ + "Your holy weapon absorbs the blinding light!") + else + target.Weaken(10) + target.Stun(10) + target.flash_eyes(1,1) + if(issilicon(target)) + var/mob/living/silicon/S = target + S.emp_act(1) + if(iscarbon(target)) + var/mob/living/carbon/C = target + C.AdjustSilence(5) + C.AdjustStuttering(15) + C.AdjustCultSlur(20) + C.Jitter(15) + user.drop_item() + qdel(src) + return + ..() + + +//Rite of Arming: Equips cultist armor on the user, where available +/obj/item/weapon/paper/talisman/armor + cultist_name = "Talisman of Arming" + cultist_desc = "A talisman that will equip the invoker with cultist equipment if there is a slot to equip it to." + invocation = "N'ath reth sh'yro eth draggathnor!" + +/obj/item/weapon/paper/talisman/armor/invoke(mob/living/user, successfuluse = 1) + . = ..() + var/mob/living/carbon/human/H = user + user.visible_message("Otherworldly armor suddenly appears on [user]!", \ + "You speak the words of the talisman, arming yourself!") + H.equip_or_collect(new /obj/item/clothing/suit/hooded/cultrobes/alt(user), slot_wear_suit) + H.equip_or_collect(new /obj/item/weapon/storage/backpack/cultpack(user), slot_back) + H.drop_item() + H.put_in_hands(new /obj/item/weapon/melee/cultblade(user)) + H.put_in_hands(new /obj/item/weapon/restraints/legcuffs/bola/cult(user)) + +/obj/item/weapon/paper/talisman/armor/attack(mob/living/target, mob/living/user) + if(iscultist(user) && iscultist(target)) + user.drop_item() + invoke(target) + qdel(src) + return + ..() + + +//Talisman of Horrors: Breaks the mind of the victim with nightmarish hallucinations +/obj/item/weapon/paper/talisman/horror + cultist_name = "Talisman of Horrors" + cultist_desc = "A talisman that will break the mind of the victim with nightmarish hallucinations." + invocation = "Lo'Nab Na'Dm!" + +/obj/item/weapon/paper/talisman/horror/attack(mob/living/target, mob/living/user) + if(iscultist(user)) + to_chat(user, "You disturb [target] with visons of the end!") + if(iscarbon(target)) + var/mob/living/carbon/H = target + H.AdjustHallucinate(30) + qdel(src) + + +//Talisman of Fabrication: Creates a construct shell out of 25 metal sheets. +/obj/item/weapon/paper/talisman/construction + cultist_name = "Talisman of Construction" + cultist_desc = "Use this talisman on at least twenty-five metal sheets to create an empty construct shell or on plasteel to make runed metal" + invocation = "Ethra p'ni dedol!" + uses = 25 + +/obj/item/weapon/paper/talisman/construction/attack_self(mob/living/user) + if(iscultist(user)) + to_chat(user, "To use this talisman, place it upon a stack of metal sheets or plasteel sheets!.") + else + to_chat(user, "You see strange symbols on the paper. Are they supposed to mean something?") + + +/obj/item/weapon/paper/talisman/construction/attack(obj/M,mob/living/user) + if(iscultist(user)) + to_chat(user, "This talisman will only work on a stack of metal sheets or plasteel sheets!!") + log_game("Construct talisman failed - not a valid target") + +/obj/item/weapon/paper/talisman/construction/afterattack(obj/item/stack/sheet/target, mob/user, proximity_flag, click_parameters) + ..() + if(proximity_flag && iscultist(user)) + if(istype(target, /obj/item/stack/sheet/metal)) + var/turf/T = get_turf(target) + if(target.use(25)) + new /obj/structure/constructshell(T) + to_chat(user, "The talisman clings to the metal and twists it into a construct shell!") + user << sound('sound/magic/Staff_Chaos.ogg',0,1,25) + qdel(src) + return + if(istype(target, /obj/item/stack/sheet/plasteel)) + var/turf/T = get_turf(target) + var/quantity = min(target.amount, uses) + uses -= quantity + new /obj/item/stack/sheet/runed_metal(T,quantity) + target.use(quantity) + to_chat(user, "The talisman clings to the plasteel, transforming it into runed metal!") + user << sound('sound/magic/Staff_Chaos.ogg',0,1,25) + invoke(user, 1) + if(uses <= 0) + qdel(src) + else + to_chat(user, "The talisman must be used on metal or plasteel!") + +//Talisman of Shackling: Applies special cuffs directly from the talisman +/obj/item/weapon/paper/talisman/shackle + cultist_name = "Talisman of Shackling" + cultist_desc = "Use this talisman on a victim to handcuff them with dark bindings." + invocation = "In'totum Lig'abis!" + uses = 4 + +/obj/item/weapon/paper/talisman/shackle/invoke(mob/living/user, successfuluse = 0) + if(successfuluse) //if we're forced to be successful(we normally aren't) then do the normal stuff + return ..() + if(iscultist(user)) + to_chat(user, "To use this talisman, attack the target directly.") + else + to_chat(user, "You see strange symbols on the paper. Are they supposed to mean something?") + return 0 + +/obj/item/weapon/paper/talisman/shackle/attack(mob/living/carbon/target, mob/living/user) + if(iscultist(user) && istype(target)) + if(target.stat == DEAD) + user.visible_message("This talisman's magic does not affect the dead!") + return + CuffAttack(target, user) + return + ..() + +/obj/item/weapon/paper/talisman/shackle/proc/CuffAttack(mob/living/carbon/C, mob/living/user) + if(!C.handcuffed) + invoke(user, 1) + playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2) + C.visible_message("[user] begins restraining [C] with dark magic!", \ + "[user] begins shaping a dark magic around your wrists!") + if(do_mob(user, C, 30)) + if(!C.handcuffed) + C.handcuffed = new /obj/item/weapon/restraints/handcuffs/energy/cult/used(C) + C.update_handcuffed() + to_chat(user, "You shackle [C].") + add_logs(user, C, "handcuffed") + uses-- + else + to_chat(user, "[C] is already bound.") + else + to_chat(user, "You fail to shackle [C].") + else + to_chat(user, "[C] is already bound.") + if(uses <= 0) + user.drop_item() + qdel(src) + return + +/obj/item/weapon/restraints/handcuffs/energy/cult //For the talisman of shackling + name = "cult shackles" + desc = "Shackles that bind the wrists with sinister magic." + trashtype = /obj/item/weapon/restraints/handcuffs/energy/used + origin_tech = "materials=2;magnets=5" + +/obj/item/weapon/restraints/handcuffs/energy/cult/used/dropped(mob/user) + user.visible_message("[user]'s shackles shatter in a discharge of dark magic!", \ + "Your [src] shatters in a discharge of dark magic!") + qdel(src) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index f94a731573a..c52b54e6f7b 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -31,6 +31,7 @@ var/ert_disabled = 0 var/uplink_welcome = "Syndicate Uplink Console:" var/uplink_uses = 20 + var/datum/cult_info/cultdat = new /datum/cult_info() //here instead of cult for adminbus purposes var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds) var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds) @@ -45,6 +46,7 @@ ///Checks to see if the game can be setup and ran with the current number of players or whatnot. /datum/game_mode/proc/can_start() var/playerC = 0 + cultdat = setupcult() for(var/mob/new_player/player in player_list) if((player.client)&&(player.ready)) playerC++ @@ -55,6 +57,7 @@ //pre_pre_setup() For when you really don't want certain jobs ingame. /datum/game_mode/proc/pre_pre_setup() + return 1 ///pre_setup() diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index bc682a4f168..b51a6074ec9 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -407,7 +407,7 @@ var/round_start_time = 0 if(player.client) if(player.client.karma_spent == 0) - if(player.client.prefs && !(player.client.prefs.toggles & DISABLE_KARMA_REMINDER)) + if(player.get_preference(DISABLE_KARMA_REMINDER)) var/dat dat += {"Karma Reminder

Karma Reminder


You have not yet spent your karma for the round, surely there is a player who was worthy of receiving
diff --git a/code/game/gamemodes/miniantags/slaughter/slaughter.dm b/code/game/gamemodes/miniantags/slaughter/slaughter.dm index 6269d2e65d6..2750341e982 100644 --- a/code/game/gamemodes/miniantags/slaughter/slaughter.dm +++ b/code/game/gamemodes/miniantags/slaughter/slaughter.dm @@ -52,18 +52,21 @@ del_on_death = 1 deathmessage = "screams in anger as it collapses into a puddle of viscera!" + var/datum/action/innate/demon/whisper/whisper_action + /mob/living/simple_animal/slaughter/New() ..() var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new AddSpell(bloodspell) + whisper_action = new() + whisper_action.Grant(src) if(istype(loc, /obj/effect/dummy/slaughter)) bloodspell.phased = 1 if(mind) to_chat(src, src.playstyle_string) to_chat(src, "You are not currently in the same plane of existence as the station. Ctrl+Click a blood pool to manifest.") src << 'sound/misc/demon_dies.ogg' - mind.current.verbs += /mob/living/simple_animal/slaughter/proc/slaughterWhisper if(!(vialspawned)) var/datum/objective/slaughter/objective = new var/datum/objective/demonFluff/fluffObjective = new @@ -101,31 +104,127 @@ speed = 0 boost = world.time + 60 + + + +/mob/living/simple_animal/slaughter/cult //Summoned as part of the cult objective "Bring the Slaughter" + name = "harbringer of the slaughter" + real_name = "harbringer of the Slaughter" + desc = "An awful creature from beyond the realms of madness." + maxHealth = 500 + health = 500 + melee_damage_upper = 60 + melee_damage_lower = 60 + environment_smash = 3 //Smashes through EVERYTHING - r-walls included + faction = list("cult") + playstyle_string = "You are a Harbringer of the Slaughter. Brought forth by the servants of Nar-Sie, you have a single purpose: slaughter the heretics \ + who do not worship your master. You may use the ability 'Blood Crawl' near a pool of blood to enter it and become incorporeal. Using the ability again near a blood pool will allow you \ + to emerge from it. You are fast, powerful, and almost invincible. By dragging a dead or unconscious body into a blood pool with you, you will consume it after a time and fully regain \ + your health. You may use the Sense Victims in your Cultist tab to locate a random, living heretic." + +/obj/effect/proc_holder/spell/targeted/sense_victims + name = "Sense Victims" + desc = "Sense the location of heratics" + charge_max = 0 + clothes_req = 0 + range = 20 + cooldown_min = 0 + overlay = null + action_icon_state = "bloodcrawl" + action_background_icon_state = "bg_cult" + panel = "Demon" + +/obj/effect/proc_holder/spell/targeted/sense_victims/cast(list/targets) + var/list/victims = targets + for(var/mob/living/L in living_mob_list) + if(!L.stat && !iscultist(L) && L.key && L != usr) + victims.Add(L) + if(!targets.len) + to_chat(usr, "You could not locate any sapient heretics for the Slaughter.") + return 0 + var/mob/living/victim = pick(victims) + to_chat(victim, "You feel an awful sense of being watched...") + victim.Stun(3) //HUE + var/area/A = get_area(victim) + if(!A) + to_chat(usr, "You could not locate any sapient heretics for the Slaughter.") + return 0 + to_chat(usr, "You sense a terrified soul at [A]. Show them the error of their ways.") + +/mob/living/simple_animal/slaughter/cult/New() + ..() + spawn(5) + var/list/demon_candidates = get_candidates(ROLE_CULTIST) + if(!demon_candidates.len) + visible_message("[src] disappears in a flash of red light!") + qdel(src) + return 0 + var/client/C = pick(demon_candidates) + var/mob/living/simple_animal/slaughter/cult/S = src + if(!C) + visible_message("[src] disappears in a flash of red light!") + qdel(src) + return 0 + + S.key = C.key + S.mind.assigned_role = "Harbringer of the Slaughter" + S.mind.special_role = "Harbringer of the Slaughter" + to_chat(S, playstyle_string) + ticker.mode.add_cultist(S.mind) + var/obj/effect/proc_holder/spell/targeted/sense_victims/SV = new + AddSpell(SV) + var/datum/objective/new_objective = new /datum/objective + new_objective.owner = S.mind + new_objective.explanation_text = "Bring forth the Slaughter to the nonbelievers." + S.mind.objectives += new_objective + to_chat(S, "Objective #[1]: [new_objective.explanation_text]") + ////////////////////The Powers //Paradise Port:I added this cuase..SPOOPY DEMON IN YOUR BRAIN -/mob/living/simple_animal/slaughter/proc/slaughterWhisper() - set name = "Whisper" - set desc = "Whisper to a mortal" - set category = "Daemon" +/datum/action/innate/demon/whisper + name = "Demonic Whisper" + button_icon_state = "cult_comms" + background_icon_state = "bg_demon" - var/list/choices = list() - for(var/mob/living/carbon/C in living_mob_list) - if(C.stat != 2 && C.client && C.stat != DEAD) - choices += C +/datum/action/innate/demon/whisper/IsAvailable() + return ..() - var/mob/living/carbon/M = input(src,"Who do you wish to talk to?") in null|choices - spawn(0) - var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "") - if(!(msg)) - return - log_say("Slaughter Demon Transmit: [key_name(usr)]->[key_name(M)]: [msg]") - to_chat(usr, "You whisper to [M]: [msg]") - to_chat(M, "Suddenly a strange, demonic voice resonates in your head... [msg]") - for(var/mob/dead/observer/G in player_list) - G.show_message("Demonic message from [usr] ([ghost_follow_link(usr, ghost=G)]) to [M] ([ghost_follow_link(M, ghost=G)]): [msg]") +/datum/action/innate/demon/whisper/proc/choose_targets(mob/user = usr)//yes i am copying from telepathy..hush... + var/list/targets = new /list() + var/list/validtargets = new /list() + for(var/mob/M in view(user.client.view, user)) + if(M && M.mind) + if(M == user) + continue + + validtargets += M + + if(!validtargets.len) + to_chat(usr, "There are no valid targets!") + return + + targets += input("Choose the target to talk to.", "Targeting") as null|mob in validtargets + + if(!targets.len || !targets[1]) + return + +/datum/action/innate/demon/whisper/Activate() + var/list/choice = choose_targets() + + if(!choice.len) + return + + var/msg = stripped_input(usr, "What do you wish to tell [choice]?", null, "") + if(!(msg)) + return + log_say("Slaughter Demon Transmit: [key_name(usr)]->[key_name(choice)]: [msg]") + to_chat(usr, "You whisper to [choice]: [msg]") + to_chat(choice, "Suddenly a strange, demonic voice resonates in your head... [msg]") + for(var/mob/dead/observer/G in player_list) + G.show_message("Demonic message from [usr] ([ghost_follow_link(usr, ghost=G)]) to [choice] ([ghost_follow_link(choice, ghost=G)]): [msg]") //////////The Loot diff --git a/code/game/gamemodes/scoreboard.dm b/code/game/gamemodes/scoreboard.dm index c4957b3b937..bd391550b62 100644 --- a/code/game/gamemodes/scoreboard.dm +++ b/code/game/gamemodes/scoreboard.dm @@ -150,9 +150,8 @@ to_chat(world, "The crew's final score is:") to_chat(world, "[score_crewscore]") for(var/mob/E in player_list) - if(E.client) - if(E.client.prefs && !(E.client.prefs.toggles & DISABLE_SCOREBOARD)) - E.scorestats() + if(E.client && !E.get_preference(DISABLE_SCOREBOARD)) + E.scorestats() // A recursive function to properly determine the wealthiest escapee /datum/controller/gameticker/proc/get_score_container_worth(atom/C, level=0) diff --git a/code/game/gamemodes/setupgame.dm b/code/game/gamemodes/setupgame.dm index 15ec89d71a2..61abe7bf39e 100644 --- a/code/game/gamemodes/setupgame.dm +++ b/code/game/gamemodes/setupgame.dm @@ -148,3 +148,14 @@ // Populate the syndicate coalition: for(var/datum/faction/syndicate/S in ticker.factions) ticker.syndicate_coalition.Add(S) + +/proc/setupcult() + var/random_cult = pick(all_cults) + var/picked_cult = new random_cult() //this seems redundent as fuck + log_startup_progress("Summoning eldritch horrors...") + if(!picked_cult)//shouldn't happen BUT JUST TO BE SURE LET US KNOW + log_startup_progress(" Failed to select a cult datum, Shank a coder!") + else + log_startup_progress(" [picked_cult] has risen!") + //todo:add adminonly datum var, check for said var here... + return picked_cult \ No newline at end of file diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm index a6e973fc536..29eae864fb8 100644 --- a/code/game/gamemodes/wizard/soulstone.dm +++ b/code/game/gamemodes/wizard/soulstone.dm @@ -104,6 +104,22 @@ /obj/item/proc/transfer_soul(var/choice as text, var/target, var/mob/U as mob). switch(choice) + if("FORCE") + var/obj/item/device/soulstone/C = src + if(!iscarbon(target)) //TODO: Add sacrifice stoning for non-organics, just because you have no body doesnt mean you dont have a soul + return 0 + if(contents.len) + return 0 + var/mob/living/carbon/T = target + if(T.client != null) + for(var/obj/item/W in T) + T.unEquip(W) + C.init_shade(T, U) + return 1 + else + to_chat(U, "Capture failed!: The soul has already fled its mortal frame. You attempt to bring it back...") + return C.getCultGhost(T,U) + if("VICTIM") var/mob/living/carbon/human/T = target var/obj/item/device/soulstone/C = src @@ -114,37 +130,15 @@ to_chat(U, "Capture failed!: Kill or maim the victim first!") else if(T.client == null) - to_chat(U, "Capture failed!: The soul has already fled it's mortal frame.") + to_chat(U, "Capture failed!: The soul has already fled its mortal frame. You attempt to bring it back...") + C.getCultGhost(T,U) else if(C.contents.len) to_chat(U, "Capture failed!: The soul stone is full! Use or free an existing soul to make room.") else for(var/obj/item/W in T) T.unEquip(W) - new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton - T.invisibility = 101 - var/atom/movable/overlay/animation = new /atom/movable/overlay( T.loc ) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = T - flick("dust-h", animation) - qdel(animation) - var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade( T.loc ) - S.loc = C //put shade in stone - S.status_flags |= GODMODE //So they won't die inside the stone somehow - S.canmove = 0//Can't move out of the soul stone - S.faction |= "\ref[U]" - S.name = "Shade of [T.real_name]" - S.real_name = "Shade of [T.real_name]" - if(T.client) - T.client.mob = S - S.cancel_camera() - C.icon_state = "soulstone2" - C.name = "Soul Stone: [S.real_name]" - to_chat(S, "Your soul has been captured! You are now bound to [U.name]'s will, help them suceed in their goals at all costs.") - to_chat(U, "Capture successful!: [T.real_name]'s soul has been ripped from their body and stored within the soul stone.") - to_chat(U, "The soulstone has been imprinted with [S.real_name]'s mind, it will no longer react to other souls.") - C.imprinted = "[S.name]" + C.init_shade(T, U, vic = 1) qdel(T) if("SHADE") var/mob/living/simple_animal/shade/T = target @@ -174,7 +168,7 @@ var/construct_class = alert(U, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer") switch(construct_class) if("Juggernaut") - var/mob/living/simple_animal/construct/armoured/Z = new /mob/living/simple_animal/construct/armoured (get_turf(T.loc)) + var/mob/living/simple_animal/hostile/construct/armoured/Z = new /mob/living/simple_animal/hostile/construct/armoured (get_turf(T.loc)) Z.key = A.key Z.faction |= "\ref[U]" if(iscultist(U)) @@ -190,7 +184,7 @@ qdel(C) if("Wraith") - var/mob/living/simple_animal/construct/wraith/Z = new /mob/living/simple_animal/construct/wraith (get_turf(T.loc)) + var/mob/living/simple_animal/hostile/construct/wraith/Z = new /mob/living/simple_animal/hostile/construct/wraith (get_turf(T.loc)) Z.key = A.key Z.faction |= "\ref[U]" if(iscultist(U)) @@ -206,7 +200,7 @@ qdel(C) if("Artificer") - var/mob/living/simple_animal/construct/builder/Z = new /mob/living/simple_animal/construct/builder (get_turf(T.loc)) + var/mob/living/simple_animal/hostile/construct/builder/Z = new /mob/living/simple_animal/hostile/construct/builder (get_turf(T.loc)) Z.key = A.key Z.faction |= "\ref[U]" if(iscultist(U)) @@ -224,10 +218,10 @@ to_chat(U, "Creation failed!: The soul stone is empty! Go kill someone!") return -/proc/makeNewConstruct(var/mob/living/simple_animal/construct/ctype, var/mob/target, var/mob/stoner = null, cultoverride = 0) +/proc/makeNewConstruct(var/mob/living/simple_animal/hostile/construct/ctype, var/mob/target, var/mob/stoner = null, cultoverride = 0) if(jobban_isbanned(target, "cultist") || jobban_isbanned(target, "Syndicate")) return - var/mob/living/simple_animal/construct/newstruct = new ctype(get_turf(target)) + var/mob/living/simple_animal/hostile/construct/newstruct = new ctype(get_turf(target)) newstruct.faction |= "\ref[stoner]" newstruct.key = target.key if(stoner && iscultist(stoner) || cultoverride) @@ -242,4 +236,61 @@ to_chat(newstruct, "You are still bound to serve the cult, follow their orders and help them complete their goals at all costs.") else to_chat(newstruct, "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.") - newstruct.cancel_camera() \ No newline at end of file + newstruct.cancel_camera() + + +/obj/item/device/soulstone/proc/init_shade(mob/living/carbon/human/T, mob/U, vic = 0) + new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton + T.invisibility = 101 + var/atom/movable/overlay/animation = new /atom/movable/overlay( T.loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = T + flick("dust-h", animation) + qdel(animation) + var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade(src) + S.status_flags |= GODMODE //So they won't die inside the stone somehow + S.canmove = 0//Can't move out of the soul stone + S.name = "Shade of [T.real_name]" + S.real_name = "Shade of [T.real_name]" + S.key = T.key + if(U) + S.faction |= "\ref[U]" //Add the master as a faction, allowing inter-mob cooperation + if(U && iscultist(U)) + ticker.mode.add_cultist(S.mind, 0) + S.cancel_camera() + name = "soulstone: Shade of [T.real_name]" + icon_state = "soulstone2" + if(U && iswizard(U)) + to_chat(S, "Your soul has been captured! You are now bound to [U.real_name]'s will. Help them succeed in their goals at all costs.") + else if(U && iscultist(U)) + to_chat(S, "Your soul has been captured! You are now bound to the cult's will. Help them succeed in their goals at all costs.") + if(vic && U) + to_chat(U, "Capture successful!: [T.real_name]'s soul has been ripped from their body and stored within the soul stone.") + + +/obj/item/device/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/U) + var/mob/dead/observer/chosen_ghost + + for(var/mob/dead/observer/ghost in player_list) //We put them back in their body + if(ghost.mind && ghost.mind.current == T && ghost.client) + chosen_ghost = ghost + break + + if(!chosen_ghost) //Failing that, we grab a ghost + var/list/consenting_candidates = pollCandidates("Would you like to play as a Shade?", "Cultist", null, ROLE_CULTIST, poll_time = 100) + if(consenting_candidates.len) + chosen_ghost = pick(consenting_candidates) + if(!T) + return 0 + if(!chosen_ghost) + to_chat(U, "There were no spirits willing to become a shade.") + return 0 + if(contents.len) //If they used the soulstone on someone else in the meantime + return 0 + T.ckey = chosen_ghost.ckey + for(var/obj/item/W in T) + T.unEquip(W) + init_shade(T, U) + qdel(T) + return 1 \ No newline at end of file diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm index a8846f2134a..0384276a5e6 100644 --- a/code/game/jobs/job/engineering.dm +++ b/code/game/jobs/job/engineering.dm @@ -17,7 +17,8 @@ access_heads, access_construction, access_sec_doors, access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_minisat, access_mechanic, access_mineral_storeroom) minimal_player_age = 21 - + exp_requirements = 600 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 @@ -51,7 +52,6 @@ minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_mineral_storeroom) alt_titles = list("Maintenance Technician","Engine Technician","Electrician") minimal_player_age = 7 - equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_or_collect(new /obj/item/device/radio/headset/headset_eng(H), slot_l_ear) @@ -83,7 +83,6 @@ minimal_access = list(access_eva, access_atmospherics, access_maint_tunnels, access_external_airlocks, access_emergency_storage, access_construction, access_mineral_storeroom) alt_titles = list("Atmospheric Technician") minimal_player_age = 7 - equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_or_collect(new /obj/item/device/radio/headset/headset_eng(H), slot_l_ear) diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 104ed27bc05..52a33e0f0fb 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -41,6 +41,9 @@ //If you have use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) var/minimal_player_age = 0 + var/exp_requirements = 0 + var/exp_type = "" + var/admin_only = 0 var/spawn_ert = 0 diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm index 1baceb6a57e..64b34a4fa79 100644 --- a/code/game/jobs/job/medical.dm +++ b/code/game/jobs/job/medical.dm @@ -15,6 +15,8 @@ access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, access_keycard_auth, access_sec_doors, access_psychiatrist, access_maint_tunnels, access_paramedic, access_mineral_storeroom) minimal_player_age = 21 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 @@ -109,7 +111,6 @@ alt_titles = list("Pharmacist","Pharmacologist") minimal_player_age = 7 - equip(var/mob/living/carbon/human/H) if(!H) return 0 switch(H.backbag) diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm index f03f5b4c0a1..7ea2eb5464f 100644 --- a/code/game/jobs/job/science.dm +++ b/code/game/jobs/job/science.dm @@ -17,6 +17,8 @@ access_research, access_robotics, access_xenobiology, access_ai_upload, access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_minisat, access_maint_tunnels, access_mineral_storeroom) minimal_player_age = 21 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW // All science-y guys get bonuses for maxing out their tech. required_objectives=list( diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index 47532f8d081..19539a83f4e 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -17,6 +17,8 @@ access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting, access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_pilot, access_weapons) minimal_player_age = 21 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 @@ -56,6 +58,8 @@ access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_morgue, access_weapons) minimal_access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_weapons) minimal_player_age = 21 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 @@ -98,6 +102,8 @@ minimal_access = list(access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court, access_weapons) alt_titles = list("Forensic Technician") minimal_player_age = 14 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_or_collect(new /obj/item/device/radio/headset/headset_sec/alt(H), slot_l_ear) @@ -148,6 +154,8 @@ access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_morgue, access_weapons) minimal_access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_weapons) minimal_player_age = 14 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_or_collect(new /obj/item/device/radio/headset/headset_sec/alt(H), slot_l_ear) diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm index 7bb2b006f87..eedb50a8412 100644 --- a/code/game/jobs/job/silicon.dm +++ b/code/game/jobs/job/silicon.dm @@ -8,6 +8,8 @@ supervisors = "your laws" req_admin_notify = 1 minimal_player_age = 30 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 @@ -15,7 +17,7 @@ /datum/job/ai/is_position_available() return (empty_playable_ai_cores.len != 0) - + /datum/job/cyborg title = "Cyborg" @@ -26,6 +28,8 @@ supervisors = "your laws and the AI" //Nodrak selection_color = "#ddffdd" minimal_player_age = 21 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW alt_titles = list("Android", "Robot") equip(var/mob/living/carbon/human/H) diff --git a/code/game/jobs/job/supervisor.dm b/code/game/jobs/job/supervisor.dm index 66f0ddb2c65..586fd27d639 100644 --- a/code/game/jobs/job/supervisor.dm +++ b/code/game/jobs/job/supervisor.dm @@ -12,6 +12,8 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) access = list() //See get_access() minimal_access = list() //See get_access() minimal_player_age = 30 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_or_collect(new /obj/item/device/radio/headset/heads/captain/alt(H), slot_l_ear) @@ -56,6 +58,8 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) idtype = /obj/item/weapon/card/id/silver req_admin_notify = 1 minimal_player_age = 21 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW access = list(access_security, access_sec_doors, access_brig, access_court, access_forensics_lockers, access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads, access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue, diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index 9073f56ceb3..93d048ce96e 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -123,6 +123,9 @@ var/global/datum/controller/occupations/job_master if(job.admin_only) // No admin positions either. continue + if(job.available_in_playtime(player.client)) + continue + if(jobban_isbanned(player, job.title)) Debug("GRJ isbanned failed, Player: [player], Job: [job.title]") continue diff --git a/code/game/jobs/job_exp.dm b/code/game/jobs/job_exp.dm new file mode 100644 index 00000000000..23d217a83bc --- /dev/null +++ b/code/game/jobs/job_exp.dm @@ -0,0 +1,191 @@ +// Admin Verbs + +/client/proc/cmd_admin_check_player_exp() //Allows admins to determine who the newer players are. + set category = "Admin" + set name = "Check Player Playtime" + if(!check_rights(R_ADMIN)) + return + var/msg = "Playtime ReportPlaytime:
" + src << browse(msg, "window=Player_playtime_check") + + +/datum/admins/proc/cmd_show_exp_panel(var/client/C) + if(!C) + to_chat(usr, "ERROR: Client not found.") + return + if(!check_rights(R_ADMIN)) + return + var/body = "Playtime for [C.key]
Playtime:" + body += C.get_exp_report() + body += "" + usr << browse(body, "window=playerplaytime[C.ckey];size=550x615") + + +// Procs + + +/datum/job/proc/available_in_playtime(client/C) + if(!C) + return 0 + if(!exp_requirements || !exp_type) + return 0 + if(!config.use_exp_restrictions) + return 0 + if(config.use_exp_restrictions_admin_bypass && check_rights(R_ADMIN, 0, C.mob)) + return 0 + var/list/play_records = params2list(C.prefs.exp) + var/isexempt = text2num(play_records[EXP_TYPE_EXEMPT]) + if(isexempt) + return 0 + var/my_exp = text2num(play_records[get_exp_req_type()]) + var/job_requirement = text2num(get_exp_req_amount()) + if(my_exp >= job_requirement) + return 0 + else + return (job_requirement - my_exp) + +/datum/job/proc/get_exp_req_amount() + return exp_requirements + +/datum/job/proc/get_exp_req_type() + return exp_type + +/mob/proc/get_exp_report() + if(client) + return client.get_exp_report() + else + return "[src] has no client." + +/client/proc/get_exp_report() + if(!config.use_exp_tracking) + return "Tracking is disabled in the server configuration file." + var/list/play_records = params2list(prefs.exp) + if(!play_records.len) + return "[key] has no records." + var/return_text = "" + if(config.use_exp_restrictions) + var/list/jobs_locked = list() + var/list/jobs_unlocked = list() + for(var/datum/job/job in job_master.occupations) + if(job.exp_requirements && job.exp_type) + if(!job.available_in_playtime(mob.client)) + jobs_unlocked += job.title + else + var/xp_req = job.get_exp_req_amount() + jobs_locked += "[job.title] ([get_exp_format(text2num(play_records[job.get_exp_req_type()]))] / [get_exp_format(xp_req)] as [job.get_exp_req_type()])" + if(jobs_unlocked.len) + return_text += "

Jobs Unlocked:" + if(jobs_locked.len) + return_text += "

Jobs Not Unlocked:" + return return_text + + +/client/proc/get_exp_living() + var/list/play_records = params2list(prefs.exp) + var/exp_living = text2num(play_records[EXP_TYPE_LIVING]) + return get_exp_format(exp_living) + +/proc/get_exp_format(var/expnum) + if(expnum > 60) + return num2text(round(expnum / 60)) + "h" + else if(expnum > 0) + return num2text(expnum) + "m" + else + return "none" + +/proc/update_exp(var/mins, var/ann = 0) + if(!establish_db_connection()) + return -1 + spawn(0) + for(var/client/L in clients) + if(L.inactivity >= (10 MINUTES)) + continue + spawn(0) + L.update_exp_client(mins, ann) + sleep(10) + +/client/proc/update_exp_client(var/minutes, var/announce_changes = 0) + if(!src ||!ckey) + return + var/DBQuery/exp_read = dbcon.NewQuery("SELECT exp FROM [format_table_name("player")] WHERE ckey='[ckey]'") + if(!exp_read.Execute()) + var/err = exp_read.ErrorMsg() + log_game("SQL ERROR during exp_update_client read. Error : \[[err]\]\n") + message_admins("SQL ERROR during exp_update_client read. Error : \[[err]\]\n") + return + var/list/read_records = list() + var/hasread = 0 + while(exp_read.NextRow()) + read_records = params2list(exp_read.item[1]) + hasread = 1 + if(!hasread) + return + var/list/play_records = list() + for(var/rtype in exp_jobsmap) + if(text2num(read_records[rtype])) + play_records[rtype] = text2num(read_records[rtype]) + else + play_records[rtype] = 0 + if(mob.stat == CONSCIOUS && mob.mind.assigned_role) + play_records[EXP_TYPE_LIVING] += minutes + if(announce_changes) + to_chat(mob,"You got: [minutes] Living EXP!") + for(var/category in exp_jobsmap) + if(exp_jobsmap[category]["titles"]) + if(mob.mind.assigned_role in exp_jobsmap[category]["titles"]) + play_records[category] += minutes + if(announce_changes) + to_chat(mob,"You got: [minutes] [category] EXP!") + if(mob.mind.special_role) + play_records[EXP_TYPE_SPECIAL] += minutes + if(announce_changes) + to_chat(mob,"You got: [minutes] Special EXP!") + else if(isobserver(mob)) + play_records[EXP_TYPE_GHOST] += minutes + if(announce_changes) + to_chat(mob,"You got: [minutes] Ghost EXP!") + else + return + var/new_exp = list2params(play_records) + prefs.exp = new_exp + new_exp = sanitizeSQL(new_exp) + var/DBQuery/update_query = dbcon.NewQuery("UPDATE [format_table_name("player")] SET exp = '[new_exp]' WHERE ckey='[ckey]'") + if(!update_query.Execute()) + var/err = update_query.ErrorMsg() + log_game("SQL ERROR during exp_update_client write. Error : \[[err]\]\n") + message_admins("SQL ERROR during exp_update_client write. Error : \[[err]\]\n") + return + +/hook/roundstart/proc/exptimer() + if(!config.sql_enabled || !config.use_exp_tracking) + return 1 + spawn(0) + while(TRUE) + sleep(5 MINUTES) + update_exp(5,0) + return 1 diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm index 6af69ebed9d..73f5cc2e5b0 100644 --- a/code/game/jobs/jobs.dm +++ b/code/game/jobs/jobs.dm @@ -183,3 +183,10 @@ var/list/whitelisted_positions = list( return titles +var/global/list/exp_jobsmap = list( + EXP_TYPE_LIVING = list(), // all living mobs + EXP_TYPE_CREW = list(titles = command_positions | engineering_positions | medical_positions | science_positions | support_positions | supply_positions | security_positions | civilian_positions | list("AI","Cyborg") | whitelisted_positions), // crew positions + EXP_TYPE_SPECIAL = list(), // antags, ERT, etc + EXP_TYPE_GHOST = list(), // dead people, observers + EXP_TYPE_EXEMPT = list() // special grandfather setting +) diff --git a/code/game/machinery/Freezer.dm b/code/game/machinery/Freezer.dm index 8a8c7a04114..542ed8b47b4 100644 --- a/code/game/machinery/Freezer.dm +++ b/code/game/machinery/Freezer.dm @@ -109,7 +109,7 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/atmospherics/unary/cold_sink/freezer/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/atmospherics/unary/cold_sink/freezer/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["on"] = on ? 1 : 0 data["gasPressure"] = round(air_contents.return_pressure()) @@ -267,7 +267,7 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/atmospherics/unary/heat_reservoir/heater/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/atmospherics/unary/heat_reservoir/heater/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["on"] = on ? 1 : 0 data["gasPressure"] = round(air_contents.return_pressure()) diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index 566fc4f80ff..a5db47222e6 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -696,7 +696,7 @@ data["danger"] = danger return data -/obj/machinery/alarm/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/alarm/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/list/href_list = state.href_list() diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index a7d62d74b94..65f6fb7b09d 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -131,7 +131,7 @@ var/datum/canister_icons/canister_icon_container = new() var/list/LL = L[i] LL = LL.Copy() //make sure we don't edit the datum list LL.Add(list("active" = decals[LL["icon"]])) //"active" used by nanoUI - possibledecals[i] = LL + possibledecals.Add(LL) /obj/machinery/portable_atmospherics/canister/proc/check_change() var/old_flag = update_flag @@ -181,6 +181,7 @@ update_flag if(src.destroyed) src.overlays = 0 src.icon_state = text("[]-1", src.canister_color["prim"])//yes, I KNOW the colours don't reflect when the can's borked, whatever. + return if(icon_state != src.canister_color["prim"]) icon_state = src.canister_color["prim"] @@ -420,9 +421,9 @@ update_flag data["hasHoldingTank"] = holding ? 1 : 0 if(holding) - data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure())) - - return data + data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure())) + + return data /obj/machinery/portable_atmospherics/canister/Topic(href, href_list) if(..()) diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm index 8f7f6d72bb4..acdb4d30aa0 100644 --- a/code/game/machinery/atmoalter/pump.dm +++ b/code/game/machinery/atmoalter/pump.dm @@ -117,7 +117,7 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/portable_atmospherics/pump/ui_data(mob/user, datum/topic_state/state = physical_state) +/obj/machinery/portable_atmospherics/pump/ui_data(mob/user, ui_key = "main", datum/topic_state/state = physical_state) var/data[0] data["portConnected"] = connected_port ? 1 : 0 data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm index de5ac2dc49d..044023c394a 100644 --- a/code/game/machinery/atmoalter/scrubber.dm +++ b/code/game/machinery/atmoalter/scrubber.dm @@ -128,7 +128,7 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/portable_atmospherics/scrubber/ui_data(mob/user, datum/topic_state/state = physical_state) +/obj/machinery/portable_atmospherics/scrubber/ui_data(mob/user, ui_key = "main", datum/topic_state/state = physical_state) var/data[0] data["portConnected"] = connected_port ? 1 : 0 data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 0e0eaaf6985..c131652a69a 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -410,7 +410,6 @@ if(H.mind in ticker.mode.syndicates) ticker.mode.update_synd_icons_added() if(H.mind in ticker.mode.cult) - ticker.mode.add_cult_viewpoint(H) ticker.mode.add_cultist(occupant.mind) ticker.mode.update_cult_icons_added() //So the icon actually appears if((H.mind in ticker.mode.implanter) || (H.mind in ticker.mode.implanted)) diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index 1c40370f56d..31700f8c2d3 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -92,7 +92,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/computer/operating/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/operating/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/mob/living/carbon/human/occupant = src.table.victim data["hasOccupant"] = occupant ? 1 : 0 diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 7dd5075d28e..f42e50d9618 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -1,14 +1,14 @@ /obj/machinery/computer/security name = "security camera console" desc = "Used to access the various cameras networks on the station." - + icon_keyboard = "security_key" icon_screen = "cameras" light_color = LIGHT_COLOR_RED circuit = /obj/item/weapon/circuitboard/camera - + var/mapping = 0 // For the overview file (overview.dm), not used on this page - + var/list/network = list() var/list/available_networks = list() var/list/watchers = list() //who's using the console, associated with the camera they're on. @@ -16,7 +16,7 @@ /obj/machinery/computer/security/New() // Lists existing networks and their required access. Format: available_networks[] = list() generate_network_access() ..() - + /obj/machinery/computer/security/proc/generate_network_access() available_networks["SS13"] = list(access_hos,access_captain) available_networks["Telecomms"] = list(access_hos,access_captain) @@ -39,7 +39,7 @@ available_networks["ERT"] = list(access_cent_specops_commander,access_cent_commander) available_networks["CentComm"] = list(access_cent_security,access_cent_commander) available_networks["Thunderdome"] = list(access_cent_thunder,access_cent_commander) - + /obj/machinery/computer/security/Destroy() if(watchers.len) for(var/mob/M in watchers) @@ -58,11 +58,11 @@ user.unset_machine() return return 1 - + /obj/machinery/computer/security/on_unset_machine(mob/user) watchers.Remove(user) user.reset_perspective(null) - + /obj/machinery/computer/security/attack_hand(mob/user) if(stat || ..()) user.unset_machine() @@ -83,7 +83,7 @@ attack_hand(user) else attack_hand(user) - + /obj/machinery.computer/security/proc/get_user_access(mob/user) var/list/access = list() if(ishuman(user)) @@ -105,8 +105,8 @@ ui.add_template("mapHeader", "sec_camera_map_header.tmpl") ui.open() - -/obj/machinery/computer/security/ui_data(mob/user, datum/topic_state/state = default_state) + +/obj/machinery/computer/security/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/list/cameras = list() @@ -126,7 +126,7 @@ cameras.Swap(j, j + 1) data["cameras"] = cameras - + var/list/access = get_user_access(user) if(emagged) access = get_all_accesses() // Assume captain level access when emagged @@ -149,8 +149,8 @@ data["current"] = null if(watchers[user]) var/obj/machinery/camera/watched = watchers[user] - data["current"] = watched.nano_structure() - + data["current"] = watched.nano_structure() + return data /obj/machinery/computer/security/Topic(href, href_list) @@ -162,7 +162,7 @@ var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.cameras if(!C) return 1 - + switch_to_camera(usr, C) else if(href_list["reset"]) @@ -180,31 +180,31 @@ else network += net break - + nanomanager.update_uis(src) // Check if camera is accessible when jumping /obj/machinery/computer/security/proc/can_access_camera(var/obj/machinery/camera/C, var/mob/M) if(CanUseTopic(M, default_state) != STATUS_INTERACTIVE || M.incapacitated() || M.blinded) return 0 - + if(isrobot(M)) var/list/viewing = viewers(src) if(!viewing.Find(M)) return 0 - + if(isAI(M)) var/mob/living/silicon/ai/A = M if(!A.is_in_chassis()) return 0 - + if(!issilicon(M) && !Adjacent(M)) return 0 - + var/list/shared_networks = network & C.network if(!shared_networks.len || !C.can_use()) return 0 - + return 1 // Switching to cameras @@ -212,7 +212,7 @@ if(!can_access_camera(C, user)) user.unset_machine() return 1 - + if(isAI(user)) var/mob/living/silicon/ai/A = user A.eyeobj.setLoc(get_turf(C)) @@ -226,12 +226,12 @@ /obj/machinery/computer/security/proc/jump_on_click(var/mob/user, var/A) if(user.machine != src) return - + var/obj/machinery/camera/jump_to - + if(istype(A, /obj/machinery/camera)) jump_to = A - + else if(ismob(A)) if(ishuman(A)) var/mob/living/carbon/human/H = A @@ -239,11 +239,11 @@ else if(isrobot(A)) var/mob/living/silicon/robot/R = A jump_to = R.camera - + else if(isobj(A)) var/obj/O = A jump_to = locate() in O - + else if(isturf(A)) var/best_dist = INFINITY for(var/obj/machinery/camera/camera in get_area(A)) @@ -255,10 +255,10 @@ if(dist < best_dist) best_dist = dist jump_to = camera - + if(isnull(jump_to)) return - + if(can_access_camera(jump_to, user)) switch_to_camera(user, jump_to) diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index a33d3aa02eb..ebba68ec570 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -181,7 +181,7 @@ var/time_last_changed_position = 0 ui = new(user, src, ui_key, "identification_computer.tmpl", src.name, 775, 700) ui.open() -/obj/machinery/computer/card/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/card/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["src"] = UID() data["station_name"] = station_name() diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 847f20a3f23..0d47420edc9 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -127,7 +127,7 @@ ui = new(user, src, ui_key, "cloning_console.tmpl", "Cloning Console UI", 640, 520) ui.open() -/obj/machinery/computer/cloning/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/cloning/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["menu"] = src.menu data["scanner"] = sanitize("[src.scanner]") diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 7420aaaa24a..86a8b2d2bcf 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -276,6 +276,18 @@ src.emagged = 0 setMenuState(usr,COMM_SCREEN_MAIN) + if("RestartNanoMob") + if(mob_hunt_server) + if(mob_hunt_server.manual_reboot()) + var/loading_msg = pick("Respawning spawns", "Reticulating splines", "Flipping hat", + "Capturing all of them", "Fixing minor text issues", "Being the very best", + "Nerfing this", "Not communicating with playerbase", "Coding a ripoff in a 2D spaceman game") + to_chat(usr, "Restarting Nano-Mob Hunter GO! game server. [loading_msg]...") + else + to_chat(usr, "Nano-Mob Hunter GO! game server reboot failed due to recent restart. Please wait before re-attempting.") + else + to_chat(usr, "Nano-Mob Hunter GO! game server is offline for extended maintenance. Contact your Central Command administrators for more info if desired.") + if("AcceptDocking") to_chat(usr, "Docking request accepted!") trade_dock_timelimit = world.time + 1200 @@ -322,7 +334,7 @@ // open the new ui window ui.open() -/obj/machinery/computer/communications/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/communications/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["is_ai"] = isAI(user)||isrobot(user) data["menu_state"] = data["is_ai"] ? ai_menu_state : menu_state diff --git a/code/game/machinery/computer/pod_tracking_console.dm b/code/game/machinery/computer/pod_tracking_console.dm index 8664d786a24..75bad25bfab 100644 --- a/code/game/machinery/computer/pod_tracking_console.dm +++ b/code/game/machinery/computer/pod_tracking_console.dm @@ -20,7 +20,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/computer/podtracker/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/podtracker/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/list/pods[0] for(var/obj/item/device/spacepod_equipment/misc/tracker/TR in world) diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index a195ad253df..5235fffd9ba 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -41,7 +41,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/computer/robotics/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/robotics/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/list/robots = get_cyborgs(user) if(robots.len) diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm index f42650a8e86..0b078a74ec8 100644 --- a/code/game/machinery/cryo.dm +++ b/code/game/machinery/cryo.dm @@ -190,7 +190,7 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/atmospherics/unary/cryo_cell/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/atmospherics/unary/cryo_cell/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["isOperating"] = on data["hasOccupant"] = occupant ? 1 : 0 diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index fe21020af5d..5f751556d0d 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1,1142 +1,1152 @@ -/* - New methods: - pulse - sends a pulse into a wire for hacking purposes - cut - cuts a wire and makes any necessary state changes - mend - mends a wire and makes any necessary state changes - canAIControl - 1 if the AI can control the airlock, 0 if not (then check canAIHack to see if it can hack in) - canAIHack - 1 if the AI can hack into the airlock to recover control, 0 if not. Also returns 0 if the AI does not *need* to hack it. - arePowerSystemsOn - 1 if the main or backup power are functioning, 0 if not. Does not check whether the power grid is charged or an APC has equipment on or anything like that. (Check (stat & NOPOWER) for that) - requiresIDs - 1 if the airlock is requiring IDs, 0 if not - isAllPowerCut - 1 if the main and backup power both have cut wires. - regainMainPower - handles the effect of main power coming back on. - loseMainPower - handles the effect of main power going offline. Usually (if one isn't already running) spawn a thread to count down how long it will be offline - counting down won't happen if main power was completely cut along with backup power, though, the thread will just sleep. - loseBackupPower - handles the effect of backup power going offline. - regainBackupPower - handles the effect of main power coming back on. - shock - has a chance of electrocuting its target. -*/ - - -// Wires for the airlock are located in the datum folder, inside the wires datum folder. - - -/obj/machinery/door/airlock - name = "airlock" - icon = 'icons/obj/doors/Doorint.dmi' - icon_state = "door_closed" - power_channel = ENVIRON - - var/aiControlDisabled = 0 //If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in. - var/hackProof = 0 // if 1, this door can't be hacked by the AI - var/electrified_until = 0 // World time when the door is no longer electrified. -1 if it is permanently electrified until someone fixes it. - var/main_power_lost_until = 0 //World time when main power is restored. - var/backup_power_lost_until = -1 //World time when backup power is restored. - var/electrified_timer = null - var/main_power_timer = null - var/backup_power_timer = null - var/spawnPowerRestoreRunning = 0 - var/welded = null - var/locked = 0 - var/lights = 1 // bolt lights show by default - var/datum/wires/airlock/wires = null - var/aiDisabledIdScanner = 0 - var/aiHacking = 0 - var/obj/machinery/door/airlock/closeOther = null - var/closeOtherId = null - var/lockdownbyai = 0 - var/assembly_type = /obj/structure/door_assembly - var/mineral = null - var/justzap = 0 - var/safe = 1 - normalspeed = 1 - var/obj/item/weapon/airlock_electronics/electronics = null - var/hasShocked = 0 //Prevents multiple shocks from happening - var/frozen = 0 //special condition for airlocks that are frozen shut, this will look weird on not normal airlocks because of a lack of special overlays. - autoclose = 1 - explosion_block = 1 - var/doorOpen = 'sound/machines/airlock.ogg' - var/doorClose = 'sound/machines/airlock.ogg' - var/doorDeni = 'sound/machines/DeniedBeep.ogg' // i'm thinkin' Deni's - var/boltUp = 'sound/machines/BoltsUp.ogg' - var/boltDown = 'sound/machines/BoltsDown.ogg' - var/is_special = 0 - -/obj/machinery/door/airlock/command - name = "Airlock" - icon = 'icons/obj/doors/Doorcom.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_com - -/obj/machinery/door/airlock/security - name = "Airlock" - icon = 'icons/obj/doors/Doorsec.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_sec - -/obj/machinery/door/airlock/engineering - name = "Airlock" - icon = 'icons/obj/doors/Dooreng.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_eng - -/obj/machinery/door/airlock/medical - name = "Airlock" - icon = 'icons/obj/doors/Doormed.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_med - -/obj/machinery/door/airlock/maintenance - name = "Maintenance Access" - icon = 'icons/obj/doors/Doormaint.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_mai - -/obj/machinery/door/airlock/external - name = "External Airlock" - icon = 'icons/obj/doors/Doorext.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_ext - -/obj/machinery/door/airlock/glass - name = "Glass Airlock" - icon = 'icons/obj/doors/Doorglass.dmi' - opacity = 0 - glass = 1 - doorOpen = 'sound/machines/windowdoor.ogg' - doorClose = 'sound/machines/windowdoor.ogg' - -/obj/machinery/door/airlock/centcom - name = "Airlock" - icon = 'icons/obj/doors/Doorele.dmi' - opacity = 0 - -/obj/machinery/door/airlock/vault - name = "Vault" - icon = 'icons/obj/doors/vault.dmi' - opacity = 1 - assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity //Until somebody makes better sprites. - explosion_block = 2 - -/obj/machinery/door/airlock/freezer - name = "Freezer Airlock" - icon = 'icons/obj/doors/Doorfreezer.dmi' - opacity = 1 - assembly_type = /obj/structure/door_assembly/door_assembly_fre - -/obj/machinery/door/airlock/hatch - name = "Airtight Hatch" - icon = 'icons/obj/doors/Doorhatchele.dmi' - opacity = 1 - assembly_type = /obj/structure/door_assembly/door_assembly_hatch - -/obj/machinery/door/airlock/hatch/gamma - name = "Gamma Level Hatch" - hackProof = 1 - aiControlDisabled = 1 - unacidable = 1 - is_special = 1 - -/obj/machinery/door/airlock/maintenance_hatch - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorhatchmaint2.dmi' - opacity = 1 - assembly_type = /obj/structure/door_assembly/door_assembly_mhatch - -/obj/machinery/door/airlock/glass_command - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorcomglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_com - glass = 1 - -/obj/machinery/door/airlock/glass_engineering - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorengglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_eng - glass = 1 - -/obj/machinery/door/airlock/glass_security - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorsecglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_sec - glass = 1 - -/obj/machinery/door/airlock/glass_medical - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doormedglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_med - glass = 1 - -/obj/machinery/door/airlock/mining - name = "Mining Airlock" - icon = 'icons/obj/doors/Doormining.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_min - -/obj/machinery/door/airlock/atmos - name = "Atmospherics Airlock" - icon = 'icons/obj/doors/Dooratmo.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_atmo - -/obj/machinery/door/airlock/research - name = "Airlock" - icon = 'icons/obj/doors/Doorresearch.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_research - -/obj/machinery/door/airlock/glass_research - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorresearchglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_research - glass = 1 - heat_proof = 1 - -/obj/machinery/door/airlock/glass_mining - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Doorminingglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_min - glass = 1 - -/obj/machinery/door/airlock/glass_atmos - name = "Maintenance Hatch" - icon = 'icons/obj/doors/Dooratmoglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_atmo - glass = 1 - -/obj/machinery/door/airlock/gold - name = "Gold Airlock" - icon = 'icons/obj/doors/Doorgold.dmi' - mineral = "gold" - -/obj/machinery/door/airlock/silver - name = "Silver Airlock" - icon = 'icons/obj/doors/Doorsilver.dmi' - mineral = "silver" - -/obj/machinery/door/airlock/diamond - name = "Diamond Airlock" - icon = 'icons/obj/doors/Doordiamond.dmi' - mineral = "diamond" - -/obj/machinery/door/airlock/uranium - name = "Uranium Airlock" - desc = "And they said I was crazy." - icon = 'icons/obj/doors/Dooruranium.dmi' - mineral = "uranium" - var/event_step = 20 - -/obj/machinery/door/airlock/uranium/New() - ..() - addtimer(src, "radiate", event_step) - -/obj/machinery/door/airlock/uranium/proc/radiate() - if(prob(50)) - for(var/mob/living/L in range (3,src)) - L.apply_effect(15,IRRADIATE,0) - addtimer(src, "radiate", event_step) - -/obj/machinery/door/airlock/plasma - name = "plasma airlock" - desc = "No way this can end badly." - icon = 'icons/obj/doors/Doorplasma.dmi' - mineral = "plasma" - -/obj/machinery/door/airlock/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(exposed_temperature > 300) - PlasmaBurn(exposed_temperature) - -/obj/machinery/door/airlock/plasma/proc/ignite(exposed_temperature) - if(exposed_temperature > 300) - PlasmaBurn(exposed_temperature) - -/obj/machinery/door/airlock/plasma/proc/PlasmaBurn(temperature) - atmos_spawn_air(SPAWN_HEAT | SPAWN_TOXINS, 500) - new/obj/structure/door_assembly( src.loc ) - qdel(src) - -/obj/machinery/door/airlock/plasma/BlockSuperconductivity() //we don't stop the heat~ - return 0 - -/obj/machinery/door/airlock/bananium - name = "Bananium Airlock" - icon = 'icons/obj/doors/Doorbananium.dmi' - mineral = "bananium" - doorOpen = 'sound/items/bikehorn.ogg' - doorClose = 'sound/items/bikehorn.ogg' - -/obj/machinery/door/airlock/tranquillite - name = "Tranquillite Airlock" - icon = 'icons/obj/doors/Doorfreezer.dmi' - mineral = "tranquillite" - doorOpen = null - doorClose = null - -/obj/machinery/door/airlock/sandstone - name = "Sandstone Airlock" - icon = 'icons/obj/doors/Doorsand.dmi' - mineral = "sandstone" - -/obj/machinery/door/airlock/science - name = "Airlock" - icon = 'icons/obj/doors/Doorsci.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_science - -/obj/machinery/door/airlock/glass_science - name = "Glass Airlocks" - icon = 'icons/obj/doors/Doorsciglass.dmi' - opacity = 0 - assembly_type = /obj/structure/door_assembly/door_assembly_science - glass = 1 - -/obj/machinery/door/airlock/highsecurity - name = "High Tech Security Airlock" - icon = 'icons/obj/doors/hightechsecurity.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity - explosion_block = 2 - -/obj/machinery/door/airlock/highsecurity/red - name = "Secure Armory Airlock" - hackProof = 1 - aiControlDisabled = 1 - -/obj/machinery/door/airlock/shuttle - name = "shuttle airlock" - icon = 'icons/obj/doors/doorshuttle.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_shuttle - -/obj/machinery/door/airlock/alien - name = "Alien Airlock" - desc = "A mysterious alien airlock with a complicated opening mechanism." - hackProof = 1 - icon = 'icons/obj/doors/Doorplasma.dmi' - is_special = 1 - -/obj/machinery/door/airlock/alien/bumpopen(mob/living/user as mob) - if(istype(user,/mob/living/carbon/alien) || isrobot(user) || isAI(user)) - ..(user) - else - to_chat(user, "You do not know how to operate this airlock's mechanism.") - return - -/obj/machinery/door/airlock/alien/attackby(C as obj, mob/user as mob, params) - if(isalien(user) || isrobot(user) || isAI(user)) - ..(C, user) - else - to_chat(user, "You do not know how to operate this airlock's mechanism.") - return - - -/* -About the new airlock wires panel: -* An airlock wire dialog can be accessed by the normal way or by using wirecutters or a multitool on the door while the wire-panel is open. This would show the following wires, which you can either wirecut/mend or send a multitool pulse through. There are 9 wires. -* one wire from the ID scanner. Sending a pulse through this flashes the red light on the door (if the door has power). If you cut this wire, the door will stop recognizing valid IDs. (If the door has 0000 access, it still opens and closes, though) -* two wires for power. Sending a pulse through either one causes a breaker to trip, disabling the door for 10 seconds if backup power is connected, or 1 minute if not (or until backup power comes back on, whichever is shorter). Cutting either one disables the main door power, but unless backup power is also cut, the backup power re-powers the door in 10 seconds. While unpowered, the door may be \red open, but bolts-raising will not work. Cutting these wires may electrocute the user. -* one wire for door bolts. Sending a pulse through this drops door bolts (whether the door is powered or not) or raises them (if it is). Cutting this wire also drops the door bolts, and mending it does not raise them. If the wire is cut, trying to raise the door bolts will not work. -* two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter). Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user. -* one wire for opening the door. Sending a pulse through this while the door has power makes it open the door if no access is required. -* one wire for AI control. Sending a pulse through this blocks AI control for a second or so (which is enough to see the AI control light on the panel dialog go off and back on again). Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all. -* one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds. Cutting this wire electrifies the door, so that the next person to touch the door without insulated gloves gets electrocuted. (Currently it is also STAYING electrified until someone mends the wire) -* one wire for controling door safetys. When active, door does not close on someone. When cut, door will ruin someone's shit. When pulsed, door will immedately ruin someone's shit. -* one wire for controlling door speed. When active, dor closes at normal rate. When cut, door does not close manually. When pulsed, door attempts to close every tick. -*/ -// You can find code for the airlock wires in the wire datum folder. - - -/obj/machinery/door/airlock/Destroy() - qdel(wires) - wires = null - if(main_power_timer) - deltimer(main_power_timer) - main_power_timer = null - if(backup_power_timer) - deltimer(backup_power_timer) - backup_power_timer = null - if(electrified_timer) - deltimer(electrified_timer) - electrified_timer = null - return ..() - -/obj/machinery/door/airlock/bumpopen(mob/living/user as mob) //Airlocks now zap you when you 'bump' them open when they're electrified. --NeoFite - if(!issilicon(usr)) - if(src.isElectrified()) - if(!src.justzap) - if(src.shock(user, 100)) - src.justzap = 1 - spawn (10) - src.justzap = 0 - return - else /*if(src.justzap)*/ - return - else if(user.hallucination > 50 && prob(10) && src.operating == 0) - to_chat(user, "You feel a powerful shock course through your body!") - user.adjustStaminaLoss(50) - user.AdjustStunned(5) - return - ..(user) - -/obj/machinery/door/airlock/bumpopen(mob/living/simple_animal/user as mob) - ..(user) - - -/obj/machinery/door/airlock/autoclose() - autoclose_timer = 0 - if(!qdeleted(src) && !density && !operating && !locked && !welded && autoclose) - close() - return - -/obj/machinery/door/airlock/proc/isElectrified() - if(src.electrified_until != 0) - return 1 - return 0 - -/obj/machinery/door/airlock/proc/isWireCut(var/wireIndex) - // You can find the wires in the datum folder. - return wires.IsIndexCut(wireIndex) - -/obj/machinery/door/airlock/proc/canAIControl() - return ((src.aiControlDisabled!=1) && (!src.isAllPowerLoss())); - -/obj/machinery/door/airlock/proc/canAIHack() - return ((src.aiControlDisabled==1) && (!hackProof) && (!src.isAllPowerLoss())); - -/obj/machinery/door/airlock/proc/arePowerSystemsOn() - if(stat & (NOPOWER|BROKEN)) - return 0 - return (src.main_power_lost_until==0 || src.backup_power_lost_until==0) - -/obj/machinery/door/airlock/requiresID() - return !(src.isWireCut(AIRLOCK_WIRE_IDSCAN) || aiDisabledIdScanner) - -/obj/machinery/door/airlock/proc/isAllPowerLoss() - if(stat & (NOPOWER|BROKEN)) - return 1 - if(mainPowerCablesCut() && backupPowerCablesCut()) - return 1 - return 0 - -/obj/machinery/door/airlock/proc/mainPowerCablesCut() - return src.isWireCut(AIRLOCK_WIRE_MAIN_POWER1) || src.isWireCut(AIRLOCK_WIRE_MAIN_POWER2) - -/obj/machinery/door/airlock/proc/backupPowerCablesCut() - return src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER1) || src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER2) - -/obj/machinery/door/airlock/proc/loseMainPower() - main_power_lost_until = mainPowerCablesCut() ? -1 : world.time + SecondsToTicks(60) - if(main_power_lost_until > 0) - main_power_timer = addtimer(src, "regainMainPower", SecondsToTicks(60), 1) - - // If backup power is permanently disabled then activate in 10 seconds if possible, otherwise it's already enabled or a timer is already running - if(backup_power_lost_until == -1 && !backupPowerCablesCut()) - backup_power_lost_until = world.time + SecondsToTicks(10) - backup_power_timer = addtimer(src, "regainBackupPower", SecondsToTicks(10), 1) - - // Disable electricity if required - if(electrified_until && isAllPowerLoss()) - electrify(0) - -/obj/machinery/door/airlock/proc/loseBackupPower() - backup_power_lost_until = backupPowerCablesCut() ? -1 : world.time + SecondsToTicks(60) - if(backup_power_lost_until > 0) - backup_power_timer = addtimer(src, "regainBackupPower", SecondsToTicks(60), 1) - - // Disable electricity if required - if(electrified_until && isAllPowerLoss()) - electrify(0) - -/obj/machinery/door/airlock/proc/regainMainPower() - main_power_timer = null - - if(!mainPowerCablesCut()) - main_power_lost_until = 0 - // If backup power is currently active then disable, otherwise let it count down and disable itself later - if(!backup_power_lost_until) - backup_power_lost_until = -1 - update_icon() - -/obj/machinery/door/airlock/proc/regainBackupPower() - backup_power_timer = null - - if(!backupPowerCablesCut()) - // Restore backup power only if main power is offline, otherwise permanently disable - backup_power_lost_until = main_power_lost_until == 0 ? -1 : 0 - update_icon() - -/obj/machinery/door/airlock/proc/electrify(var/duration, var/feedback = 0) - if(electrified_timer) - deltimer(electrified_timer) - electrified_timer = null - - var/message = "" - if(isWireCut(AIRLOCK_WIRE_ELECTRIFY) && arePowerSystemsOn()) - message = text("The electrification wire is cut - Door permanently electrified.") - electrified_until = -1 - else if(duration && !arePowerSystemsOn()) - message = text("The door is unpowered - Cannot electrify the door.") - electrified_until = 0 - else if(!duration && electrified_until != 0) - message = "The door is now un-electrified." - electrified_until = 0 - else if(duration) //electrify door for the given duration seconds - if(usr) - shockedby += text("\[[time_stamp()]\] - [usr](ckey:[usr.ckey])") - usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") - else - shockedby += text("\[[time_stamp()]\] - EMP)") - message = "The door is now electrified [duration == -1 ? "permanently" : "for [duration] second\s"]." - electrified_until = duration == -1 ? -1 : world.time + SecondsToTicks(duration) - if(duration != -1) - electrified_timer = addtimer(src, "electrify", SecondsToTicks(duration), 1, 0) - - if(feedback && message) - to_chat(usr, message) - -// shock user with probability prb (if all connections & power are working) -// returns 1 if shocked, 0 otherwise -// The preceding comment was borrowed from the grille's shock script -/obj/machinery/door/airlock/shock(mob/user, prb) - if(!arePowerSystemsOn()) - return 0 - if(hasShocked) - return 0 //Already shocked someone recently? - if(..()) - hasShocked = 1 - sleep(10) - hasShocked = 0 - return 1 - else - return 0 - -/obj/machinery/door/airlock/update_icon() - if(overlays) overlays.Cut() - overlays = list() - if(emergency && arePowerSystemsOn()) - overlays += image('icons/obj/doors/doorint.dmi', "elights") - if(density) - if(locked && lights) - icon_state = "door_locked" - else - icon_state = "door_closed" - if(p_open || welded || frozen) - if(p_open) - overlays += image(icon, "panel_open") - if(welded) - overlays += image(icon, "welded") - if(frozen) - overlays += image(icon, "frozen") - - else - icon_state = "door_open" - - return - - -/obj/machinery/door/airlock/do_animate(animation) - switch(animation) - if("opening") - if(overlays) overlays.Cut() - if(p_open) - spawn(2) // The only work around that works. Downside is that the door will be gone for a millisecond. - flick("o_door_opening", src) //can not use flick due to BYOND bug updating overlays right before flicking - update_icon() - else - flick("door_opening", src)//[stat ? "_stat":] - update_icon() - if("closing") - if(overlays) overlays.Cut() - if(p_open) - spawn(2) - flick("o_door_closing", src) - update_icon() - else - flick("door_closing", src) - update_icon() - if("spark") - if(density) - flick("door_spark", src) - if("deny") - if(density && src.arePowerSystemsOn()) - playsound(src, doorDeni, 50, 0, 3) - flick("door_deny", src) - return - -/obj/machinery/door/airlock/attack_ai(mob/user as mob) - ui_interact(user) - -/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "door_control.tmpl", "Door Controls - [src]", 600, 375) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/door/airlock/ui_data(mob/user, datum/topic_state/state = default_state) - var/data[0] - - data["main_power_loss"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1) - data["backup_power_loss"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1) - data["electrified"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1) - data["open"] = !density - - var/commands[0] - commands[++commands.len] = list("name" = "IdScan", "command"= "idscan", "active" = !aiDisabledIdScanner,"enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) - commands[++commands.len] = list("name" = "Bolts", "command"= "bolts", "active" = !locked, "enabled" = "Raised", "disabled" = "Dropped", "danger" = 0, "act" = 0) - commands[++commands.len] = list("name" = "Bolt Lights", "command"= "lights", "active" = lights, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) - commands[++commands.len] = list("name" = "Safeties", "command"= "safeties", "active" = safe, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) - commands[++commands.len] = list("name" = "Timing", "command"= "timing", "active" = normalspeed, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) - commands[++commands.len] = list("name" = "Door State", "command"= "open", "active" = density, "enabled" = "Closed", "disabled" = "Opened", "danger" = 0, "act" = 0) - commands[++commands.len] = list("name" = "Emergency Access","command"= "emergency", "active" = !emergency, "enabled" = "Disabled", "disabled" = "Enabled", "danger" = 0, "act" = 0) - - data["commands"] = commands - return data - -/obj/machinery/door/airlock/proc/hack(mob/user as mob) - if(src.aiHacking==0) - src.aiHacking=1 - spawn(20) - //TODO: Make this take a minute - to_chat(user, "Airlock AI control has been blocked. Beginning fault-detection.") - sleep(50) - if(src.canAIControl()) - to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") - src.aiHacking=0 - return - else if(!src.canAIHack(user)) - to_chat(user, "We've lost our connection! Unable to hack airlock.") - src.aiHacking=0 - return - to_chat(user, "Fault confirmed: airlock control wire disabled or cut.") - sleep(20) - to_chat(user, "Attempting to hack into airlock. This may take some time.") - sleep(200) - if(src.canAIControl()) - to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") - src.aiHacking=0 - return - else if(!src.canAIHack(user)) - to_chat(user, "We've lost our connection! Unable to hack airlock.") - src.aiHacking=0 - return - to_chat(user, "Upload access confirmed. Loading control program into airlock software.") - sleep(170) - if(src.canAIControl()) - to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") - src.aiHacking=0 - return - else if(!src.canAIHack(user)) - to_chat(user, "We've lost our connection! Unable to hack airlock.") - src.aiHacking=0 - return - to_chat(user, "Transfer complete. Forcing airlock to execute program.") - sleep(50) - //disable blocked control - src.aiControlDisabled = 2 - to_chat(user, "Receiving control information from airlock.") - sleep(10) - //bring up airlock dialog - src.aiHacking = 0 - if(user) - src.attack_ai(user) - -/obj/machinery/door/airlock/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(src.isElectrified()) - if(istype(mover, /obj/item)) - var/obj/item/i = mover - if(i.materials[MAT_METAL]) - var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() - return ..() - -/obj/machinery/door/airlock/attack_hand(mob/user as mob) - if(!istype(user, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 100)) - return - - if(ishuman(user) && prob(40) && src.density) - var/mob/living/carbon/human/H = user - if(H.getBrainLoss() >= 60) - playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) - if(!istype(H.head, /obj/item/clothing/head/helmet)) - visible_message("\red [user] headbutts the airlock.") - var/obj/item/organ/external/affecting = H.get_organ("head") - H.Stun(5) - H.Weaken(5) - if(affecting.take_damage(10, 0)) - H.UpdateDamageIcon() - else - visible_message("\red [user] headbutts the airlock. Good thing they're wearing a helmet.") - return - - if(src.p_open) - wires.Interact(user) - else - ..(user) - return - -/obj/machinery/door/airlock/CanUseTopic(var/mob/user) - if(!issilicon(user)) - return STATUS_CLOSE - - if(operating < 0) //emagged - to_chat(user, "Unable to interface: Internal error.") - return STATUS_CLOSE - if(!src.canAIControl()) - if(src.canAIHack(user)) - src.hack(user) - else - if(src.isAllPowerLoss()) //don't really like how this gets checked a second time, but not sure how else to do it. - to_chat(user, "Unable to interface: Connection timed out.") - else - to_chat(user, "Unable to interface: Connection refused.") - return STATUS_CLOSE - - return ..() - -/obj/machinery/door/airlock/Topic(href, href_list, var/nowindow = 0) - if(..()) - return 1 - - var/activate = text2num(href_list["activate"]) - switch(href_list["command"]) - if("idscan") - if(src.isWireCut(AIRLOCK_WIRE_IDSCAN)) - to_chat(usr, "The IdScan wire has been cut - IdScan feature permanently disabled.") - else if(activate && src.aiDisabledIdScanner) - src.aiDisabledIdScanner = 0 - to_chat(usr, "IdScan feature has been enabled.") - else if(!activate && !src.aiDisabledIdScanner) - src.aiDisabledIdScanner = 1 - to_chat(usr, "IdScan feature has been disabled.") - if("main_power") - if(!main_power_lost_until) - src.loseMainPower() - if("backup_power") - if(!backup_power_lost_until) - src.loseBackupPower() - if("bolts") - if(src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) - to_chat(usr, "The door bolt control wire has been cut - Door bolts permanently dropped.") - else if(activate && src.lock()) - to_chat(usr, "The door bolts have been dropped.") - else if(!activate && src.unlock()) - to_chat(usr, "The door bolts have been raised.") - if("electrify_temporary") - if(activate && src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) - to_chat(usr, text("The electrification wire is cut - Door permanently electrified.")) - else if(!activate && electrified_until != 0) - to_chat(usr, "The door is now un-electrified.") - electrify(0) - else if(activate) //electrify door for 30 seconds - shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])") - usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") - to_chat(usr, "The door is now electrified for thirty seconds.") - electrify(30) - if("electrify_permanently") - if(src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) - to_chat(usr, text("The electrification wire is cut - Cannot electrify the door.")) - else if(!activate && electrified_until != 0) - to_chat(usr, "The door is now un-electrified.") - electrify(0) - else if(activate) - shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])") - usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") - to_chat(usr, "The door is now electrified.") - electrify(-1) - if("open") - if(src.welded) - to_chat(usr, text("The airlock has been welded shut!")) - else if(src.locked) - to_chat(usr, text("The door bolts are down!")) - else if(activate && density) - open() - else if(!activate && !density) - close() - if("safeties") - // Safeties! We don't need no stinking safeties! - if(src.isWireCut(AIRLOCK_WIRE_SAFETY)) - to_chat(usr, text("The safety wire is cut - Cannot secure the door.")) - else if(activate && src.safe) - safe = 0 - else if(!activate && !src.safe) - safe = 1 - if("timing") - // Door speed control - if(src.isWireCut(AIRLOCK_WIRE_SPEED)) - to_chat(usr, text("The timing wire is cut - Cannot alter timing.")) - else if(activate && src.normalspeed) - normalspeed = 0 - else if(!activate && !src.normalspeed) - normalspeed = 1 - if("lights") - // Bolt lights - if(src.isWireCut(AIRLOCK_WIRE_LIGHT)) - to_chat(usr, "The bolt lights wire has been cut - The door bolt lights are permanently disabled.") - else if(!activate && src.lights) - lights = 0 - to_chat(usr, "The door bolt lights have been disabled.") - else if(activate && !src.lights) - lights = 1 - to_chat(usr, "The door bolt lights have been enabled.") - if("emergency") - // Emergency access - if(src.emergency) - emergency = 0 - to_chat(usr, "Emergency access has been disabled.") - else - emergency = 1 - to_chat(usr, "Emergency access has been enabled.") - - update_icon() - return 1 - -/obj/machinery/door/airlock/attackby(C as obj, mob/user as mob, params) -// to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) - if(!istype(usr, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 75)) - return - if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) - return - - src.add_fingerprint(user) - if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating ) && src.density)) - var/obj/item/weapon/weldingtool/W = C - if(W.remove_fuel(0,user)) - if(frozen) - frozen = 0 - if(!src.welded) - src.welded = 1 - else - src.welded = null - src.update_icon() - return - else - return - else if(istype(C, /obj/item/weapon/screwdriver)) - src.p_open = !( src.p_open ) - src.update_icon() - else if(istype(C, /obj/item/weapon/wirecutters)) - return src.attack_hand(user) - else if(istype(C, /obj/item/device/multitool)) - return src.attack_hand(user) - else if(istype(C, /obj/item/device/assembly/signaler)) - return src.attack_hand(user) - else if(istype(C, /obj/item/weapon/pai_cable)) // -- TLE - var/obj/item/weapon/pai_cable/cable = C - cable.plugin(src, user) - else if(istype(C, /obj/item/weapon/crowbar) || istype(C, /obj/item/weapon/twohanded/fireaxe) ) - var/beingcrowbarred = null - if(istype(C, /obj/item/weapon/crowbar) ) - beingcrowbarred = 1 //derp, Agouri - else - beingcrowbarred = 0 - if( beingcrowbarred && src.p_open && (operating == -1 || (density && welded && operating != 1 && !src.arePowerSystemsOn() && !src.locked)) ) - playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) - user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove electronics from the airlock assembly.") - if(do_after(user,40, target = src)) - to_chat(user, "\blue You removed the airlock electronics!") - - var/obj/structure/door_assembly/da = new assembly_type(src.loc) - da.anchored = 1 - if(mineral) - da.glass = mineral - //else if(glass) - else if(glass && !da.glass) - da.glass = 1 - da.state = 1 - da.created_name = src.name - da.update_state() - - var/obj/item/weapon/airlock_electronics/ae - if(!electronics) - ae = new/obj/item/weapon/airlock_electronics( src.loc ) - if(!src.req_access) - src.check_access() - if(src.req_access.len) - ae.conf_access = src.req_access - else if(src.req_one_access.len) - ae.conf_access = src.req_one_access - ae.one_access = 1 - else - ae = electronics - electronics = null - ae.loc = src.loc - if(operating == -1) - ae.icon_state = "door_electronics_smoked" - operating = 0 - - qdel(src) - return - else if(arePowerSystemsOn()) - to_chat(user, "\blue The airlock's motors resist your efforts to force it.") - else if(locked) - to_chat(user, "\blue The airlock's bolts prevent it from being forced.") - else if( !welded && !operating ) - if(density) - if(beingcrowbarred == 0) //being fireaxe'd - var/obj/item/weapon/twohanded/fireaxe/F = C - if(F.wielded) - spawn(0) open(1) - else - to_chat(user, "\red You need to be wielding \the [C] to do that.") - else - spawn(0) open(1) - else - if(beingcrowbarred == 0) - var/obj/item/weapon/twohanded/fireaxe/F = C - if(F.wielded) - spawn(0) close(1) - else - to_chat(user, "\red You need to be wielding \the [C] to do that.") - else - spawn(0) close(1) - else - ..() - return - -/obj/machinery/door/airlock/plasma/attackby(C as obj, mob/user as mob, params) - if(is_hot(C) > 300) - message_admins("Plasma airlock ignited by [key_name_admin(user)] in ([x],[y],[z] - JMP)") - log_game("Plasma wall ignited by [key_name(user)] in ([x],[y],[z])") - ignite(is_hot(C)) - ..() - -/obj/machinery/door/airlock/open(var/forced=0) - if( operating || welded || locked ) - return 0 - if(!forced) - if( !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR) ) - return 0 - use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people - if(forced) - playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) - else - playsound(src.loc, doorOpen, 30, 1) - if(src.closeOther != null && istype(src.closeOther, /obj/machinery/door/airlock/) && !src.closeOther.density) - src.closeOther.close() - return ..() - -/obj/machinery/door/airlock/close(var/forced=0, var/override = 0) - if((operating & !override) || welded || locked) - return - if(!forced) - //despite the name, this wire is for general door control. - //Bolts are already covered by the check for locked, above - if( !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR) ) - return - if(safe) - for(var/turf/turf in locs) - if(locate(/mob/living) in turf) - // playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) //THE BUZZING IT NEVER STOPS -Pete - spawn (60) - autoclose() - return - - use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people - if(forced) - playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) - else - playsound(src.loc, doorClose, 30, 1) - var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src)) - if(killthis) - killthis.ex_act(2)//Smashin windows - - if(density) - return 1 - operating = 1 - do_animate("closing") - src.layer = 3.1 - if(!override) sleep(5) - src.density = 1 - if(!safe) - crush() - if(!override) sleep(5) - update_icon() - if(visible && !glass) - set_opacity(1) - operating = 0 - air_update_turf(1) - update_freelook_sight() - if(safe) - if(locate(/mob/living) in get_turf(src)) - open() - - return - -/obj/machinery/door/airlock/proc/lock(var/forced=0) - if(locked) - return 0 - - if(operating && !forced) return 0 - - src.locked = 1 - playsound(src, boltDown, 30, 0, 3) - update_icon() - return 1 - -/obj/machinery/door/airlock/proc/unlock(var/forced=0) - if(!src.locked) - return - - if(!forced) - if(operating || !src.arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) return - - src.locked = 0 - playsound(src,boltUp, 30, 0, 3) - update_icon() - return 1 - -/obj/machinery/door/airlock/New() - ..() - wires = new(src) - if(src.closeOtherId != null) - spawn (5) - for(var/obj/machinery/door/airlock/A in airlocks) - if(A.closeOtherId == src.closeOtherId && A != src) - src.closeOther = A - break - if(frozen) - welded = 1 - update_icon() - -/obj/machinery/door/airlock/hatch/gamma/attackby(C as obj, mob/user as mob, params) -// to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) - if(!istype(usr, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 75)) - return - if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) - return - - if(istype(C, /obj/item/weapon/grenade/plastic/c4)) - to_chat(user, "The hatch is coated with a product that prevents the shaped charge from sticking!") - return - - if(istype(C, /obj/item/mecha_parts/mecha_equipment/rcd) || istype(C, /obj/item/weapon/rcd)) - to_chat(user, "The hatch is made of an advanced compound that cannot be deconstructed using an RCD.") - return - - src.add_fingerprint(user) - if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density)) - var/obj/item/weapon/weldingtool/W = C - if(W.remove_fuel(0,user)) - if(frozen) - frozen = 0 - if(!src.welded) - src.welded = 1 - else - src.welded = null - src.update_icon() - return - else - return - - -/obj/machinery/door/airlock/highsecurity/red/attackby(C as obj, mob/user as mob, params) -// to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) - if(!istype(usr, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 75)) - return - if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) - return - - src.add_fingerprint(user) - if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density)) - var/obj/item/weapon/weldingtool/W = C - if(W.remove_fuel(0,user)) - if(frozen) - frozen = 0 - if(!src.welded) - src.welded = 1 - else - src.welded = null - src.update_icon() - return - else - return - -/obj/machinery/door/airlock/CanAStarPass(var/obj/item/weapon/card/id/ID) -//Airlock is passable if it is open (!density), bot has access, and is not bolted shut) - return !density || (check_access(ID) && !locked && arePowerSystemsOn()) - -/obj/machinery/door/airlock/emp_act(var/severity) - if(prob(40/severity)) - var/duration = world.time + SecondsToTicks(30 / severity) - if(duration > electrified_until) - electrify(duration) - ..() - -/obj/machinery/door/airlock/power_change() //putting this is obj/machinery/door itself makes non-airlock doors turn invisible for some reason - ..() - if(stat & NOPOWER) - // If we lost power, disable electrification - // Keeping door lights on, runs on internal battery or something. - electrified_until = 0 - update_icon() - -/obj/machinery/door/airlock/proc/prison_open() - if(arePowerSystemsOn()) - src.unlock() - src.open() - src.lock() - -/obj/machinery/door/airlock/hostile_lockdown(mob/origin) - // Must be powered and have working AI wire. - if(canAIControl(src) && !stat) - locked = FALSE //For airlocks that were bolted open. - safe = FALSE //DOOR CRUSH - close() - lock() //Bolt it! - electrified_until = -1 //Shock it! - if(origin) - shockedby += "\[[time_stamp()]\][origin](ckey:[origin.ckey])" - - -/obj/machinery/door/airlock/disable_lockdown() - // Must be powered and have working AI wire. - if(canAIControl(src) && !stat) - unlock() - electrified_until = 0 - open() - safe = TRUE - -////////////////////////////////// -/* - Cult Airlocks -*/ - -/obj/machinery/door/airlock/cult - name = "cult airlock" - icon = 'icons/obj/doors/doorcult.dmi' - assembly_type = /obj/structure/door_assembly/door_assembly_cult - hackProof = 1 - aiControlDisabled = 1 - var/friendly = FALSE - -/obj/machinery/door/airlock/cult/New() - ..() - -/obj/machinery/door/airlock/cult/canAIControl(mob/user) - return (iscultist(user)) - -/obj/machinery/door/airlock/cult/allowed(mob/M) - if(!density) - return 1 - if(friendly || \ - iscultist(M) || \ - istype(M, /mob/living/simple_animal/shade) || \ - istype(M, /mob/living/simple_animal/construct)) - return 1 - else - var/atom/throwtarget - throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(M, src))) - M << pick(sound('sound/hallucinations/turn_around1.ogg',0,1,50), sound('sound/hallucinations/turn_around2.ogg',0,1,50)) - M.Weaken(2) - spawn(0) - M.throw_at(throwtarget, 5, 1,src) - return 0 - -/obj/machinery/door/airlock/cult/narsie_act() - return - -/obj/machinery/door/airlock/cult/friendly - friendly = TRUE +/* + New methods: + pulse - sends a pulse into a wire for hacking purposes + cut - cuts a wire and makes any necessary state changes + mend - mends a wire and makes any necessary state changes + canAIControl - 1 if the AI can control the airlock, 0 if not (then check canAIHack to see if it can hack in) + canAIHack - 1 if the AI can hack into the airlock to recover control, 0 if not. Also returns 0 if the AI does not *need* to hack it. + arePowerSystemsOn - 1 if the main or backup power are functioning, 0 if not. Does not check whether the power grid is charged or an APC has equipment on or anything like that. (Check (stat & NOPOWER) for that) + requiresIDs - 1 if the airlock is requiring IDs, 0 if not + isAllPowerCut - 1 if the main and backup power both have cut wires. + regainMainPower - handles the effect of main power coming back on. + loseMainPower - handles the effect of main power going offline. Usually (if one isn't already running) spawn a thread to count down how long it will be offline - counting down won't happen if main power was completely cut along with backup power, though, the thread will just sleep. + loseBackupPower - handles the effect of backup power going offline. + regainBackupPower - handles the effect of main power coming back on. + shock - has a chance of electrocuting its target. +*/ + + +// Wires for the airlock are located in the datum folder, inside the wires datum folder. + + +/obj/machinery/door/airlock + name = "airlock" + icon = 'icons/obj/doors/Doorint.dmi' + icon_state = "door_closed" + power_channel = ENVIRON + + var/aiControlDisabled = 0 //If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in. + var/hackProof = 0 // if 1, this door can't be hacked by the AI + var/electrified_until = 0 // World time when the door is no longer electrified. -1 if it is permanently electrified until someone fixes it. + var/main_power_lost_until = 0 //World time when main power is restored. + var/backup_power_lost_until = -1 //World time when backup power is restored. + var/electrified_timer = null + var/main_power_timer = null + var/backup_power_timer = null + var/spawnPowerRestoreRunning = 0 + var/welded = null + var/locked = 0 + var/lights = 1 // bolt lights show by default + var/datum/wires/airlock/wires = null + var/aiDisabledIdScanner = 0 + var/aiHacking = 0 + var/obj/machinery/door/airlock/closeOther = null + var/closeOtherId = null + var/lockdownbyai = 0 + var/assembly_type = /obj/structure/door_assembly + var/mineral = null + var/justzap = 0 + var/safe = 1 + normalspeed = 1 + var/obj/item/weapon/airlock_electronics/electronics = null + var/hasShocked = 0 //Prevents multiple shocks from happening + var/frozen = 0 //special condition for airlocks that are frozen shut, this will look weird on not normal airlocks because of a lack of special overlays. + autoclose = 1 + explosion_block = 1 + var/doorOpen = 'sound/machines/airlock.ogg' + var/doorClose = 'sound/machines/airlock.ogg' + var/doorDeni = 'sound/machines/DeniedBeep.ogg' // i'm thinkin' Deni's + var/boltUp = 'sound/machines/BoltsUp.ogg' + var/boltDown = 'sound/machines/BoltsDown.ogg' + var/is_special = 0 + +/obj/machinery/door/airlock/command + name = "Airlock" + icon = 'icons/obj/doors/Doorcom.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_com + +/obj/machinery/door/airlock/security + name = "Airlock" + icon = 'icons/obj/doors/Doorsec.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_sec + +/obj/machinery/door/airlock/engineering + name = "Airlock" + icon = 'icons/obj/doors/Dooreng.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_eng + +/obj/machinery/door/airlock/medical + name = "Airlock" + icon = 'icons/obj/doors/Doormed.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_med + +/obj/machinery/door/airlock/maintenance + name = "Maintenance Access" + icon = 'icons/obj/doors/Doormaint.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_mai + +/obj/machinery/door/airlock/external + name = "External Airlock" + icon = 'icons/obj/doors/Doorext.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_ext + +/obj/machinery/door/airlock/glass + name = "Glass Airlock" + icon = 'icons/obj/doors/Doorglass.dmi' + opacity = 0 + glass = 1 + doorOpen = 'sound/machines/windowdoor.ogg' + doorClose = 'sound/machines/windowdoor.ogg' + +/obj/machinery/door/airlock/centcom + name = "Airlock" + icon = 'icons/obj/doors/Doorele.dmi' + opacity = 0 + +/obj/machinery/door/airlock/vault + name = "Vault" + icon = 'icons/obj/doors/vault.dmi' + opacity = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity //Until somebody makes better sprites. + explosion_block = 2 + +/obj/machinery/door/airlock/freezer + name = "Freezer Airlock" + icon = 'icons/obj/doors/Doorfreezer.dmi' + opacity = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_fre + +/obj/machinery/door/airlock/hatch + name = "Airtight Hatch" + icon = 'icons/obj/doors/Doorhatchele.dmi' + opacity = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_hatch + +/obj/machinery/door/airlock/hatch/gamma + name = "Gamma Level Hatch" + hackProof = 1 + aiControlDisabled = 1 + unacidable = 1 + is_special = 1 + +/obj/machinery/door/airlock/maintenance_hatch + name = "Maintenance Hatch" + icon = 'icons/obj/doors/Doorhatchmaint2.dmi' + opacity = 1 + assembly_type = /obj/structure/door_assembly/door_assembly_mhatch + +/obj/machinery/door/airlock/glass_command + name = "Maintenance Hatch" + icon = 'icons/obj/doors/Doorcomglass.dmi' + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_com + glass = 1 + +/obj/machinery/door/airlock/glass_engineering + name = "Maintenance Hatch" + icon = 'icons/obj/doors/Doorengglass.dmi' + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_eng + glass = 1 + +/obj/machinery/door/airlock/glass_security + name = "Maintenance Hatch" + icon = 'icons/obj/doors/Doorsecglass.dmi' + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_sec + glass = 1 + +/obj/machinery/door/airlock/glass_medical + name = "Maintenance Hatch" + icon = 'icons/obj/doors/Doormedglass.dmi' + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_med + glass = 1 + +/obj/machinery/door/airlock/mining + name = "Mining Airlock" + icon = 'icons/obj/doors/Doormining.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_min + +/obj/machinery/door/airlock/atmos + name = "Atmospherics Airlock" + icon = 'icons/obj/doors/Dooratmo.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_atmo + +/obj/machinery/door/airlock/research + name = "Airlock" + icon = 'icons/obj/doors/Doorresearch.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_research + +/obj/machinery/door/airlock/glass_research + name = "Maintenance Hatch" + icon = 'icons/obj/doors/Doorresearchglass.dmi' + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_research + glass = 1 + heat_proof = 1 + +/obj/machinery/door/airlock/glass_mining + name = "Maintenance Hatch" + icon = 'icons/obj/doors/Doorminingglass.dmi' + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_min + glass = 1 + +/obj/machinery/door/airlock/glass_atmos + name = "Maintenance Hatch" + icon = 'icons/obj/doors/Dooratmoglass.dmi' + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_atmo + glass = 1 + +/obj/machinery/door/airlock/gold + name = "Gold Airlock" + icon = 'icons/obj/doors/Doorgold.dmi' + mineral = "gold" + +/obj/machinery/door/airlock/silver + name = "Silver Airlock" + icon = 'icons/obj/doors/Doorsilver.dmi' + mineral = "silver" + +/obj/machinery/door/airlock/diamond + name = "Diamond Airlock" + icon = 'icons/obj/doors/Doordiamond.dmi' + mineral = "diamond" + +/obj/machinery/door/airlock/uranium + name = "Uranium Airlock" + desc = "And they said I was crazy." + icon = 'icons/obj/doors/Dooruranium.dmi' + mineral = "uranium" + var/event_step = 20 + +/obj/machinery/door/airlock/uranium/New() + ..() + addtimer(src, "radiate", event_step) + +/obj/machinery/door/airlock/uranium/proc/radiate() + if(prob(50)) + for(var/mob/living/L in range (3,src)) + L.apply_effect(15,IRRADIATE,0) + addtimer(src, "radiate", event_step) + +/obj/machinery/door/airlock/plasma + name = "plasma airlock" + desc = "No way this can end badly." + icon = 'icons/obj/doors/Doorplasma.dmi' + mineral = "plasma" + +/obj/machinery/door/airlock/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > 300) + PlasmaBurn(exposed_temperature) + +/obj/machinery/door/airlock/plasma/proc/ignite(exposed_temperature) + if(exposed_temperature > 300) + PlasmaBurn(exposed_temperature) + +/obj/machinery/door/airlock/plasma/proc/PlasmaBurn(temperature) + atmos_spawn_air(SPAWN_HEAT | SPAWN_TOXINS, 500) + new/obj/structure/door_assembly( src.loc ) + qdel(src) + +/obj/machinery/door/airlock/plasma/BlockSuperconductivity() //we don't stop the heat~ + return 0 + +/obj/machinery/door/airlock/bananium + name = "Bananium Airlock" + icon = 'icons/obj/doors/Doorbananium.dmi' + mineral = "bananium" + doorOpen = 'sound/items/bikehorn.ogg' + doorClose = 'sound/items/bikehorn.ogg' + +/obj/machinery/door/airlock/tranquillite + name = "Tranquillite Airlock" + icon = 'icons/obj/doors/Doorfreezer.dmi' + mineral = "tranquillite" + doorOpen = null + doorClose = null + +/obj/machinery/door/airlock/sandstone + name = "Sandstone Airlock" + icon = 'icons/obj/doors/Doorsand.dmi' + mineral = "sandstone" + +/obj/machinery/door/airlock/science + name = "Airlock" + icon = 'icons/obj/doors/Doorsci.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_science + +/obj/machinery/door/airlock/glass_science + name = "Glass Airlocks" + icon = 'icons/obj/doors/Doorsciglass.dmi' + opacity = 0 + assembly_type = /obj/structure/door_assembly/door_assembly_science + glass = 1 + +/obj/machinery/door/airlock/highsecurity + name = "High Tech Security Airlock" + icon = 'icons/obj/doors/hightechsecurity.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity + explosion_block = 2 + +/obj/machinery/door/airlock/highsecurity/red + name = "Secure Armory Airlock" + hackProof = 1 + aiControlDisabled = 1 + +/obj/machinery/door/airlock/shuttle + name = "shuttle airlock" + icon = 'icons/obj/doors/doorshuttle.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_shuttle + +/obj/machinery/door/airlock/alien + name = "Alien Airlock" + desc = "A mysterious alien airlock with a complicated opening mechanism." + hackProof = 1 + icon = 'icons/obj/doors/Doorplasma.dmi' + is_special = 1 + +/obj/machinery/door/airlock/alien/bumpopen(mob/living/user as mob) + if(istype(user,/mob/living/carbon/alien) || isrobot(user) || isAI(user)) + ..(user) + else + to_chat(user, "You do not know how to operate this airlock's mechanism.") + return + +/obj/machinery/door/airlock/alien/attackby(C as obj, mob/user as mob, params) + if(isalien(user) || isrobot(user) || isAI(user)) + ..(C, user) + else + to_chat(user, "You do not know how to operate this airlock's mechanism.") + return + + +/* +About the new airlock wires panel: +* An airlock wire dialog can be accessed by the normal way or by using wirecutters or a multitool on the door while the wire-panel is open. This would show the following wires, which you can either wirecut/mend or send a multitool pulse through. There are 9 wires. +* one wire from the ID scanner. Sending a pulse through this flashes the red light on the door (if the door has power). If you cut this wire, the door will stop recognizing valid IDs. (If the door has 0000 access, it still opens and closes, though) +* two wires for power. Sending a pulse through either one causes a breaker to trip, disabling the door for 10 seconds if backup power is connected, or 1 minute if not (or until backup power comes back on, whichever is shorter). Cutting either one disables the main door power, but unless backup power is also cut, the backup power re-powers the door in 10 seconds. While unpowered, the door may be \red open, but bolts-raising will not work. Cutting these wires may electrocute the user. +* one wire for door bolts. Sending a pulse through this drops door bolts (whether the door is powered or not) or raises them (if it is). Cutting this wire also drops the door bolts, and mending it does not raise them. If the wire is cut, trying to raise the door bolts will not work. +* two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter). Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user. +* one wire for opening the door. Sending a pulse through this while the door has power makes it open the door if no access is required. +* one wire for AI control. Sending a pulse through this blocks AI control for a second or so (which is enough to see the AI control light on the panel dialog go off and back on again). Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all. +* one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds. Cutting this wire electrifies the door, so that the next person to touch the door without insulated gloves gets electrocuted. (Currently it is also STAYING electrified until someone mends the wire) +* one wire for controling door safetys. When active, door does not close on someone. When cut, door will ruin someone's shit. When pulsed, door will immedately ruin someone's shit. +* one wire for controlling door speed. When active, dor closes at normal rate. When cut, door does not close manually. When pulsed, door attempts to close every tick. +*/ +// You can find code for the airlock wires in the wire datum folder. + + +/obj/machinery/door/airlock/Destroy() + qdel(wires) + wires = null + if(main_power_timer) + deltimer(main_power_timer) + main_power_timer = null + if(backup_power_timer) + deltimer(backup_power_timer) + backup_power_timer = null + if(electrified_timer) + deltimer(electrified_timer) + electrified_timer = null + return ..() + +/obj/machinery/door/airlock/bumpopen(mob/living/user as mob) //Airlocks now zap you when you 'bump' them open when they're electrified. --NeoFite + if(!issilicon(usr)) + if(src.isElectrified()) + if(!src.justzap) + if(src.shock(user, 100)) + src.justzap = 1 + spawn (10) + src.justzap = 0 + return + else /*if(src.justzap)*/ + return + else if(user.hallucination > 50 && prob(10) && src.operating == 0) + to_chat(user, "You feel a powerful shock course through your body!") + user.adjustStaminaLoss(50) + user.AdjustStunned(5) + return + ..(user) + +/obj/machinery/door/airlock/bumpopen(mob/living/simple_animal/user as mob) + ..(user) + + +/obj/machinery/door/airlock/autoclose() + autoclose_timer = 0 + if(!qdeleted(src) && !density && !operating && !locked && !welded && autoclose) + close() + return + +/obj/machinery/door/airlock/proc/isElectrified() + if(src.electrified_until != 0) + return 1 + return 0 + +/obj/machinery/door/airlock/proc/isWireCut(var/wireIndex) + // You can find the wires in the datum folder. + return wires.IsIndexCut(wireIndex) + +/obj/machinery/door/airlock/proc/canAIControl() + return ((src.aiControlDisabled!=1) && (!src.isAllPowerLoss())); + +/obj/machinery/door/airlock/proc/canAIHack() + return ((src.aiControlDisabled==1) && (!hackProof) && (!src.isAllPowerLoss())); + +/obj/machinery/door/airlock/proc/arePowerSystemsOn() + if(stat & (NOPOWER|BROKEN)) + return 0 + return (src.main_power_lost_until==0 || src.backup_power_lost_until==0) + +/obj/machinery/door/airlock/requiresID() + return !(src.isWireCut(AIRLOCK_WIRE_IDSCAN) || aiDisabledIdScanner) + +/obj/machinery/door/airlock/proc/isAllPowerLoss() + if(stat & (NOPOWER|BROKEN)) + return 1 + if(mainPowerCablesCut() && backupPowerCablesCut()) + return 1 + return 0 + +/obj/machinery/door/airlock/proc/mainPowerCablesCut() + return src.isWireCut(AIRLOCK_WIRE_MAIN_POWER1) || src.isWireCut(AIRLOCK_WIRE_MAIN_POWER2) + +/obj/machinery/door/airlock/proc/backupPowerCablesCut() + return src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER1) || src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER2) + +/obj/machinery/door/airlock/proc/loseMainPower() + main_power_lost_until = mainPowerCablesCut() ? -1 : world.time + SecondsToTicks(60) + if(main_power_lost_until > 0) + main_power_timer = addtimer(src, "regainMainPower", SecondsToTicks(60), 1) + + // If backup power is permanently disabled then activate in 10 seconds if possible, otherwise it's already enabled or a timer is already running + if(backup_power_lost_until == -1 && !backupPowerCablesCut()) + backup_power_lost_until = world.time + SecondsToTicks(10) + backup_power_timer = addtimer(src, "regainBackupPower", SecondsToTicks(10), 1) + + // Disable electricity if required + if(electrified_until && isAllPowerLoss()) + electrify(0) + +/obj/machinery/door/airlock/proc/loseBackupPower() + backup_power_lost_until = backupPowerCablesCut() ? -1 : world.time + SecondsToTicks(60) + if(backup_power_lost_until > 0) + backup_power_timer = addtimer(src, "regainBackupPower", SecondsToTicks(60), 1) + + // Disable electricity if required + if(electrified_until && isAllPowerLoss()) + electrify(0) + +/obj/machinery/door/airlock/proc/regainMainPower() + main_power_timer = null + + if(!mainPowerCablesCut()) + main_power_lost_until = 0 + // If backup power is currently active then disable, otherwise let it count down and disable itself later + if(!backup_power_lost_until) + backup_power_lost_until = -1 + update_icon() + +/obj/machinery/door/airlock/proc/regainBackupPower() + backup_power_timer = null + + if(!backupPowerCablesCut()) + // Restore backup power only if main power is offline, otherwise permanently disable + backup_power_lost_until = main_power_lost_until == 0 ? -1 : 0 + update_icon() + +/obj/machinery/door/airlock/proc/electrify(var/duration, var/feedback = 0) + if(electrified_timer) + deltimer(electrified_timer) + electrified_timer = null + + var/message = "" + if(isWireCut(AIRLOCK_WIRE_ELECTRIFY) && arePowerSystemsOn()) + message = text("The electrification wire is cut - Door permanently electrified.") + electrified_until = -1 + else if(duration && !arePowerSystemsOn()) + message = text("The door is unpowered - Cannot electrify the door.") + electrified_until = 0 + else if(!duration && electrified_until != 0) + message = "The door is now un-electrified." + electrified_until = 0 + else if(duration) //electrify door for the given duration seconds + if(usr) + shockedby += text("\[[time_stamp()]\] - [usr](ckey:[usr.ckey])") + usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") + else + shockedby += text("\[[time_stamp()]\] - EMP)") + message = "The door is now electrified [duration == -1 ? "permanently" : "for [duration] second\s"]." + electrified_until = duration == -1 ? -1 : world.time + SecondsToTicks(duration) + if(duration != -1) + electrified_timer = addtimer(src, "electrify", SecondsToTicks(duration), 1, 0) + + if(feedback && message) + to_chat(usr, message) + +// shock user with probability prb (if all connections & power are working) +// returns 1 if shocked, 0 otherwise +// The preceding comment was borrowed from the grille's shock script +/obj/machinery/door/airlock/shock(mob/user, prb) + if(!arePowerSystemsOn()) + return 0 + if(hasShocked) + return 0 //Already shocked someone recently? + if(..()) + hasShocked = 1 + sleep(10) + hasShocked = 0 + return 1 + else + return 0 + +/obj/machinery/door/airlock/update_icon() + if(overlays) overlays.Cut() + overlays = list() + if(emergency && arePowerSystemsOn()) + overlays += image('icons/obj/doors/doorint.dmi', "elights") + if(density) + if(locked && lights) + icon_state = "door_locked" + else + icon_state = "door_closed" + if(p_open || welded || frozen) + if(p_open) + overlays += image(icon, "panel_open") + if(welded) + overlays += image(icon, "welded") + if(frozen) + overlays += image(icon, "frozen") + + else + icon_state = "door_open" + + return + + +/obj/machinery/door/airlock/do_animate(animation) + switch(animation) + if("opening") + if(overlays) overlays.Cut() + if(p_open) + spawn(2) // The only work around that works. Downside is that the door will be gone for a millisecond. + flick("o_door_opening", src) //can not use flick due to BYOND bug updating overlays right before flicking + update_icon() + else + flick("door_opening", src)//[stat ? "_stat":] + update_icon() + if("closing") + if(overlays) overlays.Cut() + if(p_open) + spawn(2) + flick("o_door_closing", src) + update_icon() + else + flick("door_closing", src) + update_icon() + if("spark") + if(density) + flick("door_spark", src) + if("deny") + if(density && src.arePowerSystemsOn()) + playsound(src, doorDeni, 50, 0, 3) + flick("door_deny", src) + return + +/obj/machinery/door/airlock/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "door_control.tmpl", "Door Controls - [src]", 600, 375) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/door/airlock/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "door_control.tmpl", "Door Controls - [src]", 600, 375) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/door/airlock/ui_data(mob/user, datum/topic_state/state = default_state) + var/data[0] + + data["main_power_loss"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1) + data["backup_power_loss"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1) + data["electrified"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1) + data["open"] = !density + + var/commands[0] + commands[++commands.len] = list("name" = "IdScan", "command"= "idscan", "active" = !aiDisabledIdScanner,"enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) + commands[++commands.len] = list("name" = "Bolts", "command"= "bolts", "active" = !locked, "enabled" = "Raised", "disabled" = "Dropped", "danger" = 0, "act" = 0) + commands[++commands.len] = list("name" = "Bolt Lights", "command"= "lights", "active" = lights, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) + commands[++commands.len] = list("name" = "Safeties", "command"= "safeties", "active" = safe, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) + commands[++commands.len] = list("name" = "Timing", "command"= "timing", "active" = normalspeed, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) + commands[++commands.len] = list("name" = "Door State", "command"= "open", "active" = density, "enabled" = "Closed", "disabled" = "Opened", "danger" = 0, "act" = 0) + commands[++commands.len] = list("name" = "Emergency Access","command"= "emergency", "active" = !emergency, "enabled" = "Disabled", "disabled" = "Enabled", "danger" = 0, "act" = 0) + + data["commands"] = commands + return data + +/obj/machinery/door/airlock/proc/hack(mob/user as mob) + if(src.aiHacking==0) + src.aiHacking=1 + spawn(20) + //TODO: Make this take a minute + to_chat(user, "Airlock AI control has been blocked. Beginning fault-detection.") + sleep(50) + if(src.canAIControl()) + to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") + src.aiHacking=0 + return + else if(!src.canAIHack(user)) + to_chat(user, "We've lost our connection! Unable to hack airlock.") + src.aiHacking=0 + return + to_chat(user, "Fault confirmed: airlock control wire disabled or cut.") + sleep(20) + to_chat(user, "Attempting to hack into airlock. This may take some time.") + sleep(200) + if(src.canAIControl()) + to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") + src.aiHacking=0 + return + else if(!src.canAIHack(user)) + to_chat(user, "We've lost our connection! Unable to hack airlock.") + src.aiHacking=0 + return + to_chat(user, "Upload access confirmed. Loading control program into airlock software.") + sleep(170) + if(src.canAIControl()) + to_chat(user, "Alert cancelled. Airlock control has been restored without our assistance.") + src.aiHacking=0 + return + else if(!src.canAIHack(user)) + to_chat(user, "We've lost our connection! Unable to hack airlock.") + src.aiHacking=0 + return + to_chat(user, "Transfer complete. Forcing airlock to execute program.") + sleep(50) + //disable blocked control + src.aiControlDisabled = 2 + to_chat(user, "Receiving control information from airlock.") + sleep(10) + //bring up airlock dialog + src.aiHacking = 0 + if(user) + src.attack_ai(user) + +/obj/machinery/door/airlock/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(src.isElectrified()) + if(istype(mover, /obj/item)) + var/obj/item/i = mover + if(i.materials[MAT_METAL]) + var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + return ..() + +/obj/machinery/door/airlock/attack_hand(mob/user as mob) + if(!istype(user, /mob/living/silicon)) + if(src.isElectrified()) + if(src.shock(user, 100)) + return + + if(ishuman(user) && prob(40) && src.density) + var/mob/living/carbon/human/H = user + if(H.getBrainLoss() >= 60) + playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) + if(!istype(H.head, /obj/item/clothing/head/helmet)) + visible_message("\red [user] headbutts the airlock.") + var/obj/item/organ/external/affecting = H.get_organ("head") + H.Stun(5) + H.Weaken(5) + if(affecting.take_damage(10, 0)) + H.UpdateDamageIcon() + else + visible_message("\red [user] headbutts the airlock. Good thing they're wearing a helmet.") + return + + if(src.p_open) + wires.Interact(user) + else + ..(user) + return + +/obj/machinery/door/airlock/CanUseTopic(var/mob/user) + if(!issilicon(user)) + return STATUS_CLOSE + + if(operating < 0) //emagged + to_chat(user, "Unable to interface: Internal error.") + return STATUS_CLOSE + if(!src.canAIControl()) + if(src.canAIHack(user)) + src.hack(user) + else + if(src.isAllPowerLoss()) //don't really like how this gets checked a second time, but not sure how else to do it. + to_chat(user, "Unable to interface: Connection timed out.") + else + to_chat(user, "Unable to interface: Connection refused.") + return STATUS_CLOSE + + return ..() + +/obj/machinery/door/airlock/Topic(href, href_list, var/nowindow = 0) + if(..()) + return 1 + + var/activate = text2num(href_list["activate"]) + switch(href_list["command"]) + if("idscan") + if(src.isWireCut(AIRLOCK_WIRE_IDSCAN)) + to_chat(usr, "The IdScan wire has been cut - IdScan feature permanently disabled.") + else if(activate && src.aiDisabledIdScanner) + src.aiDisabledIdScanner = 0 + to_chat(usr, "IdScan feature has been enabled.") + else if(!activate && !src.aiDisabledIdScanner) + src.aiDisabledIdScanner = 1 + to_chat(usr, "IdScan feature has been disabled.") + if("main_power") + if(!main_power_lost_until) + src.loseMainPower() + if("backup_power") + if(!backup_power_lost_until) + src.loseBackupPower() + if("bolts") + if(src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) + to_chat(usr, "The door bolt control wire has been cut - Door bolts permanently dropped.") + else if(activate && src.lock()) + to_chat(usr, "The door bolts have been dropped.") + else if(!activate && src.unlock()) + to_chat(usr, "The door bolts have been raised.") + if("electrify_temporary") + if(activate && src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) + to_chat(usr, text("The electrification wire is cut - Door permanently electrified.")) + else if(!activate && electrified_until != 0) + to_chat(usr, "The door is now un-electrified.") + electrify(0) + else if(activate) //electrify door for 30 seconds + shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])") + usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") + to_chat(usr, "The door is now electrified for thirty seconds.") + electrify(30) + if("electrify_permanently") + if(src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) + to_chat(usr, text("The electrification wire is cut - Cannot electrify the door.")) + else if(!activate && electrified_until != 0) + to_chat(usr, "The door is now un-electrified.") + electrify(0) + else if(activate) + shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])") + usr.attack_log += text("\[[time_stamp()]\] Electrified the [name] at [x] [y] [z]") + to_chat(usr, "The door is now electrified.") + electrify(-1) + if("open") + if(src.welded) + to_chat(usr, text("The airlock has been welded shut!")) + else if(src.locked) + to_chat(usr, text("The door bolts are down!")) + else if(activate && density) + open() + else if(!activate && !density) + close() + if("safeties") + // Safeties! We don't need no stinking safeties! + if(src.isWireCut(AIRLOCK_WIRE_SAFETY)) + to_chat(usr, text("The safety wire is cut - Cannot secure the door.")) + else if(activate && src.safe) + safe = 0 + else if(!activate && !src.safe) + safe = 1 + if("timing") + // Door speed control + if(src.isWireCut(AIRLOCK_WIRE_SPEED)) + to_chat(usr, text("The timing wire is cut - Cannot alter timing.")) + else if(activate && src.normalspeed) + normalspeed = 0 + else if(!activate && !src.normalspeed) + normalspeed = 1 + if("lights") + // Bolt lights + if(src.isWireCut(AIRLOCK_WIRE_LIGHT)) + to_chat(usr, "The bolt lights wire has been cut - The door bolt lights are permanently disabled.") + else if(!activate && src.lights) + lights = 0 + to_chat(usr, "The door bolt lights have been disabled.") + else if(activate && !src.lights) + lights = 1 + to_chat(usr, "The door bolt lights have been enabled.") + if("emergency") + // Emergency access + if(src.emergency) + emergency = 0 + to_chat(usr, "Emergency access has been disabled.") + else + emergency = 1 + to_chat(usr, "Emergency access has been enabled.") + + update_icon() + return 1 + +/obj/machinery/door/airlock/attackby(C as obj, mob/user as mob, params) +// to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) + if(!istype(usr, /mob/living/silicon)) + if(src.isElectrified()) + if(src.shock(user, 75)) + return + if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) + return + + src.add_fingerprint(user) + if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating ) && src.density)) + var/obj/item/weapon/weldingtool/W = C + if(W.remove_fuel(0,user)) + if(frozen) + frozen = 0 + if(!src.welded) + src.welded = 1 + else + src.welded = null + src.update_icon() + return + else + return + else if(istype(C, /obj/item/weapon/screwdriver)) + src.p_open = !( src.p_open ) + src.update_icon() + else if(istype(C, /obj/item/weapon/wirecutters)) + return src.attack_hand(user) + else if(istype(C, /obj/item/device/multitool)) + return src.attack_hand(user) + else if(istype(C, /obj/item/device/assembly/signaler)) + return src.attack_hand(user) + else if(istype(C, /obj/item/weapon/pai_cable)) // -- TLE + var/obj/item/weapon/pai_cable/cable = C + cable.plugin(src, user) + else if(istype(C, /obj/item/weapon/crowbar) || istype(C, /obj/item/weapon/twohanded/fireaxe) ) + var/beingcrowbarred = null + if(istype(C, /obj/item/weapon/crowbar) ) + beingcrowbarred = 1 //derp, Agouri + else + beingcrowbarred = 0 + if( beingcrowbarred && src.p_open && (operating == -1 || (density && welded && operating != 1 && !src.arePowerSystemsOn() && !src.locked)) ) + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove electronics from the airlock assembly.") + if(do_after(user,40, target = src)) + to_chat(user, "\blue You removed the airlock electronics!") + + var/obj/structure/door_assembly/da = new assembly_type(src.loc) + da.anchored = 1 + if(mineral) + da.glass = mineral + //else if(glass) + else if(glass && !da.glass) + da.glass = 1 + da.state = 1 + da.created_name = src.name + da.update_state() + + var/obj/item/weapon/airlock_electronics/ae + if(!electronics) + ae = new/obj/item/weapon/airlock_electronics( src.loc ) + if(!src.req_access) + src.check_access() + if(src.req_access.len) + ae.conf_access = src.req_access + else if(src.req_one_access.len) + ae.conf_access = src.req_one_access + ae.one_access = 1 + else + ae = electronics + electronics = null + ae.loc = src.loc + if(operating == -1) + ae.icon_state = "door_electronics_smoked" + operating = 0 + + qdel(src) + return + else if(arePowerSystemsOn()) + to_chat(user, "\blue The airlock's motors resist your efforts to force it.") + else if(locked) + to_chat(user, "\blue The airlock's bolts prevent it from being forced.") + else if( !welded && !operating ) + if(density) + if(beingcrowbarred == 0) //being fireaxe'd + var/obj/item/weapon/twohanded/fireaxe/F = C + if(F.wielded) + spawn(0) open(1) + else + to_chat(user, "\red You need to be wielding \the [C] to do that.") + else + spawn(0) open(1) + else + if(beingcrowbarred == 0) + var/obj/item/weapon/twohanded/fireaxe/F = C + if(F.wielded) + spawn(0) close(1) + else + to_chat(user, "\red You need to be wielding \the [C] to do that.") + else + spawn(0) close(1) + else + ..() + return + +/obj/machinery/door/airlock/plasma/attackby(C as obj, mob/user as mob, params) + if(is_hot(C) > 300) + message_admins("Plasma airlock ignited by [key_name_admin(user)] in ([x],[y],[z] - JMP)") + log_game("Plasma wall ignited by [key_name(user)] in ([x],[y],[z])") + ignite(is_hot(C)) + ..() + +/obj/machinery/door/airlock/open(var/forced=0) + if( operating || welded || locked ) + return 0 + if(!forced) + if( !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR) ) + return 0 + use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people + if(forced) + playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) + else + playsound(src.loc, doorOpen, 30, 1) + if(src.closeOther != null && istype(src.closeOther, /obj/machinery/door/airlock/) && !src.closeOther.density) + src.closeOther.close() + return ..() + +/obj/machinery/door/airlock/close(var/forced=0, var/override = 0) + if((operating & !override) || welded || locked) + return + if(!forced) + //despite the name, this wire is for general door control. + //Bolts are already covered by the check for locked, above + if( !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR) ) + return + if(safe) + for(var/turf/turf in locs) + if(locate(/mob/living) in turf) + // playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) //THE BUZZING IT NEVER STOPS -Pete + spawn (60) + autoclose() + return + + use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people + if(forced) + playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) + else + playsound(src.loc, doorClose, 30, 1) + var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src)) + if(killthis) + killthis.ex_act(2)//Smashin windows + + if(density) + return 1 + operating = 1 + do_animate("closing") + src.layer = 3.1 + if(!override) sleep(5) + src.density = 1 + if(!safe) + crush() + if(!override) sleep(5) + update_icon() + if(visible && !glass) + set_opacity(1) + operating = 0 + air_update_turf(1) + update_freelook_sight() + if(safe) + if(locate(/mob/living) in get_turf(src)) + open() + + return + +/obj/machinery/door/airlock/proc/lock(var/forced=0) + if(locked) + return 0 + + if(operating && !forced) return 0 + + src.locked = 1 + playsound(src, boltDown, 30, 0, 3) + update_icon() + return 1 + +/obj/machinery/door/airlock/proc/unlock(var/forced=0) + if(!src.locked) + return + + if(!forced) + if(operating || !src.arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) return + + src.locked = 0 + playsound(src,boltUp, 30, 0, 3) + update_icon() + return 1 + +/obj/machinery/door/airlock/New() + ..() + wires = new(src) + if(src.closeOtherId != null) + spawn (5) + for(var/obj/machinery/door/airlock/A in airlocks) + if(A.closeOtherId == src.closeOtherId && A != src) + src.closeOther = A + break + if(frozen) + welded = 1 + update_icon() + +/obj/machinery/door/airlock/hatch/gamma/attackby(C as obj, mob/user as mob, params) +// to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) + if(!istype(usr, /mob/living/silicon)) + if(src.isElectrified()) + if(src.shock(user, 75)) + return + if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) + return + + if(istype(C, /obj/item/weapon/grenade/plastic/c4)) + to_chat(user, "The hatch is coated with a product that prevents the shaped charge from sticking!") + return + + if(istype(C, /obj/item/mecha_parts/mecha_equipment/rcd) || istype(C, /obj/item/weapon/rcd)) + to_chat(user, "The hatch is made of an advanced compound that cannot be deconstructed using an RCD.") + return + + src.add_fingerprint(user) + if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density)) + var/obj/item/weapon/weldingtool/W = C + if(W.remove_fuel(0,user)) + if(frozen) + frozen = 0 + if(!src.welded) + src.welded = 1 + else + src.welded = null + src.update_icon() + return + else + return + + +/obj/machinery/door/airlock/highsecurity/red/attackby(C as obj, mob/user as mob, params) +// to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) + if(!istype(usr, /mob/living/silicon)) + if(src.isElectrified()) + if(src.shock(user, 75)) + return + if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) + return + + src.add_fingerprint(user) + if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density)) + var/obj/item/weapon/weldingtool/W = C + if(W.remove_fuel(0,user)) + if(frozen) + frozen = 0 + if(!src.welded) + src.welded = 1 + else + src.welded = null + src.update_icon() + return + else + return + +/obj/machinery/door/airlock/CanAStarPass(var/obj/item/weapon/card/id/ID) +//Airlock is passable if it is open (!density), bot has access, and is not bolted shut) + return !density || (check_access(ID) && !locked && arePowerSystemsOn()) + +/obj/machinery/door/airlock/emp_act(var/severity) + if(prob(40/severity)) + var/duration = world.time + SecondsToTicks(30 / severity) + if(duration > electrified_until) + electrify(duration) + ..() + +/obj/machinery/door/airlock/power_change() //putting this is obj/machinery/door itself makes non-airlock doors turn invisible for some reason + ..() + if(stat & NOPOWER) + // If we lost power, disable electrification + // Keeping door lights on, runs on internal battery or something. + electrified_until = 0 + update_icon() + +/obj/machinery/door/airlock/proc/prison_open() + if(arePowerSystemsOn()) + src.unlock() + src.open() + src.lock() + +/obj/machinery/door/airlock/hostile_lockdown(mob/origin) + // Must be powered and have working AI wire. + if(canAIControl(src) && !stat) + locked = FALSE //For airlocks that were bolted open. + safe = FALSE //DOOR CRUSH + close() + lock() //Bolt it! + electrified_until = -1 //Shock it! + if(origin) + shockedby += "\[[time_stamp()]\][origin](ckey:[origin.ckey])" + + +/obj/machinery/door/airlock/disable_lockdown() + // Must be powered and have working AI wire. + if(canAIControl(src) && !stat) + unlock() + electrified_until = 0 + open() + safe = TRUE + +////////////////////////////////// +/* + Cult Airlocks +*/ + +/obj/machinery/door/airlock/cult + name = "cult airlock" + icon = 'icons/obj/doors/doorcult.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_cult + hackProof = 1 + aiControlDisabled = 1 + var/friendly = FALSE + +/obj/machinery/door/airlock/cult/New() + ..() + +/obj/machinery/door/airlock/cult/canAIControl(mob/user) + return (iscultist(user)) + +/obj/machinery/door/airlock/cult/allowed(mob/M) + if(!density) + return 1 + if(friendly || \ + iscultist(M) || \ + istype(M, /mob/living/simple_animal/shade) || \ + istype(M, /mob/living/simple_animal/construct)) + return 1 + else + var/atom/throwtarget + throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(M, src))) + M << pick(sound('sound/hallucinations/turn_around1.ogg',0,1,50), sound('sound/hallucinations/turn_around2.ogg',0,1,50)) + M.Weaken(2) + spawn(0) + M.throw_at(throwtarget, 5, 1,src) + return 0 + +/obj/machinery/door/airlock/cult/narsie_act() + return + +/obj/machinery/door/airlock/cult/friendly + friendly = TRUE diff --git a/code/game/machinery/embedded_controller/airlock_controllers.dm b/code/game/machinery/embedded_controller/airlock_controllers.dm index d9be59bde59..99b5189e206 100644 --- a/code/game/machinery/embedded_controller/airlock_controllers.dm +++ b/code/game/machinery/embedded_controller/airlock_controllers.dm @@ -27,7 +27,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data = list( @@ -83,7 +83,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/embedded_controller/radio/airlock/airlock_controller/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/embedded_controller/radio/airlock/airlock_controller/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data = list( @@ -146,7 +146,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/embedded_controller/radio/airlock/access_controller/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/embedded_controller/radio/airlock/access_controller/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data = list( diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index b1f7d33244d..3e77a7548b3 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -180,7 +180,7 @@ FIRE ALARM ui.open() ui.set_auto_update(1) -/obj/machinery/firealarm/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/firealarm/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/area/A = get_area(src) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 519a7177d7a..60ce5e32a34 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -154,7 +154,7 @@ Class Procs: if(use_power && stat == 0) use_power(7500/severity) - new/obj/effect/overlay/temp/emp(src.loc) + new/obj/effect/overlay/temp/emp(loc) ..() /obj/machinery/ex_act(severity) @@ -184,9 +184,9 @@ Class Procs: /obj/machinery/proc/auto_use_power() if(!powered(power_channel)) return 0 - if(src.use_power == 1) + if(use_power == 1) use_power(idle_power_usage,power_channel, 1) - else if(src.use_power >= 2) + else if(use_power >= 2) use_power(active_power_usage,power_channel, 1) return 1 @@ -229,7 +229,7 @@ Class Procs: if(!(href_list["set_tag"] in vars)) to_chat(usr, "Something went wrong: Unable to find [href_list["set_tag"]] in vars!") return 1 - var/current_tag = src.vars[href_list["set_tag"]] + var/current_tag = vars[href_list["set_tag"]] var/newid = copytext(reject_bad_text(input(usr, "Specify the new value", src, current_tag) as null|text),1,MAX_MESSAGE_LEN) if(newid) vars[href_list["set_tag"]] = newid @@ -355,13 +355,13 @@ Class Procs: return 1 if(panel_open) - src.add_fingerprint(user) + add_fingerprint(user) return 0 if(!interact_offline && stat & (NOPOWER|BROKEN|MAINT)) return 1 - src.add_fingerprint(user) + add_fingerprint(user) return ..() @@ -379,8 +379,8 @@ Class Procs: /obj/machinery/proc/default_deconstruction_crowbar(var/obj/item/weapon/crowbar/C, var/ignore_panel = 0) if(istype(C) && (panel_open || ignore_panel)) - playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) - var/obj/machinery/constructable_frame/machine_frame/M = new /obj/machinery/constructable_frame/machine_frame(src.loc) + playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) + var/obj/machinery/constructable_frame/machine_frame/M = new /obj/machinery/constructable_frame/machine_frame(loc) M.state = 2 M.icon_state = "box_1" for(var/obj/item/I in component_parts) @@ -393,7 +393,7 @@ Class Procs: /obj/machinery/proc/default_deconstruction_screwdriver(var/mob/user, var/icon_state_open, var/icon_state_closed, var/obj/item/weapon/screwdriver/S) if(istype(S)) - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) if(!panel_open) panel_open = 1 icon_state = icon_state_open @@ -407,7 +407,7 @@ Class Procs: /obj/machinery/proc/default_change_direction_wrench(var/mob/user, var/obj/item/weapon/wrench/W) if(panel_open && istype(W)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) dir = turn(dir,-90) to_chat(user, "You rotate [src].") return 1 @@ -416,11 +416,14 @@ Class Procs: /obj/proc/default_unfasten_wrench(mob/user, obj/item/weapon/wrench/W, time = 20) if(istype(W)) to_chat(user, "Now [anchored ? "un" : ""]securing [name].") - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) if(do_after(user, time, target = src)) to_chat(user, "You've [anchored ? "un" : ""]secured [name].") anchored = !anchored - playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + if(istype(src, /obj/machinery)) + var/obj/machinery/M = src + M.power_change() //Turn on or off the machine depending on the status of power in the new area. + playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) return 1 return 0 @@ -506,7 +509,7 @@ Class Procs: if(check_access && !allowed(perp)) threatcount += 4 - if(auth_weapons && !src.allowed(perp)) + if(auth_weapons && !allowed(perp)) if(istype(perp.l_hand, /obj/item/weapon/gun) || istype(perp.l_hand, /obj/item/weapon/melee)) threatcount += 4 diff --git a/code/game/machinery/poolcontroller.dm b/code/game/machinery/poolcontroller.dm index 80f5e8be5d7..db60adb5c9a 100644 --- a/code/game/machinery/poolcontroller.dm +++ b/code/game/machinery/poolcontroller.dm @@ -135,7 +135,7 @@ ui = new(user, src, ui_key, "poolcontroller.tmpl", "Pool Controller Interface", 520, 410) ui.open() -/obj/machinery/poolcontroller/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/poolcontroller/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["currentTemp"] = temperature diff --git a/code/game/machinery/portable_tag_turret.dm b/code/game/machinery/portable_tag_turret.dm index de78d46178f..1944da8f071 100644 --- a/code/game/machinery/portable_tag_turret.dm +++ b/code/game/machinery/portable_tag_turret.dm @@ -49,7 +49,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/porta_turret/tag/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/porta_turret/tag/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["access"] = !isLocked(user) data["locked"] = locked diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 5832e41a4f5..cc9347b4bdb 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -206,7 +206,7 @@ var/list/turret_icons ui.open() ui.set_auto_update(1) -/obj/machinery/porta_turret/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/porta_turret/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["access"] = !isLocked(user) data["screen"] = screen diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 9de1806852f..704da886685 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -115,7 +115,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() ui.open() ui.set_auto_update(1) -/obj/machinery/requests_console/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/requests_console/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["department"] = department diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm index c72e987cd92..1c6dcf6322e 100644 --- a/code/game/machinery/slotmachine.dm +++ b/code/game/machinery/slotmachine.dm @@ -28,7 +28,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/slot_machine/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/slot_machine/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["working"] = working diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index 44a3181b8b9..7449f731f11 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -285,14 +285,14 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* --- Loop through the receivers and categorize them --- */ - if(R.client && R.client.holder && !(R.client.prefs.toggles & CHAT_RADIO)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios. + if(is_admin(R) && !R.get_preference(CHAT_RADIO)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios. continue if(istype(R, /mob/new_player)) // we don't want new players to hear messages. rare but generates runtimes. continue // Ghosts hearing all radio chat don't want to hear syndicate intercepts, they're duplicates - if(data == 3 && istype(R, /mob/dead/observer) && R.client && (R.client.prefs.toggles & CHAT_GHOSTRADIO)) + if(data == 3 && istype(R, /mob/dead/observer) && R.get_preference(CHAT_GHOSTRADIO)) continue // --- Check for compression --- @@ -495,7 +495,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* --- Loop through the receivers and categorize them --- */ - if(R.client && !(R.client.prefs.toggles & CHAT_RADIO)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios. + if(R.client && !R.get_preference(CHAT_RADIO)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios. continue diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 0fec852c2f5..843002a804d 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -75,7 +75,7 @@ ui = new(user, src, ui_key, "teleporter_console.tmpl", "Teleporter Console UI", 400, 400) ui.open() -/obj/machinery/computer/teleporter/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/teleporter/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["powerstation"] = power_station if(power_station) diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm index eda38ee6120..21da8c4159c 100644 --- a/code/game/machinery/turret_control.dm +++ b/code/game/machinery/turret_control.dm @@ -125,7 +125,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/turretid/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/turretid/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["access"] = !isLocked(user) data["locked"] = locked diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index ed6a23998c4..4ec9471a36a 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -416,7 +416,7 @@ ui = new(user, src, ui_key, "vending_machine.tmpl", src.name, 440, 600) ui.open() -/obj/machinery/vending/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/vending/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/list/data = list() if(currently_vending) data["mode"] = 1 @@ -834,11 +834,11 @@ product_slogans = "Carts to go!" icon_state = "cart" icon_deny = "cart-deny" - products = list(/obj/item/device/pda =10,/obj/item/weapon/cartridge/medical = 10,/obj/item/weapon/cartridge/chemistry = 10, + products = list(/obj/item/device/pda =10,/obj/item/weapon/cartridge/mob_hunt_game = 25,/obj/item/weapon/cartridge/medical = 10,/obj/item/weapon/cartridge/chemistry = 10, /obj/item/weapon/cartridge/engineering = 10,/obj/item/weapon/cartridge/atmos = 10,/obj/item/weapon/cartridge/janitor = 10, /obj/item/weapon/cartridge/signal/toxins = 10,/obj/item/weapon/cartridge/signal = 10) contraband = list(/obj/item/weapon/cartridge/clown = 1,/obj/item/weapon/cartridge/mime = 1) - prices = list(/obj/item/device/pda =300,/obj/item/weapon/cartridge/medical = 200,/obj/item/weapon/cartridge/chemistry = 150,/obj/item/weapon/cartridge/engineering = 100, + prices = list(/obj/item/device/pda =300,/obj/item/weapon/cartridge/mob_hunt_game = 50,/obj/item/weapon/cartridge/medical = 200,/obj/item/weapon/cartridge/chemistry = 150,/obj/item/weapon/cartridge/engineering = 100, /obj/item/weapon/cartridge/atmos = 75,/obj/item/weapon/cartridge/janitor = 100,/obj/item/weapon/cartridge/signal/toxins = 150, /obj/item/weapon/cartridge/signal = 75) diff --git a/code/game/magic/Uristrunes.dm b/code/game/magic/Uristrunes.dm index df25e084d19..5cb7dc4127e 100644 --- a/code/game/magic/Uristrunes.dm +++ b/code/game/magic/Uristrunes.dm @@ -1,79 +1,36 @@ - -var/list/word_to_uristrune_table = null - -/proc/word_to_uristrune_bit(word) - if(word_to_uristrune_table == null) - word_to_uristrune_table = list() - - var/bit = 1 - var/list/words = list("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "mgar", "balaq", "karazet", "geeri") - - while(length(words)) - var/w = pick(words) - - word_to_uristrune_table[w] = bit - - words -= w - bit <<= 1 - - - return word_to_uristrune_table[word] - - - -/proc/get_uristrune_cult(word1, word2, word3) +/proc/get_rune_cult(word) var/animated - if((word1 == cultwords["travel"] && word2 == cultwords["self"]) \ - || (word1 == cultwords["join"] && word2 == cultwords["blood"] && word3 == cultwords["self"]) \ - || (word1 == cultwords["hell"] && word2 == cultwords["join"] && word3 == cultwords["self"]) \ - || (word1 == cultwords["see"] && word2 == cultwords["blood"] && word3 == cultwords["hell"]) \ - || (word1 == cultwords["destroy"] && word2 == cultwords["see"] && word3 == cultwords["technology"]) \ - || (word1 == cultwords["travel"] && word2 == cultwords["blood"] && word3 == cultwords["self"]) \ - || (word1 == cultwords["see"] && word2 == cultwords["hell"] && word3 == cultwords["join"]) \ - || (word1 == cultwords["blood"] && word2 == cultwords["join"] && word3 == cultwords["hell"]) \ - || (word1 == cultwords["hide"] && word2 == cultwords["see"] && word3 == cultwords["blood"]) \ - || (word1 == cultwords["hell"] && word2 == cultwords["travel"] && word3 == cultwords["self"]) \ - || (word1 == cultwords["blood"] && word2 == cultwords["see"] && word3 == cultwords["travel"]) \ - || (word1 == cultwords["hell"] && word2 == cultwords["technology"] && word3 == cultwords["join"]) \ - || (word1 == cultwords["hell"] && word2 == cultwords["blood"] && word3 == cultwords["join"]) \ - || (word1 == cultwords["blood"] && word2 == cultwords["see"] && word3 == cultwords["hide"]) \ - || (word1 == cultwords["destroy"] && word2 == cultwords["travel"] && word3 == cultwords["self"]) \ - || (word1 == cultwords["travel"] && word2 == cultwords["technology"] && word3 == cultwords["other"]) \ - || (word1 == cultwords["join"] && word2 == cultwords["other"] && word3 == cultwords["self"]) \ - || (word1 == cultwords["hide"] && word2 == cultwords["other"] && word3 == cultwords["see"]) \ - || (word1 == cultwords["destroy"] && word2 == cultwords["see"] && word3 == cultwords["other"]) \ - || (word1 == cultwords["destroy"] && word2 == cultwords["see"] && word3 == cultwords["blood"]) \ - || (word1 == cultwords["self"] && word2 == cultwords["other"] && word3 == cultwords["technology"]) \ - || (word1 == cultwords["travel"] && word2 == cultwords["other"]) \ - || (word1 == cultwords["join"] && word2 == cultwords["hide"] && word3 == cultwords["technology"]) ) + if(word && !(ticker.mode.cultdat.theme == "fire")) animated = 1 else animated = 0 - var/bits = word_to_uristrune_bit(word1) \ - | word_to_uristrune_bit(word2) \ - | word_to_uristrune_bit(word3) + var/bits = make_bit_triplet() - return get_uristrune(bits, animated) + return get_rune(bits, animated) -var/list/uristrune_cache = list() +var/list/rune_cache = list() +var/runetype = "rune" -/proc/get_uristrune(symbol_bits, animated = 0) +/proc/get_rune(symbol_bits, animated = 0) var/lookup = "[symbol_bits]-[animated]" - if(lookup in uristrune_cache) - return uristrune_cache[lookup] + if(ticker.mode.cultdat.theme == "fire") + runetype = "fire-rune" - var/icon/I = icon('icons/effects/uristrunes.dmi', "blank") + if(lookup in rune_cache) + return rune_cache[lookup] + + var/icon/I = icon('icons/effects/uristrunes.dmi', "[runetype]-179") for(var/i = 0, i < 10, i++) if(symbol_bits & (1 << i)) - I.Blend(icon('icons/effects/uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY) + I.Blend(icon('icons/effects/uristrunes.dmi', "[runetype]-[1 << i]"), ICON_OVERLAY) - I.SwapColor(rgb(0, 0, 0, 100), rgb(100, 0, 0, 200)) + I.SwapColor(rgb(0, 0, 0, 100), rgb(100, 0, 0, 200))//TO DO COMMENT:NEED TO ADJUST FOR DIFFRNET CULTS I.SwapColor(rgb(0, 0, 0, 50), rgb(150, 0, 0, 200)) for(var/x = 1, x <= 32, x++) @@ -127,6 +84,6 @@ var/list/uristrune_cache = list() result.Insert(I3, "", frame = 7, delay = 2) result.Insert(I2, "", frame = 8, delay = 2) - uristrune_cache[lookup] = result + rune_cache[lookup] = result return result diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm index ea8a06961cc..24b6b1822d9 100644 --- a/code/game/mecha/mech_bay.dm +++ b/code/game/mecha/mech_bay.dm @@ -155,7 +155,7 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/computer/mech_bay_power_console/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/mech_bay_power_console/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] if(!recharge_port) reconnect() diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm index 6838aae1b29..11c940f7971 100644 --- a/code/game/mecha/mecha_control_console.dm +++ b/code/game/mecha/mecha_control_console.dm @@ -23,7 +23,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/computer/mecha/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/mecha/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["screen"] = screen if(screen == 0) diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 0297a372dff..ea692339ac3 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -113,3 +113,7 @@ "You hear metal clanking.") add_fingerprint(user) return M + +/mob/living/proc/check_buckled() + if(buckled && !(buckled in loc)) + buckled.unbuckle_mob(src, force=1) diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 7a862882b0c..fa16d85a626 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -24,6 +24,14 @@ var/global/list/image/splatter_cache=list() /obj/effect/decal/cleanable/blood/New() ..() update_icon() + if(ticker && ticker.mode && istype(ticker.mode.name, "cult")) + var/datum/game_mode/cult/mode_ticker = ticker.mode + var/turf/T = get_turf(src) + if(T && (is_station_level(T.z)))//F I V E T I L E S + if(!(T in mode_ticker.bloody_floors)) + mode_ticker.bloody_floors += T + mode_ticker.bloody_floors[T] = T + mode_ticker.blood_check() if(istype(src, /obj/effect/decal/cleanable/blood/gibs)) return if(src.type == /obj/effect/decal/cleanable/blood) @@ -36,6 +44,15 @@ var/global/list/image/splatter_cache=list() spawn(DRYING_TIME * (amount+1)) dry() +/obj/effect/decal/cleanable/blood/Destroy() + if(ticker.mode && istype(ticker.mode.name, "cult")) + var/datum/game_mode/cult/mode_ticker = ticker.mode + var/turf/T = get_turf(src) + if(T && (is_station_level(T.z))) + mode_ticker.bloody_floors -= T + mode_ticker.blood_check() + .=..() + /obj/effect/decal/cleanable/blood/update_icon() if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]" color = basecolor diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 4a8681b928a..140c013b270 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -204,4 +204,62 @@ /obj/effect/overlay/wall_rot/New() ..() pixel_x += rand(-10, 10) - pixel_y += rand(-10, 10) \ No newline at end of file + pixel_y += rand(-10, 10) +/obj/effect/overlay/temp/cult + randomdir = 0 + duration = 10 + + + icon = 'icons/effects/effects.dmi' + +/obj/effect/overlay/temp/cult/sparks + randomdir = 1 + name = "blood sparks" + icon_state = "bloodsparkles" + +/obj/effect/overlay/temp/cult/phase + name = "phase glow" + duration = 7 + icon_state = "cultin" + +/obj/effect/overlay/temp/cult/phase/New(loc, set_dir) + ..() + if(set_dir) + dir = set_dir + +/obj/effect/overlay/temp/cult/phase/out + icon_state = "cultout" + +/obj/effect/overlay/temp/heal //color is white by default, set to whatever is needed + name = "healing glow" + icon = 'icons/effects/effects.dmi' + icon_state = "heal" + duration = 15 + +/obj/effect/overlay/temp/heal/New(loc, colour) + ..() + pixel_x = rand(-12, 12) + pixel_y = rand(-9, 0) + if(colour) + color = colour + +/obj/effect/overlay/temp/cult/sac + name = "maw of Nar-Sie" + icon_state = "sacconsume" + +/obj/effect/overlay/temp/cult/door + name = "unholy glow" + icon_state = "doorglow" + layer = 3.17 //above closed doors + +/obj/effect/overlay/temp/cult/door/unruned + icon_state = "unruneddoorglow" + +/obj/effect/overlay/temp/cult/turf + name = "unholy glow" + icon_state = "wallglow" + layer = TURF_LAYER + 0.07 + +/obj/effect/overlay/temp/cult/turf/open/floor + icon_state = "floorglow" + duration = 5 \ No newline at end of file diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index ab897d80ec0..0d02add30a3 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -48,7 +48,7 @@ ui.set_auto_update(1) -/obj/item/device/aicard/ui_data(mob/user, datum/topic_state/state = inventory_state) +/obj/item/device/aicard/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state) var/data[0] var/mob/living/silicon/ai/AI = locate() in src diff --git a/code/game/objects/items/devices/guitar.dm b/code/game/objects/items/devices/guitar.dm index 73831d1f468..eaf1c668e3c 100644 --- a/code/game/objects/items/devices/guitar.dm +++ b/code/game/objects/items/devices/guitar.dm @@ -33,8 +33,8 @@ song.ui_interact(user, ui_key, ui, force_open) -/obj/item/device/guitar/ui_data(mob/user, datum/topic_state/state = default_state) - return song.ui_data(user, state) +/obj/item/device/guitar/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) + return song.ui_data(user, ui_key, state) /obj/item/device/guitar/Topic(href, href_list) song.Topic(href, href_list) @@ -46,4 +46,4 @@ /obj/item/stack/cable_coil = 6, /obj/item/stack/tape_roll = 5) tools = list(/obj/item/weapon/screwdriver, /obj/item/weapon/wirecutters) - time = 80 \ No newline at end of file + time = 80 diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm index 51859fd27ac..35848bdc087 100644 --- a/code/game/objects/items/devices/radio/electropack.dm +++ b/code/game/objects/items/devices/radio/electropack.dm @@ -105,7 +105,7 @@ ui.open() ui.set_auto_update(1) -/obj/item/device/radio/electropack/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/item/device/radio/electropack/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["power"] = on diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 6078f855b61..f4f95559ad9 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -114,7 +114,7 @@ var/global/list/default_medbay_channels = list( ui.open() ui.set_auto_update(1) -/obj/item/device/radio/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/item/device/radio/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["mic_status"] = broadcasting @@ -757,7 +757,7 @@ var/global/list/default_medbay_channels = list( ui.open() ui.set_auto_update(1) -/obj/item/device/radio/borg/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/item/device/radio/borg/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["mic_status"] = broadcasting diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index 84b397780dc..f126910bcbb 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -101,7 +101,7 @@ // auto update every Master Controller tick //ui.set_auto_update(1) -/obj/item/device/transfer_valve/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/item/device/transfer_valve/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["attachmentOne"] = tank_one ? tank_one.name : null diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm index d29e5e5ede4..0c21ef212c9 100644 --- a/code/game/objects/items/devices/uplinks.dm +++ b/code/game/objects/items/devices/uplinks.dm @@ -198,7 +198,7 @@ var/list/world_uplinks = list() // open the new ui window ui.open() -/obj/item/device/uplink/hidden/ui_data(mob/user, datum/topic_state/state = inventory_state) +/obj/item/device/uplink/hidden/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state) var/data[0] data["welcome"] = welcome diff --git a/code/game/objects/items/devices/violin.dm b/code/game/objects/items/devices/violin.dm index 7802e832fde..323fb3db4f4 100644 --- a/code/game/objects/items/devices/violin.dm +++ b/code/game/objects/items/devices/violin.dm @@ -38,8 +38,8 @@ song.ui_interact(user, ui_key, ui, force_open) -/obj/item/device/violin/ui_data(mob/user, datum/topic_state/state = default_state) - return song.ui_data(user, state) +/obj/item/device/violin/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) + return song.ui_data(user, ui_key, state) /obj/item/device/violin/Topic(href, href_list) song.Topic(href, href_list) diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 061d9a927de..45be8bc7c6a 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -98,6 +98,11 @@ var/global/list/datum/stack_recipe/metal_recipes = list( flags = CONDUCT origin_tech = "materials=1" +/obj/item/stack/sheet/metal/narsie_act() + if(prob(20)) + new /obj/item/stack/sheet/runed_metal(loc, amount) + qdel(src) + /obj/item/stack/sheet/metal/cyborg materials = list() @@ -202,6 +207,40 @@ var/global/list/datum/stack_recipe/cardboard_recipes = list ( recipes = cardboard_recipes return ..() +/* + * Runed Metal + */ + +var/global/list/datum/stack_recipe/runed_metal_recipes = list ( \ + new/datum/stack_recipe("runed door", /obj/machinery/door/airlock/cult, 1, time = 50, one_per_turf = 1, on_floor = 1), + new/datum/stack_recipe("runed girder", /obj/structure/cultgirder, 1, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("pylon", /obj/structure/cult/functional/pylon, 3, time = 40, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("forge", /obj/structure/cult/functional/forge, 5, time = 40, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("archives", /obj/structure/cult/functional/tome, 2, time = 40, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("altar", /obj/structure/cult/functional/talisman, 5, time = 40, one_per_turf = 1, on_floor = 1), \ + ) + +/obj/item/stack/sheet/runed_metal + name = "runed metal" + desc = "Sheets of cold metal with shifting inscriptions writ upon them." + singular_name = "runed metal" + icon_state = "sheet-runed" + icon = 'icons/obj/items.dmi' + sheettype = "runed" + +/obj/item/stack/sheet/runed_metal/attack_self(mob/living/user) + if(!iscultist(user)) + to_chat(user, "Only one with forbidden knowledge could hope to work this metal...") + return + return ..() + +/obj/item/stack/sheet/runed_metal/fifty + amount = 50 + +/obj/item/stack/sheet/runed_metal/New(var/loc, var/amount=null) + recipes = runed_metal_recipes + return ..() + /* * Bones */ diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index 0a503aa7cb9..088c26f06c2 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -89,7 +89,7 @@ RCD ui.open() ui.set_auto_update(1) -/obj/item/weapon/rcd/ui_data(mob/user, datum/topic_state/state = inventory_state) +/obj/item/weapon/rcd/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state) var/data[0] data["mode"] = mode data["door_type"] = door_type diff --git a/code/game/objects/items/weapons/legcuffs.dm b/code/game/objects/items/weapons/legcuffs.dm index 4dc192e065b..7e62a14250b 100644 --- a/code/game/objects/items/weapons/legcuffs.dm +++ b/code/game/objects/items/weapons/legcuffs.dm @@ -103,7 +103,7 @@ /obj/item/weapon/restraints/legcuffs/beartrap/Crossed(AM as mob|obj) if(armed && isturf(src.loc)) - if( (iscarbon(AM) || isanimal(AM)) && !istype(AM, /mob/living/simple_animal/parrot) && !istype(AM, /mob/living/simple_animal/construct) && !istype(AM, /mob/living/simple_animal/shade) && !istype(AM, /mob/living/simple_animal/hostile/viscerator)) + if( (iscarbon(AM) || isanimal(AM)) && !istype(AM, /mob/living/simple_animal/parrot) && !istype(AM, /mob/living/simple_animal/hostile/construct) && !istype(AM, /mob/living/simple_animal/shade) && !istype(AM, /mob/living/simple_animal/hostile/viscerator)) var/mob/living/L = AM armed = 0 icon_state = "[initial(icon_state)][armed]" diff --git a/code/game/objects/items/weapons/storage/bible.dm b/code/game/objects/items/weapons/storage/bible.dm index 042f6d2423a..8a9b86d4e81 100644 --- a/code/game/objects/items/weapons/storage/bible.dm +++ b/code/game/objects/items/weapons/storage/bible.dm @@ -100,7 +100,7 @@ if(istype(A, /turf/simulated/floor)) to_chat(user, "You hit the floor with the bible.") if(user.mind && (user.mind.assigned_role == "Chaplain")) - call(/obj/effect/rune/proc/revealrunes)(src) + call(/obj/effect/rune/proc/talismanreveal)(src) if(user.mind && (user.mind.assigned_role == "Chaplain")) if(A.reagents && A.reagents.has_reagent("water")) //blesses all the water in the holder to_chat(user, "You bless [A].") diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 5dbcc68ab2b..a61a3cea5ce 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -152,7 +152,7 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/item/weapon/tank/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/item/weapon/tank/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/using_internal if(iscarbon(loc)) var/mob/living/carbon/C = loc diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index f83c257740f..9dddd902740 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -144,6 +144,20 @@ obj/structure/door_assembly/multi_tile/Move() bound_width = world.icon_size bound_height = width * world.icon_size +/obj/structure/door_assembly/door_assembly_cult + icon = 'icons/obj/doors/Doorcult.dmi' + base_icon_state = "construction" + base_name = "engraved airlock" + airlock_type = "/cult" + glass = -1 + + +/obj/structure/door_assembly/door_assembly_cultruned + icon = 'icons/obj/doors/Doorcultruned.dmi' + base_icon_state = "construction" + base_name = "runed airlock" + airlock_type = "/cult/runed" + glass = -1 /obj/structure/door_assembly/attackby(obj/item/W as obj, mob/user as mob, params) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 643728dd6cb..6051bbebef6 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -188,6 +188,11 @@ if(prob(40)) qdel(src) +/obj/structure/girder/narsie_act() + if(prob(25)) + new /obj/structure/cultgirder(loc) + qdel(src) + /obj/structure/girder/bullet_act(var/obj/item/projectile/Proj) if(istype(Proj ,/obj/item/projectile/beam/pulse)) src.ex_act(2) diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm index c28ebe05c55..f1d9b6ac578 100644 --- a/code/game/objects/structures/musician.dm +++ b/code/game/objects/structures/musician.dm @@ -122,7 +122,7 @@ ui.open() ui.set_auto_update(1) -/datum/song/ui_data(mob/user, datum/topic_state/state = default_state) +/datum/song/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["lines"] = lines @@ -296,8 +296,8 @@ song.ui_interact(user, ui_key, ui, force_open) -/obj/structure/piano/ui_data(mob/user, datum/topic_state/state = default_state) - return song.ui_data(user, state) +/obj/structure/piano/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) + return song.ui_data(user, ui_key, state) /obj/structure/piano/Topic(href, href_list) song.Topic(href, href_list) diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 1c3c3f8e793..e2e287052ff 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -13,6 +13,12 @@ handle_rotation() return +/obj/structure/stool/bed/chair/narsie_act() + if(prob(20)) + var/obj/structure/stool/bed/chair/wood/W = new/obj/structure/stool/bed/chair/wood(get_turf(src)) + W.dir = dir + qdel(src) + /obj/structure/stool/bed/chair/Move(atom/newloc, direct) ..() handle_rotation() @@ -81,6 +87,9 @@ burntime = 20 // TODO: Special ash subtype that looks like charred chair legs +/obj/structure/stool/bed/chair/wood/narsie_act() + return + /obj/structure/stool/bed/chair/wood/normal icon_state = "wooden_chair" name = "wooden chair" diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 6a7476d6be1..ae9e6b41d05 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -41,6 +41,10 @@ density = 0 qdel(src) +/obj/structure/table/narsie_act() + if(prob(20)) + new /obj/structure/table/woodentable(loc) + /obj/structure/table/update_icon() if(smooth && !flipped) icon_state = "" @@ -386,6 +390,10 @@ return 1 + +/obj/structure/table/woodentable/narsie_act() + return + /obj/structure/table/woodentable/poker //No specialties, Just a mapping object. name = "gambling table" desc = "A seedy table for seedy dealings in seedy places." @@ -398,6 +406,9 @@ new /obj/item/stack/tile/grass(loc) ..() +/obj/structure/table/woodentable/poker/narsie_act() + return + /obj/structure/glasstable_frame name = "glass table frame" desc = "A metal frame for a glass table." diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 051dbe55495..22331e4f484 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -76,6 +76,9 @@ var/global/wcCommon = pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e", "#8f /obj/structure/window/blob_act() destroy() +/obj/structure/window/narsie_act() + color = "#7D1919" + /obj/structure/window/singularity_pull(S, current_size) if(current_size >= STAGE_FIVE) destroy() diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index a247e35a86f..cf1a1303025 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -120,10 +120,11 @@ return 0 var/obj/effect/decal/cleanable/blood/B = locate() in contents //check for existing blood splatter if(!B) - blood_splatter(src,M.get_blood(M.vessel),1) - B = locate(/obj/effect/decal/cleanable/blood) in contents - B.add_blood_list(M) - return 1 //we bloodied the floor + B = blood_splatter(src,M.get_blood(M.vessel),1) + if(B) + B.add_blood_list(M) + return 1 //we bloodied the floor + return 0 // Clean floors club // Only adds blood on the floor -- Skie /turf/simulated/add_blood_floor(mob/living/carbon/M as mob) diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 761e05f60c3..c6b51a05067 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -133,6 +133,11 @@ name = "engraved floor" icon_state = "cult" +/turf/simulated/floor/engine/cult/New() + ..() + if(ticker.mode)//only do this if the round is going..otherwise..fucking asteroid.. + icon_state = ticker.mode.cultdat.cult_floor_icon_state + /turf/simulated/floor/engine/cult/narsie_act() return diff --git a/code/game/turfs/simulated/walls_misc.dm b/code/game/turfs/simulated/walls_misc.dm index def35564327..da77242a276 100644 --- a/code/game/turfs/simulated/walls_misc.dm +++ b/code/game/turfs/simulated/walls_misc.dm @@ -5,10 +5,22 @@ icon_state = "cult" builtin_sheet = null canSmoothWith = null + smooth = SMOOTH_FALSE + +/turf/simulated/wall/cult/New() + ..() + if(ticker.mode)//game hasn't started offically don't do shit.. + new /obj/effect/overlay/temp/cult/turf(src) + icon_state = ticker.mode.cultdat.cult_wall_icon_state + +/turf/simulated/wall/cult/artificer + name = "runed stone wall" + desc = "A cold stone wall engraved with indecipherable symbols. Studying them causes your head to pound." + /turf/simulated/wall/cult/narsie_act() return - + /turf/simulated/wall/cult/break_wall() new /obj/effect/decal/cleanable/blood(src) return (new /obj/structure/cultgirder(src)) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 3350a9f4432..bd35698b94a 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -41,7 +41,8 @@ var/global/nologevent = 0 body += "Options panel for [M]" if(M.client) body += " played by [M.client] " - body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" + body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\] " + body += "\[" + M.client.get_exp_living() + "\]" if(istype(M, /mob/new_player)) body += " Hasn't Entered Game " diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index cb8a1bbd6a9..062f58018c7 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -37,7 +37,6 @@ var/list/admin_verbs_admin = list( /client/proc/jumptoturf, /*allows us to jump to a specific turf*/ /client/proc/admin_call_shuttle, /*allows us to call the emergency shuttle*/ /client/proc/admin_cancel_shuttle, /*allows us to cancel the emergency shuttle, sending it back to centcomm*/ - /client/proc/check_words, /*displays cult-words*/ /client/proc/check_ai_laws, /*shows AI and borg laws*/ /client/proc/manage_silicon_laws, /* Allows viewing and editing silicon laws. */ /client/proc/admin_memo, /*admin memo system. show/delete/write. +SERVER needed to delete admin memos of others*/ @@ -75,6 +74,7 @@ var/list/admin_verbs_admin = list( /client/proc/debug_variables, /client/proc/show_snpc_verbs, /client/proc/reset_all_tcs, /*resets all telecomms scripts*/ + /client/proc/cmd_admin_check_player_exp, /* shows players by playtime */ /client/proc/toggle_mentor_chat ) var/list/admin_verbs_ban = list( diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 25d550349de..24d6c3186a1 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -270,9 +270,6 @@ else if(isobserver(M)) M_job = "Ghost" - else if(isSpirit(M)) - M_job = (ismask(M)) ? "Mask" : "Spirit" - M_job = replacetext(M_job, "'", "") M_job = replacetext(M_job, "\"", "") M_job = replacetext(M_job, "\\", "") @@ -360,10 +357,6 @@ dat += "Ghost" else if(isalien(M)) dat += "Alien" - else if(ismask(M)) - dat += "Mask" - else if(isSpirit(M)) - dat += "Spirit" else dat += "Unknown" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index ef87ffe8820..830fa2909b5 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -336,9 +336,9 @@ if("coffee") M.change_mob_type( /mob/living/simple_animal/crab/Coffee , null, null, delmob, 1 ) if("parrot") M.change_mob_type( /mob/living/simple_animal/parrot , null, null, delmob, 1 ) if("polyparrot") M.change_mob_type( /mob/living/simple_animal/parrot/Poly , null, null, delmob, 1 ) - if("constructarmoured") M.change_mob_type( /mob/living/simple_animal/construct/armoured , null, null, delmob, 1 ) - if("constructbuilder") M.change_mob_type( /mob/living/simple_animal/construct/builder , null, null, delmob, 1 ) - if("constructwraith") M.change_mob_type( /mob/living/simple_animal/construct/wraith , null, null, delmob, 1 ) + if("constructarmoured") M.change_mob_type( /mob/living/simple_animal/hostile/construct/armoured , null, null, delmob, 1 ) + if("constructbuilder") M.change_mob_type( /mob/living/simple_animal/hostile/construct/builder , null, null, delmob, 1 ) + if("constructwraith") M.change_mob_type( /mob/living/simple_animal/hostile/construct/wraith , null, null, delmob, 1 ) if("shade") M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob, 1 ) @@ -1419,19 +1419,6 @@ var/mob/living/silicon/ai/ai_character = H.AIize() ai_character.moveToAILandmark() - - else if(href_list["makemask"]) - if(!check_rights(R_SPAWN)) return - - if(alert(usr, "Confirm make mask?",, "Yes", "No") != "Yes") - return - - var/mob/currentMob = locate(href_list["makemask"]) - message_admins("\red Admin [key_name_admin(usr)] made [key_name_admin(currentMob)] into a Mask of Nar'Sie!", 1) - log_admin("[key_name(usr)] made [key_name(currentMob)] into a Mask of Nar'Sie!") - currentMob.make_into_mask(0,0) - - else if(href_list["makealien"]) if(!check_rights(R_SPAWN)) return @@ -2009,6 +1996,15 @@ fax_panel(usr) + else if(href_list["getplaytimewindow"]) + if(!check_rights(R_ADMIN)) + return + var/mob/M = locateUID(href_list["getplaytimewindow"]) + if(!M) + to_chat(usr, "ERROR: Mob not found.") + return + cmd_show_exp_panel(M.client) + else if(href_list["jumpto"]) if(!check_rights(R_ADMIN)) return diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 13fea30a7f8..84577b51102 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -78,22 +78,23 @@ if("where" in query_tree) var/objs_temp = objs objs = list() - for(var/datum/d in objs_temp) + for(var/d in objs_temp) if(SDQL_expression(d, query_tree["where"])) objs += d switch(query_tree[1]) if("call") - for(var/datum/d in objs) + for(var/d in objs) SDQL_var(d, query_tree["call"][1], source = d) if("delete") - for(var/datum/d in objs) + for(var/d in objs) qdel(d) if("select") var/text = "" - for(var/datum/t in objs) + for(var/o in objs) + var/datum/t = o text += "\ref[t]" if(istype(t, /atom)) var/atom/a = t @@ -115,7 +116,7 @@ if("update") if("set" in query_tree) var/list/set_list = query_tree["set"] - for(var/datum/d in objs) + for(var/d in objs) for(var/list/sets in set_list) var/datum/temp = d var/i = 0 @@ -252,6 +253,12 @@ if(istype(d, type)) out += d + else if(ispath(type, /client)) + for(var/client/C) + if((location != world) && !(C.mob in location)) + continue + out += C + else if(location == world) for(var/datum/d) if(istype(d, type)) diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index e9648119f42..e71c6981d97 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -164,7 +164,6 @@ client/proc/one_click_antag() H = pick(candidates) H.mind.make_Cultist() candidates.Remove(H) - temp.grant_runeword(H) return 1 diff --git a/code/modules/arcade/mob_hunt/battle_computer.dm b/code/modules/arcade/mob_hunt/battle_computer.dm new file mode 100644 index 00000000000..97055664cdb --- /dev/null +++ b/code/modules/arcade/mob_hunt/battle_computer.dm @@ -0,0 +1,278 @@ + +/obj/machinery/computer/mob_battle_terminal + name = "Nano-Mob Hunter GO! Battle Terminal" + desc = "Insert a mob card to partake in life-like Nano-Mob Battle Action!" + icon_state = "mob_battle_empty" + icon_screen = null + icon_keyboard = null + density = 0 + anchored = 1 + var/obj/item/weapon/nanomob_card/card + var/datum/mob_hunt/mob_info + var/obj/effect/nanomob/battle/avatar + var/ready = 0 + var/team = "Grey" + var/avatar_x_offset = 4 + var/avatar_y_offset = 0 + +/obj/machinery/computer/mob_battle_terminal/red + pixel_y = 24 + dir = SOUTH + team = "Red" + avatar_y_offset = -1 + +/obj/machinery/computer/mob_battle_terminal/blue + pixel_y = -24 + dir = NORTH + team = "Blue" + avatar_y_offset = 1 + +/obj/machinery/computer/mob_battle_terminal/red/initialize() + ..() + check_connection() + +/obj/machinery/computer/mob_battle_terminal/blue/initialize() + ..() + check_connection() + +/obj/machinery/computer/mob_battle_terminal/update_icon() + if(card) + icon_state = "mob_battle_loaded" + else + icon_state = "mob_battle_empty" + ..() + +/obj/machinery/computer/mob_battle_terminal/Destroy() + eject_card(1) + if(mob_hunt_server) + if(mob_hunt_server.battle_turn) + mob_hunt_server.battle_turn = null + if(mob_hunt_server.red_terminal == src) + mob_hunt_server.red_terminal = null + if(mob_hunt_server.blue_terminal == src) + mob_hunt_server.blue_terminal = null + if(avatar) + qdel(avatar) + return ..() + +/obj/machinery/computer/mob_battle_terminal/attackby(obj/item/O, mob/user) + if(istype(O, /obj/item/weapon/nanomob_card)) + insert_card(O, user) + +/obj/machinery/computer/mob_battle_terminal/proc/insert_card(obj/item/weapon/nanomob_card/new_card, mob/user) + if(!new_card) + return + if(card) + to_chat(user, "The card slot is currently filled.") + return + if(!new_card.mob_data) + to_chat(user, "This is a blank mob card.") + return + if(new_card.mob_data && !new_card.mob_data.cur_health) + to_chat(user, "This mob is incapacitated! Heal it before attempting to use it in battle!") + return + user.unEquip(new_card) + new_card.forceMove(src) + card = new_card + mob_info = card.mob_data + update_icon() + update_avatar() + updateUsrDialog() + +/obj/machinery/computer/mob_battle_terminal/proc/eject_card(override = 0) + if(!override) + if(ready && mob_hunt_server.battle_turn != team) + audible_message("You can't recall on your rival's turn!", null, 2) + return + card.mob_data = mob_info + mob_info = null + card.forceMove(get_turf(src)) + card = null + update_avatar() + update_icon() + updateUsrDialog() + +/obj/machinery/computer/mob_battle_terminal/proc/update_avatar() + //if we don't have avatars yet, spawn them + if(!avatar) + avatar = new(locate((x + avatar_x_offset), (y + avatar_y_offset), z)) + //update avatar info from card + if(mob_info) + avatar.mob_info = mob_info + else + avatar.mob_info = null + //tell the avatar to update themself with the new info + avatar.update_self() + +/obj/machinery/computer/mob_battle_terminal/attack_hand(mob/user) + add_fingerprint(user) + interact(user) + +/obj/machinery/computer/mob_battle_terminal/attack_ai(mob/user) + to_chat(user, "You cannot interface with this portion of the simulation.") + return + +/obj/machinery/computer/mob_battle_terminal/interact(mob/user) + check_connection() + var/dat = "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + if(ready && mob_hunt_server.battle_turn) //offer the surrender option if they are in a battle (ready), but don't have a card loaded + dat += "" + dat += "" + dat += "" + else + dat += "
" + dat += "[team] PLAYER" + dat += "
" + if(!card) + dat += "

No Nano-Mob card loaded.

" + dat += "
Surrender!
" + dat += "" + dat += "" + if(mob_info.nickname) + dat += "" + dat += "" + if(mob_info.nickname) + dat += "" + dat += "" + dat += "" + dat += "
" + dat += "

[mob_info.mob_name]

" + dat += "
" + else + dat += "" + var/img_src = "[mob_info.icon_state_normal].png" + if(mob_info.is_shiny) + dat += "[mob_info.icon_state_shiny].png" + dat += "" + dat += "
" + dat += "

[mob_info.nickname]

" + dat += "
" + dat += "
" + dat += "Health: [mob_info.cur_health] / [mob_info.max_health]
" + dat += "" + dat += "" + if(mob_info.cur_health) + dat += "" + else + dat += "" + dat += "" + dat += "" + dat += "
Attack!Incapacitated!Recall!
" + dat += "" + dat += "" + if(!ready) + dat += "" + dat += "Battle!" + dat += "" + if(ready && !mob_hunt_server.battle_turn) + dat += "" + dat += "Cancel Battle!" + dat += "" + dat += "" + + var/datum/browser/popup = new(user, "mob_battle_terminal", "Nano-Mob Hunter GO! Battle Terminal", 575, 400) + popup.set_content(dat) + popup.open() + +/obj/machinery/computer/mob_battle_terminal/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["attack"]) + do_attack() + + if(href_list["eject"]) + eject_card() + + if(href_list["surrender"]) + surrender() + + if(href_list["ready"]) + var/option = text2num(href_list["ready"]) + if(option == 1) + start_battle() + else if(option == 2) + ready = 0 + audible_message("[team] Player cancels their battle challenge.", null, 5) + + updateUsrDialog() + +/obj/machinery/computer/mob_battle_terminal/proc/check_connection() + if(team == "Red") + if(mob_hunt_server && !mob_hunt_server.red_terminal) + mob_hunt_server.red_terminal = src + else if(team == "Blue") + if(mob_hunt_server && !mob_hunt_server.blue_terminal) + mob_hunt_server.blue_terminal = src + +/obj/machinery/computer/mob_battle_terminal/proc/do_attack() + if(!ready) //no attacking if you arent ready to fight (duh) + return + if(!mob_hunt_server || team != mob_hunt_server.battle_turn) //don't attack unless it is actually our turn + return + else + var/message = "[mob_info.mob_name] attacks!" + if(mob_info.nickname) + message = "[mob_info.nickname] attacks!" + audible_message(message, null, 5) + mob_hunt_server.launch_attack(team, mob_info.get_raw_damage(), mob_info.get_attack_type()) + +/obj/machinery/computer/mob_battle_terminal/proc/start_battle() + if(ready) //don't do anything if we are still ready + return + if(!card) //don't do anything if there isn't a card inserted + return + ready = 1 + audible_message("[team] Player is ready for battle! Waiting for rival...", null, 5) + mob_hunt_server.start_check() + +/obj/machinery/computer/mob_battle_terminal/proc/receive_attack(raw_damage, datum/mob_type/attack_type) + var/message = mob_info.take_damage(raw_damage, attack_type) + avatar.audible_message(message, null, 5) + if(!mob_info.cur_health) + mob_hunt_server.end_battle(team) + eject_card(1) //force the card out, they were defeated + else + mob_hunt_server.end_turn() + +/obj/machinery/computer/mob_battle_terminal/proc/surrender() + audible_message("[team] Player surrenders the battle!", null, 5) + mob_hunt_server.end_battle(team, 1) + +////////////////////////////// +// Mob Healing Terminal // +// (Pokemon Center) // +////////////////////////////// + +/obj/machinery/computer/mob_healer_terminal + name = "Nano-Mob Hunter GO! Restoration Terminal" + desc = "Swipe a mob card to instantly restore it to full health!" + icon_state = "mob_battle_loaded" + icon_screen = null + icon_keyboard = null + density = 0 + anchored = 1 + dir = EAST + +/obj/machinery/computer/mob_healer_terminal/attackby(obj/item/O, mob/user) + if(istype(O, /obj/item/weapon/nanomob_card)) + heal_card(O, user) + +/obj/machinery/computer/mob_healer_terminal/proc/heal_card(obj/item/weapon/nanomob_card/patient, mob/user) + if(!patient) + return + if(!patient.mob_data) + to_chat(user, "This is a blank mob card.") + return + if(patient.mob_data && patient.mob_data.cur_health == patient.mob_data.max_health) + to_chat(user, "This mob is already at maximum health!") + return + patient.mob_data.cur_health = patient.mob_data.max_health + to_chat(user, "[patient.mob_data.nickname ? patient.mob_data.nickname : patient.mob_data.mob_name] has been restored to full health!") \ No newline at end of file diff --git a/code/modules/arcade/mob_hunt/mob_avatar.dm b/code/modules/arcade/mob_hunt/mob_avatar.dm new file mode 100644 index 00000000000..8717d5eb2a5 --- /dev/null +++ b/code/modules/arcade/mob_hunt/mob_avatar.dm @@ -0,0 +1,162 @@ + +/obj/effect/nanomob + name = "Nano-Mob Avatar" //will be overridden by the mob datum name value when created + desc = "A wild Nano-Mob appeared! Hit it with your PDA with the game open to attempt to capture it!" + invisibility = 101 + alpha = 128 + anchored = 1 //just in case + density = 0 + icon = 'icons/effects/mob_hunt.dmi' + var/state_name + var/datum/mob_hunt/mob_info = null + var/list/clients_encountered = list() //tracks who has already interacted with us, so they can't attempt a second capture + var/image/avatar + +/obj/effect/nanomob/New(loc, datum/mob_hunt/new_info) + ..() + if(!new_info) + qdel(src) + return + mob_info = new_info + update_self() + forceMove(mob_info.spawn_point) + if(!mob_info.is_trap) + addtimer(src, "despawn", mob_info.lifetime) + +/obj/effect/nanomob/proc/update_self() + if(!mob_info) + return + name = mob_info.mob_name + desc = "A wild [name] (level [mob_info.level]) appeared! Hit it with your PDA with the game open to attempt to capture it!" + if(mob_info.is_shiny) + state_name = mob_info.icon_state_shiny + else + state_name = mob_info.icon_state_normal + avatar = image(icon, src, state_name) + avatar.override = 1 + add_alt_appearance("nanomob_avatar", avatar) + +/obj/effect/nanomob/attackby(obj/item/O, mob/user) + if(istype(O, /obj/item/device/pda)) + var/obj/item/device/pda/P = O + attempt_capture(P, -20) //attempting a melee capture reduces the mob's effective run_chance by 20% to balance the risk of triggering a trap mob + return 1 + +/obj/effect/nanomob/hitby(obj/item/O) + if(istype(O, /obj/item/device/pda)) + var/obj/item/device/pda/P = O + attempt_capture(P) //attempting a ranged capture does not affect the mob's effective run_chance but does prevent you from being shocked by a trap mob + return 1 + +/obj/effect/nanomob/proc/attempt_capture(obj/item/device/pda/P, catch_mod = 0) //negative catch_mods lower effective run chance, + if(!P || !P.current_app || !istype(P.current_app, /datum/data/pda/app/mob_hunter_game) || !P.cartridge) + return + + var/datum/data/pda/app/mob_hunter_game/client = P.current_app + var/total_catch_mod = client.catch_mod + catch_mod //negative values decrease the chance of the mob running, positive values makes it more likely to flee + if(!client.connected) //must be connected to attempt captures + P.audible_message("[bicon(P)] No server connection. Capture aborted.", null, 4) + return + + if(mob_info.is_trap) //traps work even if you ran into them before, which is why this is before the clients_encountered check + if(client.hacked) //hacked copies of the game (copies capable of setting traps) are protected from traps + return + if(iscarbon(P.loc)) + var/mob/living/carbon/C = P.loc + //Strike them down with a lightning bolt to complete the illusion (copied from the surge reagent overdose, probably could make this a general-use proc in the future) + playsound(get_turf(C), 'sound/effects/eleczap.ogg', 75, 1) + var/icon/I=new('icons/obj/zap.dmi',"lightningend") + I.Turn(-135) + var/obj/effect/overlay/beam/B = new(get_turf(C)) + B.pixel_x = rand(-20, 0) + B.pixel_y = rand(-20, 0) + B.icon = I + //then actually do the damage/stun + C.electrocute_act(20, P, 1) //same damage as a revenant's overload ability, except subject to gloves/species shock resistance (for human mobs at least) + return + + if(client in clients_encountered) //we've already dealt with you, go away! + return + else //deal with the new hunter by either running away or getting caught + clients_encountered += client + var/message = "[bicon(P)] " + var/effective_run_chance = mob_info.run_chance + total_catch_mod + if((effective_run_chance > 0) && prob(effective_run_chance)) + message += "Capture failed! [name] escaped [P.owner ? "from [P.owner]" : "from this hunter"]!" + conceal(client) + else + if(client.register_capture(mob_info, 1)) + message += "Capture success! [P.owner ? P.owner : "This hunter"] captured [name]!" + conceal(client) + else + message += "Capture error! Try again." + clients_encountered -= client //if the capture registration failed somehow, let them have another chance with this mob + P.audible_message(message, null, 4) + +/obj/effect/nanomob/proc/despawn() + if(mob_hunt_server) + if(mob_info.is_trap) + mob_hunt_server.trap_spawns -= src + else + mob_hunt_server.normal_spawns -= src + qdel(src) + +/obj/effect/nanomob/proc/reveal() + if(!mob_hunt_server) + return + var/list/show_to = list() + for(var/A in mob_hunt_server.connected_clients) + if((A in clients_encountered) || !mob_hunt_server.connected_clients[A]) + continue + show_to |= mob_hunt_server.connected_clients[A] + display_alt_appearance("nanomob_avatar", show_to) + +/obj/effect/nanomob/proc/conceal(list/hide_from) + if(!mob_hunt_server) + return + var/list/hiding_from = list() + if(hide_from) + hiding_from = hide_from + else + for(var/A in mob_hunt_server.connected_clients) + if((A in clients_encountered) && mob_hunt_server.connected_clients[A]) + hiding_from |= mob_hunt_server.connected_clients[A] + hide_alt_appearance("nanomob_avatar", hiding_from) + +// BATTLE MOB AVATARS + +/obj/effect/nanomob/battle + name = "Nano-Mob Battle Avatar" + desc = "A new challenger approaches!" + invisibility = 0 + icon_state = "placeholder" + var/obj/machinery/computer/mob_battle_terminal/my_terminal + +/obj/effect/nanomob/battle/New(loc, datum/mob_hunt/new_info) + if(new_info) + mob_info = new_info + update_self() + +/obj/effect/nanomob/battle/update_self() + if(!mob_info) + name = "Nano-Mob Battle Avatar" + desc = "A new challenger approaches" + icon_state = "placeholder" + else + name = mob_info.mob_name + desc = "A tamed [name] (level [mob_info.level]) ready for battle!" + if(mob_info.is_shiny) + icon_state = mob_info.icon_state_shiny + else + icon_state = mob_info.icon_state_normal + +/obj/effect/nanomob/battle/attempt_capture(obj/item/device/pda/P, catch_mod = 0) + //you can't capture battle avatars, since they belong to someone already + return + +//battle avatars are always visible, so we can ignore reveal and conceal calls for them +/obj/effect/nanomob/battle/reveal() + return + +/obj/effect/nanomob/battle/conceal() + return diff --git a/code/modules/arcade/mob_hunt/mob_cards.dm b/code/modules/arcade/mob_hunt/mob_cards.dm new file mode 100644 index 00000000000..16aea7ba55f --- /dev/null +++ b/code/modules/arcade/mob_hunt/mob_cards.dm @@ -0,0 +1,43 @@ + +//Standard Cards +/obj/item/weapon/nanomob_card + name = "Nano-Mob Hunter Trading Card" + desc = "A blank Nano-Mob Hunter Trading Card. Worthless!" + icon = 'icons/obj/card.dmi' + icon_state = "trade_card" + force = 0 + throwforce = 1 + w_class = 1 + var/datum/mob_hunt/mob_data + +/obj/item/weapon/nanomob_card/proc/update_info() + if(!mob_data) + return + if(mob_data.is_shiny) + name = "Holographic [mob_data.mob_name] Nano-Mob Hunter Card" + desc = "WOW! A holographic trading card containing a level [mob_data.level] [mob_data.mob_name]!" + icon_state = "trade_card_holo" + else + name = "[mob_data.mob_name] Nano-Mob Hunter Card" + desc = "A trading card containing a level [mob_data.level] [mob_data.mob_name]!" + +//Booster Pack Cards (random mob data) +/obj/item/weapon/nanomob_card/booster + name = "Nano-Mob Hunter Booster Pack Card" + desc = "A random Nano-Mob Trading Card from a Booster Pack. Wonder what it is?" + +/obj/item/weapon/nanomob_card/booster/New() + var/datum/mob_hunt/mob_info = pick(subtypesof(/datum/mob_hunt)) + mob_data = new mob_info(0,null,1) + update_info() + +//Booster Packs (Box of booster pack cards) +/obj/item/weapon/storage/box/nanomob_booster_pack + name = "Nano-Mob Hunter Trading Card Booster Pack" + desc = "Contains 6 random Nano-Mob Hunter Trading Cards. May contain a holographic card!" + can_hold = list("/obj/item/weapon/nanomob_card") + +/obj/item/weapon/storage/box/nanomob_booster_pack/New() + ..() + for(var/i in 1 to 6) + new /obj/item/weapon/nanomob_card/booster(src) \ No newline at end of file diff --git a/code/modules/arcade/mob_hunt/mob_datums.dm b/code/modules/arcade/mob_hunt/mob_datums.dm new file mode 100644 index 00000000000..f6bc9dff826 --- /dev/null +++ b/code/modules/arcade/mob_hunt/mob_datums.dm @@ -0,0 +1,501 @@ + +#define TYPE_FIRE /datum/mob_type/fire +#define TYPE_WATER /datum/mob_type/water +#define TYPE_GRASS /datum/mob_type/grass +#define TYPE_ELECTRIC /datum/mob_type/electric +#define TYPE_GROUND /datum/mob_type/ground +#define TYPE_ROCK /datum/mob_type/rock +#define TYPE_BUG /datum/mob_type/bug +#define TYPE_POISON /datum/mob_type/poison +#define TYPE_NORMAL /datum/mob_type/normal +#define TYPE_FIGHTING /datum/mob_type/fighting +#define TYPE_PSYCHIC /datum/mob_type/psychic +#define TYPE_GHOST /datum/mob_type/ghost +#define TYPE_ICE /datum/mob_type/ice +#define TYPE_FLYING /datum/mob_type/flying +#define TYPE_BLUESPACE /datum/mob_type/bluespace +#define TYPE_DARK /datum/mob_type/dark +#define TYPE_STEEL /datum/mob_type/steel + +/datum/mob_hunt + //GENERAL STATS AND VARIABLES + var/mob_name = "Generic Mob" //the mob's original name (its species/type/whatever) + var/nickname = "" //the mob's nickname (if given by the owner) + var/run_chance = 0 //percent chance the mob will escape capture attempts (higher is obviously more likely to get away) + + //COMBAT STATS AND VARIABLES + var/level = 0 //actual level of this mob (don't set this, it gets overwritten in New()) + var/min_level = 1 //minimum level of this mob (used for randomizing the actual level) + var/max_level = 1 //maximum level of this mob (used for randomizing the actual level) + var/exp = 0 //number of battles the mob has won towards the next level (resets to 0 on level-up) + var/exp_to_level = 3 //number of battles the mob must win to level up (in case we want to make some mobs harder or easier to level) + //the types of the mob will be used for battles to determine damage resistance or weakness (mob_type_datums.dm) + var/datum/mob_type/primary_type //Make sure you set this or the mob will be unable to deal damage and will take absurd damage in battles + var/datum/mob_type/secondary_type //Don't set if not a dual-type mob so the mob will only calculate damage based on primary type + var/base_attack = 5 //base damage dealt by the mob's attacks for battling (effectively damage dealt at level 0) + var/base_health = 5 //base health of the mob for battling (effectively max health at level 0) + var/attack_multiplier = 1 //how much additional damage per level the mob deals (level * attack_multiplier) + var/health_multiplier = 1 //how much additional health per level the mob gets (level * health_multiplier) for calculating max health + var/cur_health = 0 + var/max_health = 0 + + //SPAWN PREFERENCES AND VARIABLES + //A note on mob spawn preferences: The mob types also have preferences, which are handled prior to per-mob preferences, so ultimately you use a combined set of preferences + var/list/area_blacklist = list() //list of areas this mob can NOT spawn in (such as the bridge) + var/list/turf_blacklist = list() //list of turfs this mob can NOT spawn on (such as wood floors) + var/list/area_whitelist = list() //list of areas this mob is more likely to spawn in (can be used to reinclude subtypes of blacklisted areas) + var/list/turf_whitelist = list() //list of turfs this mob is more likely to spawn on (can be used to reinclude subtypes of blacklisted turfs) + var/turf/spawn_point //gets set and sent to the game server to spawn its avatar (generated in select_spawn or assigned via set_trap) + var/lifetime = 6000 //number of deciseconds the mob will remain before despawning (REMEMBER: DECISECONDS! So 6000 is 600 seconds which is 10 minutes) + var/is_shiny = 0 //if this gets set at spawn (super rare), the mob is considered "shiny" and will use the shiny icon_state and holographic cards + + //the icon file for mob_hunt stuff is 'icons/effects/mob_hunt.dmi' so reference that for the following vars + var/icon_state_normal = "placeholder" //the icon_state for this mob's normal version + var/icon_state_shiny = "placeholder" //the icon_state for this mob's rare shiney version + + var/is_trap = 0 //if this gets set, the mob is a booby-trap and will electrocute any players that dare attempt to catch it + +/datum/mob_hunt/New(set_trap = 0, turf/trap_turf = null, no_register = 0) + if(set_trap) + level = max_level + is_trap = 1 + spawn_point = trap_turf + else + level = rand(min_level, max_level) + if(prob(1) && prob(1)) + is_shiny = 1 + max_health = base_health + (level * health_multiplier) + cur_health = max_health + if(primary_type) + primary_type = new primary_type() + if(secondary_type) + secondary_type = new secondary_type() + if(no_register) //for booster pack cards + return + if(mob_hunt_server) + if(set_trap) + if(mob_hunt_server.register_trap(src)) + return + else if(select_spawn()) + if(mob_hunt_server.register_spawn(src)) + return + qdel(src) //if you reach this, the datum is just pure clutter, so delete it + +/datum/mob_hunt/proc/select_spawn() + var/list/possible_areas = get_possible_areas() + if(!possible_areas.len) + log_admin("No possible areas to spawn [type] found. Possible code/mapping error?") + return 0 + while(possible_areas.len) + //randomly select an area from our possible_areas list to try spawning in, then remove it from possible_areas so it won't get picked over and over forever. + var/area/spawn_area = locate(pickweight(possible_areas)) + possible_areas -= spawn_area + if(!spawn_area) + break + //clear and generate a fresh list of turfs in the selected area, weighted based on white/black lists + var/list/possible_turfs = get_possible_turfs(spawn_area) + if(!possible_turfs.len) //If we don't have any possible turfs, this attempt was a failure. Try again. + continue + //if we got this far, we're spawning on this attempt, hooray! + spawn_point = pickweight(possible_turfs) + break + if(!spawn_point) + //if we get to this, we failed every attempt to find a suitable turf for EVERY area in our list of possible areas. DAMN. + log_admin("No acceptable turfs to spawn [type] on could be located. Possible code/mapping error, or someone replaced/destroyed all the acceptable turf types?") + return 0 + return 1 + +/datum/mob_hunt/proc/get_possible_areas() + var/list/possible_areas = list() + //setup, sets all station areas (and subtypes) to weight 1 + for(var/A in the_station_areas) + if(A == /area/holodeck) //don't allow holodeck areas as possible spawns since it will allow it to spawn in the holodeck rooms on z2 as well + continue + if(A in possible_areas) + continue + for(var/areapath in typesof(A)) + possible_areas[areapath] = 1 + //primary type preferences + if(primary_type) + for(var/A in primary_type.area_whitelist) + for(var/areapath in typesof(A)) + possible_areas[areapath] += 4 + for(var/A in primary_type.area_blacklist) + for(var/areapath in typesof(A)) + possible_areas[areapath] -= 2 + //secondary type preferences + if(secondary_type) + for(var/A in secondary_type.area_whitelist) + for(var/areapath in typesof(A)) + possible_areas[areapath] += 4 + for(var/A in secondary_type.area_blacklist) + for(var/areapath in typesof(A)) + possible_areas[areapath] -= 2 + //mob preferences + for(var/A in area_whitelist) + for(var/areapath in typesof(A)) + possible_areas[areapath] += 4 + for(var/A in area_blacklist) + for(var/areapath in typesof(A)) + possible_areas[areapath] -= 2 + //removes "bad areas" which shouldn't be on-station but are subtypes of station areas. probably should the unused ones and consider repathing the rest + var/list/bad_areas = list(subtypesof(/area/construction), /area/solar/derelict_starboard, /area/solar/derelict_aft, /area/solar/constructionsite) + for(var/A in bad_areas) + possible_areas -= A + //weight check, remove negative or zero weight areas from the list, then return the list. + for(var/areapath in possible_areas) + //remove any areas that shouldn't be on the station-level + if(possible_areas[areapath] < 1) + possible_areas -= areapath + continue + return possible_areas + +/datum/mob_hunt/proc/get_possible_turfs(area/spawn_area) + if(!spawn_area) + return list() + var/list/possible_turfs = list() + //setup, sets all turfs in spawn_area to weight 1 + for(var/turf/T in spawn_area) + if(!is_station_level(T.z)) //mobs will only consider station-level turfs for spawning. Largely here so we won't have to worry about mapping errors or mobs on the derelict solars + continue + possible_turfs[T] = 1 + //primary type preferences + if(primary_type) + if(is_type_in_list(T, primary_type.turf_whitelist)) + possible_turfs[T] += 4 + if(is_type_in_list(T, primary_type.turf_blacklist)) + possible_turfs[T] -= 2 + //secondary type preferences + if(secondary_type) + if(is_type_in_list(T, secondary_type.turf_whitelist)) + possible_turfs[T] += 4 + if(is_type_in_list(T, secondary_type.turf_blacklist)) + possible_turfs[T] -= 2 + //mob preferences + if(is_type_in_list(T, turf_whitelist)) + possible_turfs[T] += 4 + if(is_type_in_list(T, turf_blacklist)) + possible_turfs[T] -= 2 + //weight check, remove negative or zero weight turfs from the list, then return the list + if(possible_turfs[T] < 1) + possible_turfs -= T + return possible_turfs + +/datum/mob_hunt/proc/calc_def_multiplier(datum/mob_type/attack_type) + if(!primary_type) + return 99 //typeless mobs are weak to everything since they shouldn't exist + if(!attack_type) //typeless attacks will return a multiplier of 1 in case we want to use this for calculating unmodified damage for some reason (UI maybe?) + return 1 + + var/multiplier = 1 + if(attack_type in primary_type.immunity) + return 0 //a single immunity negates all damage + else if(attack_type in primary_type.resistance) + multiplier *= 0.5 + else if(attack_type in primary_type.weakness) + multiplier *= 2 + else + multiplier *= 1 + + if(!secondary_type) //if we don't have a second type, we're done here + return multiplier + if(attack_type in secondary_type.immunity) + return 0 //a single immunity negates all damage + else if(attack_type in secondary_type.resistance) + multiplier *= 0.5 + else if(attack_type in secondary_type.weakness) + multiplier *= 2 + else + multiplier *= 1 + return multiplier + +/datum/mob_hunt/proc/take_damage(raw_damage, datum/mob_type/attack_type) + var/message = "" + var/multiplier = calc_def_multiplier(attack_type) + var/total_damage = raw_damage * multiplier + if(!cur_health) //it's already downed, quit hitting it + return null + if(!total_damage) + message += "The attack is completely ineffective! " + else + cur_health = max(cur_health - total_damage, 0) + switch(multiplier) + if(0) + message += "The attack is completely ineffective! " + if(0.25) + message += "It's barely effective... " + if(0.5) + message += "It's not very effective... " + if(2) + message += "It's super effective! " + if(4) + message += "It's ultra effective! " + if(99) + message += pick("REKT! ", "DUNKED! ", "DEFENSE BREAK! ", "WOMBO-COMBO'D!") + if(!cur_health) + message += "[nickname ? nickname : mob_name] is downed!" + return message + +/datum/mob_hunt/proc/get_raw_damage() + return (level * attack_multiplier) + +/datum/mob_hunt/proc/get_attack_type() + var/datum/mob_type/attack_type = primary_type + if(secondary_type && prob(40)) + attack_type = secondary_type + return attack_type + +/datum/mob_hunt/proc/gain_exp() + exp++ + var/message = "[nickname ? nickname : mob_name] gained EXP! ([exp] / [exp_to_level] EXP)" + if(exp >= exp_to_level) + message = levelup() + return message + +/datum/mob_hunt/proc/levelup() + var/message = "" + level++ + exp = 0 + if(level > max_level) //This is where we would trigger an evolution, when those are added (need to add evolved forms first) + level = max_level //for now though, we'll just cap them back at their max_level + message += "[nickname ? nickname : mob_name] can't get any stronger right now!" + else + max_health = base_health + (level * health_multiplier) + cur_health = max_health //full heal on level-up + message += "[nickname ? nickname : mob_name] has reached level [level]!" + return message + +/datum/mob_hunt/proc/get_type1() + if(!primary_type) + return "Typeless" + else + return primary_type.name + +/datum/mob_hunt/proc/get_type2() + if(!secondary_type) + return null + else + return secondary_type.name + + +/datum/mob_hunt/nemabug + mob_name = "Nemabug" + run_chance = 50 + min_level = 1 + max_level = 10 + primary_type = TYPE_BUG + icon_state_normal = "nemabug" + icon_state_shiny = "nemabug_shiny" + lifetime = 6000 + +/datum/mob_hunt/stoutquill + mob_name = "Stoutquill" + run_chance = 50 + min_level = 5 + max_level = 15 + primary_type = TYPE_ICE + icon_state_normal = "stoutquill" + icon_state_shiny = "stoutquill_shiny" + lifetime = 4500 + +/datum/mob_hunt/spectra + mob_name = "Spectra" + run_chance = 35 + min_level = 1 + max_level = 10 + primary_type = TYPE_POISON + icon_state_normal = "spectra" + icon_state_shiny = "spectra_shiny" + lifetime = 6000 + +/datum/mob_hunt/dunny + mob_name = "Dunny" + run_chance = 35 + min_level = 1 + max_level = 10 + primary_type = TYPE_FIRE + icon_state_normal = "dunny" + icon_state_shiny = "dunny_shiny" + lifetime = 6000 + +/datum/mob_hunt/buffsel + mob_name = "Buffsel" + run_chance = 35 + min_level = 1 + max_level = 10 + primary_type = TYPE_ROCK + icon_state_normal = "buffsel" + icon_state_shiny = "buffsel_shiny" + lifetime = 6000 + +/datum/mob_hunt/quarrel + mob_name = "Quarrel" + run_chance = 35 + min_level = 1 + max_level = 10 + primary_type = TYPE_NORMAL + icon_state_normal = "quarrel" + icon_state_shiny = "quarrel_shiny" + lifetime = 6000 + +/datum/mob_hunt/vulerrt + mob_name = "Vulerrt" + run_chance = 50 + min_level = 5 + max_level = 15 + primary_type = TYPE_DARK + icon_state_normal = "vulerrt" + icon_state_shiny = "vulerrt_shiny" + turf_whitelist = list() + lifetime = 4500 + +/datum/mob_hunt/strudel + mob_name = "Strudel" + run_chance = 35 + min_level = 1 + max_level = 10 + primary_type = TYPE_ELECTRIC + icon_state_normal = "strudel" + icon_state_shiny = "strudel_shiny" + lifetime = 4500 + +/datum/mob_hunt/folstick + mob_name = "Folstick" + run_chance = 35 + min_level = 1 + max_level = 10 + primary_type = TYPE_WATER + icon_state_normal = "folstick" + icon_state_shiny = "folstick_shiny" + lifetime = 6000 + +/datum/mob_hunt/glimmerflare + mob_name = "Glimmerflare" + run_chance = 50 + min_level = 5 + max_level = 15 + primary_type = TYPE_PSYCHIC + icon_state_normal = "glimmerflare" + icon_state_shiny = "glimmerflare_shiny" + lifetime = 4500 + +/datum/mob_hunt/leecoon + mob_name = "Leecoon" + run_chance = 35 + min_level = 1 + max_level = 10 + primary_type = TYPE_GRASS + icon_state_normal = "leecoon" + icon_state_shiny = "leecoon_shiny" + lifetime = 6000 + +/datum/mob_hunt/halk + mob_name = "Halk" + run_chance = 35 + min_level = 1 + max_level = 10 + primary_type = TYPE_FLYING + icon_state_normal = "halk" + icon_state_shiny = "halk_shiny" + lifetime = 6000 + +/datum/mob_hunt/gooby + mob_name = "Gooby" + run_chance = 65 + min_level = 5 + max_level = 20 + primary_type = TYPE_ELECTRIC + secondary_type = TYPE_BUG + icon_state_normal = "gooby" + icon_state_shiny = "gooby_shiny" + lifetime = 3000 + +/datum/mob_hunt/pandoom + mob_name = "Pandoom" + run_chance = 50 + min_level = 5 + max_level = 15 + primary_type = TYPE_GHOST + icon_state_normal = "pandoom" + icon_state_shiny = "pandoom_shiny" + lifetime = 4500 + +/datum/mob_hunt/relish + mob_name = "Relish" + run_chance = 65 + min_level = 5 + max_level = 20 + primary_type = TYPE_FIRE + secondary_type = TYPE_GROUND + icon_state_normal = "relish" + icon_state_shiny = "relish_shiny" + lifetime = 3000 + +/datum/mob_hunt/xofine + mob_name = "Xofine" + run_chance = 50 + min_level = 5 + max_level = 10 + primary_type = TYPE_FIRE + secondary_type = TYPE_NORMAL + icon_state_normal = "xofine" + icon_state_shiny = "xofine_shiny" + lifetime = 3000 + +/datum/mob_hunt/gitten + mob_name = "Gitten" + run_chance = 65 + min_level = 5 + max_level = 20 + primary_type = TYPE_WATER + secondary_type = TYPE_POISON + icon_state_normal = "gitten" + icon_state_shiny = "gitten_shiny" + lifetime = 3000 + +/datum/mob_hunt/nai + mob_name = "Nai" + run_chance = 65 + min_level = 5 + max_level = 20 + primary_type = TYPE_GRASS + secondary_type = TYPE_NORMAL + icon_state_normal = "nai" + icon_state_shiny = "nai_shiny" + lifetime = 3000 + +/datum/mob_hunt/pyroghast + mob_name = "Pyroghast" + run_chance = 65 + min_level = 5 + max_level = 20 + primary_type = TYPE_FIRE + secondary_type = TYPE_GHOST + icon_state_normal = "pyroghast" + icon_state_shiny = "pyroghast" + lifetime = 4500 + +/datum/mob_hunt/starslam + mob_name = "Starslam" + run_chance = 65 + min_level = 5 + max_level = 20 + primary_type = TYPE_FIGHTING + secondary_type = TYPE_ICE + icon_state_normal = "starslam" + icon_state_shiny = "starslam_shiny" + lifetime = 2500 + +/datum/mob_hunt/pheron + mob_name = "Pheron" + run_chance = 85 + min_level = 10 + max_level = 20 + primary_type = TYPE_BLUESPACE + icon_state_normal = "pheron" + icon_state_shiny = "pheron_shiny" + area_blacklist = list() + turf_blacklist = list() + area_whitelist = list() + turf_whitelist = list() + lifetime = 2000 \ No newline at end of file diff --git a/code/modules/arcade/mob_hunt/mob_type_datums.dm b/code/modules/arcade/mob_hunt/mob_type_datums.dm new file mode 100644 index 00000000000..9d27a844ea8 --- /dev/null +++ b/code/modules/arcade/mob_hunt/mob_type_datums.dm @@ -0,0 +1,256 @@ + +/datum/mob_type + var/name = "Typeless" + var/list/weakness = list() + var/list/resistance = list() + var/list/immunity = list() + + //Type-based spawn preferences (to eliminate copy-pasting the same area and turf lists on each mob type) + var/list/area_blacklist = list() //areas to be avoided + var/list/area_whitelist = list() //areas to be more preferred + var/list/turf_blacklist = list() //turf types to be avoided + var/list/turf_whitelist = list() //turf types to be more preferred + +//Type defines, to avoid spelling mistakes +/datum/mob_type/fire + name = "Fire" + weakness = list(TYPE_WATER, + TYPE_ROCK, + TYPE_GROUND) + resistance = list(TYPE_BUG, + TYPE_FIRE, + TYPE_GRASS, + TYPE_ICE, + TYPE_STEEL) + area_blacklist = list(/area/crew_quarters/toilet, + /area/crew_quarters/sleep_male/toilet_male, + /area/crew_quarters/sleep_female/toilet_female, + /area/crew_quarters/locker/locker_toilet, + /area/toxins/server_coldroom) + area_whitelist = list(/area/maintenance/turbine, + /area/maintenance/incinerator, + /area/crew_quarters/kitchen) + turf_blacklist = list(/turf/simulated/floor/beach/water) + +/datum/mob_type/water + name = "Water" + weakness = list(TYPE_ELECTRIC, + TYPE_GRASS) + resistance = list(TYPE_FIRE, + TYPE_ICE, + TYPE_STEEL, + TYPE_WATER) + area_blacklist = list(/area/maintenance/turbine, + /area/maintenance/incinerator, + /area/crew_quarters/kitchen) + area_whitelist = list(/area/crew_quarters/toilet, + /area/crew_quarters/sleep_male/toilet_male, + /area/crew_quarters/sleep_female/toilet_female, + /area/crew_quarters/locker/locker_toilet) + turf_whitelist = list(/turf/simulated/floor/beach/water) + +/datum/mob_type/grass + name = "Grass" + weakness = list(TYPE_FIRE, + TYPE_BUG, + TYPE_POISON, + TYPE_ICE, + TYPE_FLYING) + resistance = list(TYPE_WATER, + TYPE_GRASS, + TYPE_ELECTRIC, + TYPE_GROUND) + area_blacklist = list(/area/toxins) + area_whitelist = list(/area/hydroponics, + /area/hallway/secondary/construction) + turf_whitelist = list(/turf/simulated/floor/grass) + +/datum/mob_type/electric + name = "Electric" + weakness = list(TYPE_GROUND) + resistance = list(TYPE_ELECTRIC, + TYPE_FLYING, + TYPE_STEEL) + area_whitelist = list(/area/engine, + /area/toxins/server, + /area/maintenance, + /area/turret_protected/ai, + /area/turret_protected/ai_upload, + /area/turret_protected/aisat_interior, + /area/aisat, + /area/assembly) + turf_whitelist = list(/turf/simulated/floor/bluegrid) + +/datum/mob_type/ground + name = "Ground" + weakness = list(TYPE_WATER, + TYPE_GRASS, + TYPE_ICE) + resistance = list(TYPE_ROCK, + TYPE_POISON) + immunity = list(TYPE_ELECTRIC) + +/datum/mob_type/rock + name = "Rock" + weakness = list(TYPE_WATER, + TYPE_GRASS, + TYPE_GROUND, + TYPE_FIGHTING, + TYPE_STEEL) + resistance = list(TYPE_FIRE, + TYPE_FLYING, + TYPE_POISON, + TYPE_NORMAL) + area_whitelist = list(/area/quartermaster, + /area/maintenance/disposal) + turf_whitelist = list(/turf/simulated/wall, + /turf/simulated/floor/mineral) + +/datum/mob_type/bug + name = "Bug" + weakness = list(TYPE_FIRE, + TYPE_ROCK, + TYPE_FLYING) + resistance = list(TYPE_GRASS, + TYPE_GROUND, + TYPE_FIGHTING) + area_blacklist = list(/area/toxins) + area_whitelist = list(/area/hydroponics, + /area/hallway/secondary/construction) + turf_whitelist = list(/turf/simulated/floor/grass) + +/datum/mob_type/poison + name = "Poison" + weakness = list(TYPE_GROUND, + TYPE_PSYCHIC) + resistance = list(TYPE_GRASS, + TYPE_BUG, + TYPE_POISON, + TYPE_FIGHTING) + area_blacklist = list(/area/medical, + /area/security/medbay, + /area/janitor) + area_whitelist = list(/area/medical/virology, + /area/toxins, + /area/medical/research, + /area/medical/research_shuttle_dock, + /area/crew_quarters/hor, + /area/maintenance/asmaint2) + +/datum/mob_type/normal + name = "Normal" + weakness = list(TYPE_FIGHTING) + immunity = list(TYPE_GHOST) + +/datum/mob_type/fighting + name = "Fighting" + weakness = list(TYPE_PSYCHIC, + TYPE_FLYING) + resistance = list(TYPE_ROCK, + TYPE_BUG, + TYPE_DARK) + area_blacklist = list(/area/medical) + area_whitelist = list(/area/crew_quarters/bar, + /area/crew_quarters/fitness, + /area/security) + turf_whitelist = list(/turf/simulated/floor/wood) + +/datum/mob_type/psychic + name = "Psychic" + weakness = list(TYPE_BUG, + TYPE_GHOST, + TYPE_DARK) + resistance = list(TYPE_FIGHTING, + TYPE_PSYCHIC) + area_blacklist = list(/area/toxins, + /area/medical/research, + /area/medical/research_shuttle_dock, + /area/crew_quarters/hor, + /area/maintenance/asmaint2, + /area/teleporter, + /area/gateway) + area_whitelist = list(/area/library, + /area/chapel, + /area/medical/psych) + +/datum/mob_type/ghost + name = "Ghost" + weakness = list(TYPE_GHOST, + TYPE_DARK) + resistance = list(TYPE_BUG, + TYPE_POISON) + immunity = list(TYPE_NORMAL, + TYPE_FIGHTING) + area_whitelist = list(/area/medical/morgue, + /area/chapel, + /area/medical/genetics_cloning) + +/datum/mob_type/ice + name = "Ice" + weakness = list(TYPE_FIRE, + TYPE_ROCK, + TYPE_FIGHTING, + TYPE_STEEL) + resistance = list(TYPE_ICE) + area_blacklist = list(/area/maintenance/turbine, + /area/maintenance/incinerator, + /area/crew_quarters/kitchen) + area_whitelist = list(/area/toxins/server_coldroom) + +/datum/mob_type/flying + name = "Flying" + weakness = list(TYPE_ELECTRIC, + TYPE_ROCK, + TYPE_ICE) + resistance = list(TYPE_GRASS, + TYPE_BUG, + TYPE_FIGHTING) + immunity = list(TYPE_GROUND) + area_blacklist = list(/area/maintenance) + area_whitelist = list(/area/hallway, + /area/escapepodbay, + /area/engine/mechanic_workshop, + /area/security/podbay) + +/datum/mob_type/bluespace + name = "Bluespace" + weakness = list(TYPE_ICE, + TYPE_BLUESPACE) + resistance = list(TYPE_FIRE, + TYPE_WATER, + TYPE_GRASS, + TYPE_ELECTRIC) + +/datum/mob_type/dark + name = "Dark" + weakness = list(TYPE_BUG, + TYPE_FIGHTING) + resistance = list(TYPE_GHOST, + TYPE_DARK) + immunity = list(TYPE_PSYCHIC) + area_blacklist = list(/area/solar, + /area/maintenance/auxsolarport, + /area/maintenance/starboardsolar, + /area/maintenance/portsolar, + /area/maintenance/auxsolarstarboard, + /area/clownoffice) + area_whitelist = list(/area/maintenance, + /area/assembly/assembly_line, + /area/mimeoffice) + turf_blacklist = list(/turf/simulated/floor/light) + +/datum/mob_type/steel + name = "Steel" + weakness = list(TYPE_FIRE, + TYPE_GROUND, + TYPE_FIGHTING) + resistance = list(TYPE_GRASS, + TYPE_ROCK, + TYPE_BUG, + TYPE_NORMAL, + TYPE_PSYCHIC, + TYPE_ICE, + TYPE_FLYING, + TYPE_BLUESPACE, + TYPE_STEEL) + immunity = list(TYPE_POISON) \ No newline at end of file diff --git a/code/modules/arcade/prize_datums.dm b/code/modules/arcade/prize_datums.dm index da78a7806ef..9334502dd10 100644 --- a/code/modules/arcade/prize_datums.dm +++ b/code/modules/arcade/prize_datums.dm @@ -190,6 +190,12 @@ var/global/datum/prizes/global_prizes = new typepath = /obj/item/weapon/spellbook/oneuse/fake_gib cost = 100 +/datum/prize_item/nanomob_booster + name = "Nano-Mob Hunter Trading Card Booster Pack" + desc = "Contains 6 random Nano-Mob Hunter Trading Cards. May contain a holographic card!" + typepath = /obj/item/weapon/storage/box/nanomob_booster_pack + cost = 100 + /datum/prize_item/capgun name = "Capgun Revolver" desc = "Do you feel lucky... punk?" diff --git a/code/modules/awaymissions/bluespaceartillery.dm b/code/modules/awaymissions/bluespaceartillery.dm index 9eb71904de5..6b6eb863b45 100644 --- a/code/modules/awaymissions/bluespaceartillery.dm +++ b/code/modules/awaymissions/bluespaceartillery.dm @@ -24,7 +24,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/computer/artillerycontrol/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/artillerycontrol/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/time_to_wait = round(reload_cooldown - ((world.time / 10) - last_fire), 1) diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index 5045b5369a1..cf6da43847b 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -9,14 +9,14 @@ var/obj/machinery/gateway/centerstation/the_gateway = null unacidable = 1 var/active = 0 +/obj/machinery/gateway/initialize() + ..() + update_icon() + update_density_from_dir() -/obj/machinery/gateway/New() - if(!the_gateway) - the_gateway = src - spawn(25) - update_icon() - if(dir == 2) - density = 0 +/obj/machinery/gateway/proc/update_density_from_dir() + if(dir == 2) + density = 0 /obj/machinery/gateway/update_icon() @@ -40,13 +40,18 @@ var/obj/machinery/gateway/centerstation/the_gateway = null var/obj/machinery/gateway/centeraway/awaygate = null /obj/machinery/gateway/centerstation/New() + ..() if(!the_gateway) the_gateway = src - spawn(25) - update_icon() - wait = world.time + config.gateway_delay //+ thirty minutes default - awaygate = locate(/obj/machinery/gateway/centeraway) in world +/obj/machinery/gateway/centerstation/initialize() + ..() + update_icon() + wait = world.time + config.gateway_delay //+ thirty minutes default + awaygate = locate(/obj/machinery/gateway/centeraway) in world + +/obj/machinery/gateway/centerstation/update_density_from_dir() + return /obj/machinery/gateway/centerstation/Destroy() if(the_gateway == src) @@ -61,7 +66,7 @@ var/obj/machinery/gateway/centerstation/the_gateway = null -obj/machinery/gateway/centerstation/process() +/obj/machinery/gateway/centerstation/process() if(stat & (NOPOWER)) if(active) toggleoff() return @@ -165,12 +170,15 @@ obj/machinery/gateway/centerstation/process() var/obj/machinery/gateway/centeraway/stationgate = null -/obj/machinery/gateway/centeraway/New() - spawn(25) - update_icon() - stationgate = locate(/obj/machinery/gateway/centerstation) in world +/obj/machinery/gateway/centeraway/initialize() + ..() + update_icon() + stationgate = locate(/obj/machinery/gateway/centerstation) in world +/obj/machinery/gateway/centeraway/update_density_from_dir() + return + /obj/machinery/gateway/centeraway/update_icon() if(active) icon_state = "oncenter" diff --git a/code/modules/awaymissions/mission_code/stationCollision.dm b/code/modules/awaymissions/mission_code/stationCollision.dm index 7a6480943a7..dcb10c651c0 100644 --- a/code/modules/awaymissions/mission_code/stationCollision.dm +++ b/code/modules/awaymissions/mission_code/stationCollision.dm @@ -161,7 +161,7 @@ var/sc_safecode5 = "[rand(0,9)]" desc = "Your body becomes weak and your feel your mind slipping away as you try to comprehend what you know can't be possible." move_self = 0 //Contianed narsie does not move! grav_pull = 0 //Contained narsie does not pull stuff in! - var/uneatable = list(/turf/space, /obj/effect/overlay, /atom/movable/lighting_overlay, /mob/living/simple_animal/construct) + var/uneatable = list(/turf/space, /obj/effect/overlay, /atom/movable/lighting_overlay, /mob/living/simple_animal/hostile/construct) //Override this to prevent no adminlog runtimes and admin warnings about a singularity without containment /obj/singularity/narsie/sc_Narsie/admin_investigate_setup() diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index 082fc0d930f..e02a1a8d810 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -261,6 +261,8 @@ proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE) send_asset_list(client, uncommon) send_asset_list(client, common) + +//Pill sprites for UIs /datum/asset/chem_master var/assets = list() var/verify = FALSE @@ -274,4 +276,21 @@ proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE) register_asset(asset_name, assets[asset_name]) /datum/asset/chem_master/send(client) - send_asset_list(client,assets,verify) \ No newline at end of file + send_asset_list(client, assets, verify) + + +//Mob Hunt sprites for UIs +/datum/asset/mob_hunt + var/assets = list() + var/verify = FALSE + +/datum/asset/mob_hunt/register() + for(var/state in icon_states('icons/effects/mob_hunt.dmi')) + if(state == "Placeholder") + continue + assets["[state].png"] = icon('icons/effects/mob_hunt.dmi', state) + for(var/asset_name in assets) + register_asset(asset_name, assets[asset_name]) + +/datum/asset/mob_hunt/send(client) + send_asset_list(client, assets, verify) \ No newline at end of file diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 0209b16c40e..6e1fe9126fd 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -111,49 +111,49 @@ to_chat(usr, "You do not have enough karma!") return else - src.DB_job_unlock("Barber",5) + DB_job_unlock("Barber",5) return if("2") if(karma <5) to_chat(usr, "You do not have enough karma!") return else - src.DB_job_unlock("Brig Physician",5) + DB_job_unlock("Brig Physician",5) return if("3") if(karma <30) to_chat(usr, "You do not have enough karma!") return else - src.DB_job_unlock("Nanotrasen Representative",30) + DB_job_unlock("Nanotrasen Representative",30) return if("5") if(karma <30) to_chat(usr, "You do not have enough karma!") return else - src.DB_job_unlock("Blueshield",30) + DB_job_unlock("Blueshield",30) return if("6") if(karma <30) to_chat(usr, "You do not have enough karma!") return else - src.DB_job_unlock("Mechanic",30) + DB_job_unlock("Mechanic",30) return if("7") if(karma <45) to_chat(usr, "You do not have enough karma!") return else - src.DB_job_unlock("Magistrate",45) + DB_job_unlock("Magistrate",45) return if("9") if(karma <30) to_chat(usr, "You do not have enough karma!") return else - src.DB_job_unlock("Security Pod Pilot",30) + DB_job_unlock("Security Pod Pilot",30) return if(href_list["KarmaBuy2"]) var/karma=verify_karma() @@ -163,55 +163,55 @@ to_chat(usr, "You do not have enough karma!") return else - src.DB_species_unlock("Machine",15) + DB_species_unlock("Machine",15) return if("2") if(karma <30) to_chat(usr, "You do not have enough karma!") return else - src.DB_species_unlock("Kidan",30) + DB_species_unlock("Kidan",30) return if("3") if(karma <30) to_chat(usr, "You do not have enough karma!") return else - src.DB_species_unlock("Grey",30) + DB_species_unlock("Grey",30) return if("4") if(karma <45) to_chat(usr, "You do not have enough karma!") return else - src.DB_species_unlock("Vox",45) + DB_species_unlock("Vox",45) return if("5") if(karma <45) to_chat(usr, "You do not have enough karma!") return else - src.DB_species_unlock("Slime People",45) + DB_species_unlock("Slime People",45) return if("6") if(karma <100) to_chat(usr, "You do not have enough karma!") return else - src.DB_species_unlock("Plasmaman",100) + DB_species_unlock("Plasmaman",100) return if("7") if(karma <30) to_chat(usr, "You do not have enough karma!") return else - src.DB_species_unlock("Drask",30) + DB_species_unlock("Drask",30) return if(href_list["KarmaRefund"]) var/type = href_list["KarmaRefundType"] var/job = href_list["KarmaRefund"] var/cost = href_list["KarmaRefundCost"] - src.karmarefund(type,job,cost) + karmarefund(type,job,cost) return switch(href_list["_src_"]) @@ -273,6 +273,7 @@ //CONNECT// /////////// /client/New(TopicData) + var/tdata = TopicData //save this for later use chatOutput = new /datum/chatOutput(src) // Right off the bat. TopicData = null //Prevent calls to client.Topic from connect @@ -290,8 +291,8 @@ // Change the way they should download resources. if(config.resource_urls) - src.preload_rsc = pick(config.resource_urls) - else src.preload_rsc = 1 // If config.resource_urls is not set, preload like normal. + preload_rsc = pick(config.resource_urls) + else preload_rsc = 1 // If config.resource_urls is not set, preload like normal. to_chat(src, "\red If the title screen is black, resources are still downloading. Please be patient until the title screen appears.") @@ -340,7 +341,7 @@ winset(src, null, "command=\".configure graphics-hwmode off\"") winset(src, null, "command=\".configure graphics-hwmode on\"") - log_client_to_db() + log_client_to_db(tdata) if(ckey in clientmessages) for(var/message in clientmessages[ckey]) @@ -399,7 +400,7 @@ donator_level = text2num(query_donor_select.item[2]) break -/client/proc/log_client_to_db() +/client/proc/log_client_to_db(connectiontopic) if(IsGuestKey(key)) return @@ -430,6 +431,14 @@ if(ckey != query_cid.item[1]) related_accounts_cid.Add("[query_cid.item[1]]") + var/admin_rank = "Player" + if(holder) + admin_rank = holder.rank + // Admins don't get slammed by this, I guess + else + if(check_randomizer(connectiontopic)) + return + //Log all the alts if(related_accounts_cid.len) log_access("Alts: [key_name(src)]:[jointext(related_accounts_cid, " - ")]") @@ -446,10 +455,6 @@ if(!isnum(sql_id)) return - var/admin_rank = "Player" - if(src.holder) - admin_rank = src.holder.rank - var/sql_ip = sanitizeSQL(address) var/sql_computerid = sanitizeSQL(computer_id) var/sql_admin_rank = sanitizeSQL(admin_rank) @@ -469,11 +474,128 @@ var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[ckey]','[sql_ip]','[sql_computerid]');") query_accesslog.Execute() - #undef TOPIC_SPAM_DELAY #undef UPLOAD_LIMIT #undef MIN_CLIENT_VERSION +// Returns true if a randomizer is being used +/client/proc/check_randomizer(topic) + . = FALSE + if(connection != "seeker") //Invalid connection type. + return null + topic = params2list(topic) + if(!config.check_randomizer) + return + // Stash o' ckeys + var/static/cidcheck = list() + var/static/tokens = list() + // Ckeys that failed the test, stored to send acceptance messages only for atoners + var/static/cidcheck_failedckeys = list() + var/static/cidcheck_spoofckeys = list() + + var/oldcid = cidcheck[ckey] + + if(!oldcid) + var/DBQuery/query_cidcheck = dbcon.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey = '[ckey]'") + query_cidcheck.Execute() + + var/lastcid = computer_id + if(query_cidcheck.NextRow()) + lastcid = query_cidcheck.item[1] + + if(computer_id != lastcid) + // Their current CID does not match what the DB says - OFF WITH THEIR HEAD + cidcheck[ckey] = computer_id + + // Disable the reconnect button to force a CID change + winset(src, "reconnectbutton", "is-disable=true") + + tokens[ckey] = cid_check_reconnect() + sleep(10) // Since browse is non-instant, and kinda async + + to_chat(src, "
you're a huge nerd. wakka wakka doodle doop nobody's ever gonna see this, the chat system shouldn't be online by this point
") + del(src) + return TRUE + else + if (!topic || !topic["token"] || !tokens[ckey] || topic["token"] != tokens[ckey]) + if (!cidcheck_spoofckeys[ckey]) + message_admins("[key_name(src)] appears to have attempted to spoof a cid randomizer check.") + cidcheck_spoofckeys[ckey] = TRUE + cidcheck[ckey] = computer_id + tokens[ckey] = cid_check_reconnect() + + sleep(10) //browse is queued, we don't want them to disconnect before getting the browse() command. + del(src) + return TRUE + // We DO have their cached CID handy - compare it, now + if(oldcid != computer_id) + // Change detected, they are randomizing + cidcheck -= ckey // To allow them to try again after removing CID randomization + + to_chat(src, "Connection Error:") + to_chat(src, "Invalid ComputerID(spoofed). Please remove the ComputerID spoofer from your BYOND installation and try again.") + + if(!cidcheck_failedckeys[ckey]) + message_admins("[key_name(src)] has been detected as using a CID randomizer. Connection rejected.") + send2irc(config.cidrandomizer_irc, "[key_name(src)] has been detected as using a CID randomizer. Connection rejected.") + cidcheck_failedckeys[ckey] = TRUE + note_randomizer_user() + + log_access("Failed Login: [key] [computer_id] [address] - CID randomizer confirmed (oldcid: [oldcid])") + + del(src) + return TRUE + else + // don't shoot, I'm innocent + if(cidcheck_failedckeys[ckey]) + // Atonement + message_admins("[key_name_admin(src)] has been allowed to connect after showing they removed their cid randomizer") + send2irc(config.cidrandomizer_irc, "[key_name(src)] has been allowed to connect after showing they removed their cid randomizer.") + cidcheck_failedckeys -= ckey + if (cidcheck_spoofckeys[ckey]) + message_admins("[key_name_admin(src)] has been allowed to connect after appearing to have attempted to spoof a cid randomizer check because it appears they aren't spoofing one this time") + cidcheck_spoofckeys -= ckey + cidcheck -= ckey + +/client/proc/note_randomizer_user() + var/const/adminckey = "CID-Error" + + // Check for notes in the last day - only 1 note per 24 hours + var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT id from [format_table_name("notes")] WHERE ckey = '[ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW()") + if(!query_get_notes.Execute()) + var/err = query_get_notes.ErrorMsg() + log_game("SQL ERROR obtaining id from notes table. Error : \[[err]\]\n") + return + if(query_get_notes.NextRow()) + return + + // Only add a note if their most recent note isn't from the randomizer blocker, either + query_get_notes = dbcon.NewQuery("SELECT adminckey FROM [format_table_name("notes")] WHERE ckey = '[ckey]' ORDER BY timestamp DESC LIMIT 1") + if(!query_get_notes.Execute()) + var/err = query_get_notes.ErrorMsg() + log_game("SQL ERROR obtaining adminckey from notes table. Error : \[[err]\]\n") + return + if(query_get_notes.NextRow()) + if(query_get_notes.item[1] == adminckey) + return + add_note(ckey, "Detected as using a cid randomizer.", null, adminckey, logged = 0) + +/client/proc/cid_check_reconnect() + var/token = md5("[rand(0,9999)][world.time][rand(0,9999)][ckey][rand(0,9999)][address][rand(0,9999)][computer_id][rand(0,9999)]") + . = token + log_access("Failed Login: [key] [computer_id] [address] - CID randomizer check") + var/url = winget(src, null, "url") + //special javascript to make them reconnect under a new window. + src << browse("\ + byond://[url]?token=[token]\ + \ + ", + "border=0;titlebar=0;size=1x1") + to_chat(src, "You will be automatically taken to the game, if not, click here to be taken manually. Except you can't, since the chat window doesn't exist yet.") + //checks if a client is afk //3000 frames = 5 minutes /client/proc/is_afk(duration=3000) diff --git a/code/modules/client/preference/loadout/loadout_general.dm b/code/modules/client/preference/loadout/loadout_general.dm index 347447f892f..919a77a44e8 100644 --- a/code/modules/client/preference/loadout/loadout_general.dm +++ b/code/modules/client/preference/loadout/loadout_general.dm @@ -74,3 +74,8 @@ /datum/gear/skullbandana display_name = "bandana, skull" path = /obj/item/clothing/mask/bandana/skull + +/datum/gear/mob_hunt_game + display_name = "Nano-Mob Hunter GO! Cartridge" + path = /obj/item/weapon/cartridge/mob_hunt_game + cost = 2 diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index c049852e3be..bf139ee4c8b 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -82,6 +82,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts //game-preferences var/lastchangelog = "" //Saved changlog filesize to detect if there was a change + var/exp var/ooccolor = "#b82e00" var/be_special = list() //Special role selection var/UI_style = "Midnight" @@ -593,6 +594,10 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if(jobban_isbanned(user, rank)) HTML += "[rank] \[BANNED]" continue + var/available_in_playtime = job.available_in_playtime(user.client) + if(available_in_playtime) + HTML += "[rank] \[ " + get_exp_format(available_in_playtime) + " as " + job.get_exp_req_type() + " \]" + continue if(!job.player_old_enough(user.client)) var/available_in_days = job.available_in_days(user.client) HTML += "[rank] \[IN [(available_in_days)] DAYS]" diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm index 1425f714183..581daf222d3 100644 --- a/code/modules/client/preference/preferences_mysql.dm +++ b/code/modules/client/preference/preferences_mysql.dm @@ -13,7 +13,8 @@ volume, nanoui_fancy, show_ghostitem_attack, - lastchangelog + lastchangelog, + exp FROM [format_table_name("player")] WHERE ckey='[C.ckey]'"} ) @@ -40,6 +41,7 @@ nanoui_fancy = text2num(query.item[11]) show_ghostitem_attack = text2num(query.item[12]) lastchangelog = query.item[13] + exp = query.item[14] //Sanitize ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) @@ -54,6 +56,7 @@ nanoui_fancy = sanitize_integer(nanoui_fancy, 0, 1, initial(nanoui_fancy)) show_ghostitem_attack = sanitize_integer(show_ghostitem_attack, 0, 1, initial(show_ghostitem_attack)) lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) + exp = sanitize_text(exp, initial(exp)) return 1 /datum/preferences/proc/save_preferences(client/C) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index ab5f8832ab3..078f83f506a 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -154,7 +154,7 @@ var/invis_override = 0 var/emagged = 0 - var/color_view = null//overrides client.color while worn + var/list/color_view = null//overrides client.color while worn var/prescription = 0 var/prescription_upgradable = 0 strip_delay = 20 // but seperated to allow items to protect but not impair vision, like space helmets diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index f8ff3ea4ecc..4fde338ba54 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -243,26 +243,35 @@ return 1 /obj/item/clothing/glasses/sunglasses/noir/proc/toggle_noir() + var/list/difference = difflist(usr.client.color, color_view) + if(!noir_mode) - if(color_view && usr.client && !usr.client.color) + if(color_view && usr.client && (!usr.client.color || difference)) animate(usr.client, color = color_view, time = 10) noir_mode = 1 else - if(usr.client && usr.client.color) - animate(usr.client, color = null, time = 10) + if(usr.client && usr.client.color && !difference) + animate(usr.client, color = initial(usr.client.color), time = 10) noir_mode = 0 /obj/item/clothing/glasses/sunglasses/noir/equipped(mob/user, slot) + var/list/difference = difflist(user.client.color, color_view) + if(slot == slot_glasses) if(noir_mode) - if(color_view && user.client && !user.client.color) + if(color_view && user.client && (!user.client.color || difference.len)) animate(user.client, color = color_view, time = 10) + else + if(user.client && user.client.color && !difference.len) + animate(user.client, color = initial(user.client.color), time = 10) ..(user, slot) /obj/item/clothing/glasses/sunglasses/noir/dropped(mob/living/carbon/human/user) + var/list/difference = difflist(user.client.color, color_view) + if(istype(user) && user.glasses == src) - if(user.client && user.client.color) - animate(user.client, color = null, time = 10) + if(user.client && user.client.color && !difference.len) + animate(user.client, color = initial(user.client.color), time = 10) ..(user) /obj/item/clothing/glasses/sunglasses/yeah diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm index 7e5dfcad115..2ebd01a9162 100644 --- a/code/modules/clothing/spacesuits/rig/rig.dm +++ b/code/modules/clothing/spacesuits/rig/rig.dm @@ -514,7 +514,7 @@ ui.open() ui.set_auto_update(1) -/obj/item/weapon/rig/ui_data(mob/user, datum/topic_state/state = inventory_state) +/obj/item/weapon/rig/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state) var/data[0] data["primarysystem"] = null diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index 63875ee04ee..df0f6916530 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -313,6 +313,11 @@ icon_state = "eyepro" item_state = "eyepro" +/obj/item/clothing/glasses/hud/security/sunglasses/fluff/voxxyhud //LP Spartan: Kaskreyarawkta + name = "VoxxyHUD" + desc = "A worn down visor from a vox raider's gear, crudely ripped from its helmet and linked into the security systems of the station. The word 'Kask' is scratched into the side." + icon_state = "hud-spartan" + //////////// Hats //////////// /obj/item/clothing/head/fluff/heather_winceworth // Regens: Heather Winceworth name= "Heather's rose" diff --git a/code/modules/economy/Accounts_DB.dm b/code/modules/economy/Accounts_DB.dm index 1b238acea6e..44299826454 100644 --- a/code/modules/economy/Accounts_DB.dm +++ b/code/modules/economy/Accounts_DB.dm @@ -83,7 +83,7 @@ ui = new(user, src, ui_key, "accounts_terminal.tmpl", src.name, 400, 640) ui.open() -/obj/machinery/computer/account_database/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/account_database/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["src"] = UID() diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index 528cf45a209..03aacf07796 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -325,7 +325,7 @@ ui = new(user, src, ui_key, "smartfridge.tmpl", name, 400, 500) ui.open() -/obj/machinery/smartfridge/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/smartfridge/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["contents"] = null diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 22fb9156004..4343bc75686 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -634,14 +634,20 @@ chems[rid] = gene_chem.Copy() continue + // Normally a length 2 list - but sometimes, it's length 1 - poisonberries, etc. + // This means the reagent does not scale with potency. + // Index 1 is the base value, index 2 is the potency per u of reagent + var/list/rgnt_list = chems[rid] + rgnt_list.len = max(gene_chem.len, rgnt_list.len) + for(var/i=1;i<=gene_chem.len;i++) if(isnull(gene_chem[i])) gene_chem[i] = 0 - if(chems[rid][i]) - chems[rid][i] = max(1,round((gene_chem[i] + chems[rid][i])/2)) + if(rgnt_list[i]) + rgnt_list[i] = max(1,round((gene_chem[i] + rgnt_list[i])/2)) else - chems[rid][i] = gene_chem[i] + rgnt_list[i] = gene_chem[i] var/list/new_gasses = gene.values["[TRAIT_EXUDE_GASSES]"] if(islist(new_gasses)) diff --git a/code/modules/hydroponics/seed_machines.dm b/code/modules/hydroponics/seed_machines.dm index c50503d7aa5..7e21e12370e 100644 --- a/code/modules/hydroponics/seed_machines.dm +++ b/code/modules/hydroponics/seed_machines.dm @@ -166,7 +166,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/botany/extractor/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/botany/extractor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/list/geneMasks[0] @@ -318,7 +318,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/botany/editor/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/botany/editor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["activity"] = active diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index a1fc5699d62..9954b8e12b2 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -240,17 +240,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(mind.current.key && copytext(mind.current.key,1,2)!="@") //makes sure we don't accidentally kick any clients to_chat(usr, "Another consciousness is in your body...It is resisting you.") return - if(mind.current.ajourn && mind.current.stat != DEAD) //check if the corpse is astral-journeying (it's client ghosted using a cultist rune). - var/turf/T = get_turf(mind.current) - var/found_astral_rune = 0 - if(T) - for(var/obj/effect/rune/R in T.contents) //whilst corpse is alive, we can only reenter the body if it's on the rune - if(R.word1 == cultwords["hell"] && R.word2 == cultwords["travel"] && R.word3 == cultwords["self"]) //astral journeying rune - found_astral_rune = 1 - break - if(!found_astral_rune) - to_chat(usr, "The astral cord that ties your body and your spirit has been severed. You are likely to wander the realm beyond until your body is finally dead and thus reunited with you.") - return mind.current.ajourn=0 mind.current.key = key diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index ecdc6a0220a..be6fa4a6c39 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -48,7 +48,7 @@ continue if(findtext(message," snores.")) //Because we have so many sleeping people. break - if(M.stat == 2 && (M.client.prefs.toggles & CHAT_GHOSTSIGHT) && !(M in viewers(src,null))) + if(M.stat == DEAD && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src,null))) M.show_message(message) @@ -118,8 +118,8 @@ if(istype(M, /mob/new_player)) continue - if(check_rights(R_ADMIN|R_MOD, 0, M) && (M.client.prefs.toggles & CHAT_DEAD)) // Show the emote to admins/mods + if(check_rights(R_ADMIN|R_MOD, 0, M) && M.get_preference(CHAT_DEAD)) // Show the emote to admins/mods to_chat(M, message) - else if(M.stat == DEAD && (M.client.prefs.toggles & CHAT_DEAD)) // Show the emote to regular ghosts with deadchat toggled on + else if(M.stat == DEAD && M.get_preference(CHAT_DEAD)) // Show the emote to regular ghosts with deadchat toggled on M.show_message(message, 2) diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm index c9e410d9e9b..be101742dfa 100644 --- a/code/modules/mob/language.dm +++ b/code/modules/mob/language.dm @@ -428,6 +428,19 @@ flags = RESTRICTED | HIVEMIND follow = 1 + +/datum/language/terrorspider + name = "Spider Hivemind" + desc = "Terror spiders have a limited ability to commune over a psychic hivemind, similar to xenomorphs." + speech_verb = "chitters" + ask_verb = "chitters" + exclaim_verb = "chitters" + colour = "terrorspider" + key = "ts" + flags = RESTRICTED | HIVEMIND + follow = 1 + + /datum/language/ling name = "Changeling" desc = "Although they are normally wary and suspicious of each other, changelings can commune over a distance." @@ -559,7 +572,7 @@ flags = RESTRICTED | HIVEMIND drone_only = 1 follow = 1 - + /datum/language/drone name = "Drone" desc = "An encrypted stream of data converted to speech patterns." diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index a26b5e967af..fed16671887 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -454,8 +454,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, totalMembers |= pipeline.other_atmosmch for(var/obj/machinery/atmospherics/A in totalMembers) if(!A.pipe_image) - A.pipe_image = image(A, A.loc, layer = 20, dir = A.dir) //the 20 puts it above Byond's darkness (not its opacity view) - A.pipe_image.plane = HUD_PLANE + A.update_pipe_image() pipes_shown += A.pipe_image client.images += A.pipe_image diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 37826ae0a10..558a6f8e9de 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -868,7 +868,7 @@ for(var/mob/M in dead_mob_list) if(!M.client || istype(M, /mob/new_player)) continue //skip monkeys, leavers and new players - if(M.stat == DEAD && (M.client.prefs.toggles & CHAT_GHOSTSIGHT) && !(M in viewers(src,null))) + if(M.stat == DEAD && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src,null))) M.show_message(message) switch(m_type) diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 933c1ddfc85..3c06ac497d7 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -603,15 +603,6 @@ It'll return null if the organ doesn't correspond, so include null checks when u if(E.see_invisible) H.see_invisible = min(H.see_invisible, E.see_invisible) - - if(H.seer == 1) - var/obj/effect/rune/R = locate() in H.loc - if(R && R.word1 == cultwords["see"] && R.word2 == cultwords["hell"] && R.word3 == cultwords["join"]) - H.see_invisible = SEE_INVISIBLE_OBSERVER - else - H.see_invisible = SEE_INVISIBLE_LIVING - H.seer = 0 - var/lesser_darkview_bonus = INFINITY // my glasses, I can't see without my glasses if(H.glasses) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 5deb73d219f..b85146b8b63 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -113,6 +113,7 @@ handle_sleeping() handle_slowed() handle_drunk() + handle_cultslurring() /mob/living/proc/handle_stunned() @@ -149,6 +150,11 @@ AdjustSlur(-1) return slurring +/mob/living/proc/handle_cultslurring() + if(cultslurring) + AdjustCultSlur(-1) + return cultslurring + /mob/living/proc/handle_paralysed() if(paralysis) AdjustParalysis(-1, updating = 1, force = 1) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0605c716b48..df6e913007e 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -683,7 +683,7 @@ /mob/living/narsie_act() if(client) - makeNewConstruct(/mob/living/simple_animal/construct/harvester, src, null, 1) + makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, null, 1) spawn_dust() gib() return diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 3987b709e3e..d5a1580ded9 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -79,7 +79,10 @@ proc/get_radio_key_from_channel(var/channel) message = stutter(message) verb = "stammers" speech_problem_flag = 1 - + if(cultslurring) + message = cultslur(message) + verb = "slurs" + speech_problem_flag = 1 if(!IsVocal()) message = "" speech_problem_flag = 1 @@ -241,7 +244,7 @@ proc/get_radio_key_from_channel(var/channel) continue //skip monkeys and leavers if(isnewplayer(M)) continue - if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS) && client) // client is so that ghosts don't have to listen to mice + if(M.stat == DEAD && M.client && M.get_preference(CHAT_GHOSTEARS) && client) // client is so that ghosts don't have to listen to mice listening |= M continue if(get_turf(M) in hearturfs) @@ -285,8 +288,8 @@ proc/get_radio_key_from_channel(var/channel) if(client.prefs.muted & MUTE_IC) to_chat(src, "You cannot speak in IC (Muted).") return - - if(stat) + + if(stat) return 0 if(..(act, type, message)) @@ -299,7 +302,7 @@ proc/get_radio_key_from_channel(var/channel) if(!M.client || istype(M, /mob/new_player)) continue //skip monkeys, leavers and new players //who the hell knows why new players are in the dead mob list - if(M.stat == DEAD && (M.client.prefs.toggles & CHAT_GHOSTSIGHT) && !(M in viewers(src,null))) + if(M.stat == DEAD && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src,null))) M.show_message(message) switch(type) @@ -399,7 +402,7 @@ proc/get_radio_key_from_channel(var/channel) for(var/mob/M in dead_mob_list) //does this include players who joined as observers as well? if(!M.client) continue - if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS)) + if(M.stat == DEAD && M.client && M.get_preference(CHAT_GHOSTEARS)) listening |= M //Pass whispers on to anything inside the immediate listeners. diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index fe0924880f2..94814045871 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -47,10 +47,12 @@ to_chat(src, "Alert cancelled. Power has been restored without our assistance.") aiRestorePowerRoutine = 0 clear_fullscreen("blind") + update_sight() else if(aiRestorePowerRoutine == 3) to_chat(src, "Alert cancelled. Power has been restored.") aiRestorePowerRoutine = 0 clear_fullscreen("blind") + update_sight() else diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 43249060652..d0aeb8b9fa7 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -114,8 +114,6 @@ C.toff = 1 ..() -/mob/living/silicon/pai/Login() - ..() // this function shows the information about being silenced as a pAI in the Status panel /mob/living/silicon/pai/proc/show_silenced() diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index ed5ba8ce49a..4847931e543 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -41,7 +41,12 @@ var/global/list/default_pai_software = list() if(ui_key != "main") var/datum/pai_software/S = software[ui_key] if(S && !S.toggle) - S.on_ui_interact(src, ui, force_open) + ui = nanomanager.try_update_ui(user, src, S.id, ui, force_open) + if(!ui) + ui = new(user, src, S.id, S.template_file, S.ui_title, S.ui_width, S.ui_height, state = state) + ui.open() + if(S.autoupdate) + ui.set_auto_update(1) else if(ui) ui.set_status(STATUS_CLOSE, 0) @@ -53,9 +58,15 @@ var/global/list/default_pai_software = list() ui.open() ui.set_auto_update(1) -/mob/living/silicon/pai/ui_data(mob/user, datum/topic_state/state = self_state) +/mob/living/silicon/pai/ui_data(mob/user, ui_key = "main", datum/topic_state/state = self_state) var/data[0] + if(ui_key != "main") + var/datum/pai_software/S = software[ui_key] + if(S && !S.toggle) + return S.on_ui_data(user, state) + log_runtime(EXCEPTION("Unrecognized/invalid pAI UI state '[ui_key]'"), src) + return // Software we have bought var/bought_software[0] // Software we have not bought diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm index 104c2746d16..12f94d5fe64 100644 --- a/code/modules/mob/living/silicon/pai/software_modules.dm +++ b/code/modules/mob/living/silicon/pai/software_modules.dm @@ -7,18 +7,25 @@ var/id = "" // Whether this software is a toggle or not // Toggled software should override toggle() and is_active() - // Non-toggled software should override on_ui_interact() and Topic() + // Non-toggled software should override on_ui_data() and Topic() var/toggle = 1 // Whether pAIs should automatically receive this module at no cost var/default = 0 - proc/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + // Vars for pAI nanoUI handling + var/autoupdate = 0 + var/template_file = "oops" + var/ui_title = "somebody forgot to set this" + var/ui_width = 450 + var/ui_height = 600 + +/datum/pai_software/proc/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + return list() + +/datum/pai_software/proc/toggle(mob/living/silicon/pai/user) return - proc/toggle(mob/living/silicon/pai/user) - return - - proc/is_active(mob/living/silicon/pai/user) +/datum/pai_software/proc/is_active(mob/living/silicon/pai/user) return 0 /datum/pai_software/directives @@ -28,54 +35,52 @@ toggle = 0 default = 1 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] + template_file = "pai_directives.tmpl" + ui_title = "pAI Directives" + autoupdate = 1 - data["master"] = user.master - data["dna"] = user.master_dna - data["prime"] = user.pai_law0 - data["supplemental"] = user.pai_laws +/datum/pai_software/directives/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["master"] = user.master + data["dna"] = user.master_dna + data["prime"] = user.pai_law0 + data["supplemental"] = user.pai_laws - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return + return data - if(href_list["getdna"]) - var/mob/living/M = P.loc - var/count = 0 +/datum/pai_software/directives/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return - // Find the carrier - while(!istype(M, /mob/living)) - if(!M || !M.loc || count > 6) - //For a runtime where M ends up in nullspace (similar to bluespace but less colourful) - to_chat(P, "You are not being carried by anyone!") - return 0 - M = M.loc - count++ + if(href_list["getdna"]) + var/mob/living/M = P.loc + var/count = 0 - // Check the carrier - var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No") - if(answer == "Yes") - var/turf/T = get_turf_or_move(P.loc) - for(var/mob/v in viewers(T)) - v.show_message("[M] presses \his thumb against [P].", 3, "[P] makes a sharp clicking sound as it extracts DNA material from [M].", 2) - var/datum/dna/dna = M.dna - to_chat(P, "

[M]'s UE string : [dna.unique_enzymes]

") - if(dna.unique_enzymes == P.master_dna) - to_chat(P, "DNA is a match to stored Master DNA.") - else - to_chat(P, "DNA does not match stored Master DNA.") + // Find the carrier + while(!istype(M, /mob/living)) + if(!M || !M.loc || count > 6) + //For a runtime where M ends up in nullspace (similar to bluespace but less colourful) + to_chat(P, "You are not being carried by anyone!") + return 0 + M = M.loc + count++ + + // Check the carrier + var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No") + if(answer == "Yes") + var/turf/T = get_turf_or_move(P.loc) + for(var/mob/v in viewers(T)) + v.show_message("[M] presses \his thumb against [P].", 3, "[P] makes a sharp clicking sound as it extracts DNA material from [M].", 2) + var/datum/dna/dna = M.dna + to_chat(P, "

[M]'s UE string : [dna.unique_enzymes]

") + if(dna.unique_enzymes == P.master_dna) + to_chat(P, "DNA is a match to stored Master DNA.") else - to_chat(P, "[M] does not seem like \he is going to provide a DNA sample willingly.") - return 1 + to_chat(P, "DNA does not match stored Master DNA.") + else + to_chat(P, "[M] does not seem like \he is going to provide a DNA sample willingly.") + return 1 /datum/pai_software/radio_config name = "Radio Configuration" @@ -84,35 +89,35 @@ toggle = 0 default = 1 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1) - var/data[0] + template_file = "pai_radio.tmpl" + ui_title = "Radio Configuration" + ui_width = 300 + ui_height = 150 - data["listening"] = user.radio.broadcasting - data["frequency"] = format_frequency(user.radio.frequency) +/datum/pai_software/radio_config/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] - var/channels[0] - for(var/ch_name in user.radio.channels) - var/ch_stat = user.radio.channels[ch_name] - var/ch_dat[0] - ch_dat["name"] = ch_name - // FREQ_LISTENING is const in /obj/item/device/radio - ch_dat["listening"] = !!(ch_stat & user.radio.FREQ_LISTENING) - channels[++channels.len] = ch_dat + data["listening"] = user.radio.broadcasting + data["frequency"] = format_frequency(user.radio.frequency) + var/channels[0] + for(var/ch_name in user.radio.channels) + var/ch_stat = user.radio.channels[ch_name] + var/ch_dat[0] + ch_dat["name"] = ch_name + // FREQ_LISTENING is const in /obj/item/device/radio + ch_dat["listening"] = !!(ch_stat & user.radio.FREQ_LISTENING) + channels[++channels.len] = ch_dat - data["channels"] = channels + data["channels"] = channels - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150) - ui.set_initial_data(data) - ui.open() + return data - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return +/datum/pai_software/radio_config/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return - P.radio.Topic(href, href_list) - return 1 + P.radio.Topic(href, href_list) + return 1 /datum/pai_software/crew_manifest name = "Crew Manifest" @@ -120,19 +125,17 @@ id = "manifest" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + autoupdate = 1 + template_file = "pai_manifest.tmpl" + ui_title = "Crew Manifest" - var/data[0] - data_core.get_manifest_json() - data["manifest"] = PDA_Manifest +/datum/pai_software/crew_manifest/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_manifest.tmpl", "Crew Manifest", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data_core.get_manifest_json() + data["manifest"] = PDA_Manifest + + return data /datum/pai_software/messenger name = "Digital Messenger" @@ -140,88 +143,88 @@ id = "messenger" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] + autoupdate = 1 + template_file = "pai_messenger.tmpl" + ui_title = "Digital Messenger" - if(!user.pda) - return - var/datum/data/pda/app/messenger/M = user.pda.find_program(/datum/data/pda/app/messenger) +/datum/pai_software/messenger/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] + + if(!user.pda) + log_runtime(EXCEPTION("pAI found without PDA."), user) + return data + var/datum/data/pda/app/messenger/M = user.pda.find_program(/datum/data/pda/app/messenger) + if(!M) + log_runtime(EXCEPTION("pAI PDA lacks a messenger program"), user) + return data + + data["receiver_off"] = M.toff + data["ringer_off"] = M.notify_silent + data["current_ref"] = null + data["current_name"] = user.current_pda_messaging + + var/pdas[0] + if(!M.toff) + for(var/obj/item/device/pda/P in PDAs) + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if(P == user.pda || !PM || !PM.can_receive()) + continue + var/pda[0] + pda["name"] = "[P]" + pda["owner"] = "[P.owner]" + pda["ref"] = "\ref[P]" + if(P.owner == user.current_pda_messaging) + data["current_ref"] = "\ref[P]" + pdas[++pdas.len] = pda + + data["pdas"] = pdas + + var/messages[0] + if(user.current_pda_messaging) + for(var/index in M.tnote) + if(index["owner"] != user.current_pda_messaging) + continue + var/msg[0] + var/sent = index["sent"] + msg["sent"] = sent ? 1 : 0 + msg["target"] = index["owner"] + msg["message"] = index["message"] + messages[++messages.len] = msg + + data["messages"] = messages + + return data + +/datum/pai_software/messenger/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(!isnull(P.pda)) + var/datum/data/pda/app/messenger/M = P.pda.find_program(/datum/data/pda/app/messenger) if(!M) return - data["receiver_off"] = M.toff - data["ringer_off"] = M.notify_silent - data["current_ref"] = null - data["current_name"] = user.current_pda_messaging + if(href_list["toggler"]) + M.toff = href_list["toggler"] != "1" + return 1 + else if(href_list["ringer"]) + M.notify_silent = href_list["ringer"] != "1" + return 1 + else if(href_list["select"]) + var/s = href_list["select"] + if(s == "*NONE*") + P.current_pda_messaging = null + else + P.current_pda_messaging = s + return 1 + else if(href_list["target"]) + if(P.silence_time) + return alert("Communications circuits remain uninitialized.") - var/pdas[0] - if(!M.toff) - for(var/obj/item/device/pda/P in PDAs) - var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) - - if(P == user.pda || !PM || !PM.can_receive()) - continue - var/pda[0] - pda["name"] = "[P]" - pda["owner"] = "[P.owner]" - pda["ref"] = "\ref[P]" - if(P.owner == user.current_pda_messaging) - data["current_ref"] = "\ref[P]" - pdas[++pdas.len] = pda - - data["pdas"] = pdas - - var/messages[0] - if(user.current_pda_messaging) - for(var/index in M.tnote) - if(index["owner"] != user.current_pda_messaging) - continue - var/msg[0] - var/sent = index["sent"] - msg["sent"] = sent ? 1 : 0 - msg["target"] = index["owner"] - msg["message"] = index["message"] - messages[++messages.len] = msg - - data["messages"] = messages - - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_messenger.tmpl", "Digital Messenger", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return - - if(!isnull(P.pda)) - var/datum/data/pda/app/messenger/M = P.pda.find_program(/datum/data/pda/app/messenger) - if(!M) - return - - if(href_list["toggler"]) - M.toff = href_list["toggler"] != "1" - return 1 - else if(href_list["ringer"]) - M.notify_silent = href_list["ringer"] != "1" - return 1 - else if(href_list["select"]) - var/s = href_list["select"] - if(s == "*NONE*") - P.current_pda_messaging = null - else - P.current_pda_messaging = s - return 1 - else if(href_list["target"]) - if(P.silence_time) - return alert("Communications circuits remain uninitialized.") - - var/target = locate(href_list["target"]) - M.create_message(P, target, 1) - return 1 + var/target = locate(href_list["target"]) + M.create_message(P, target, 1) + return 1 /datum/pai_software/chatroom name = "Digital Chatroom" @@ -229,116 +232,116 @@ id = "chatroom" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] + autoupdate = 1 + template_file = "pai_chatroom.tmpl" + ui_title = "Digital Chatroom" - if(!user.pda) - return - var/datum/data/pda/app/chatroom/M = user.pda.find_program(/datum/data/pda/app/chatroom) +/datum/pai_software/chatroom/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] + + if(!user.pda) + log_runtime(EXCEPTION("pAI found without PDA."), user) + return data + var/datum/data/pda/app/chatroom/M = user.pda.find_program(/datum/data/pda/app/chatroom) + if(!M) + log_runtime(EXCEPTION("pAI PDA lacks a chatroom program"), user) + return data + + data["receiver_off"] = M.toff + data["ringer_off"] = M.notify_silent + + var/list/rooms[0] + for(var/datum/chatroom/c in chatrooms) + if((M in c.users) || (M in c.invites) || c.is_public) + rooms += list(list(name = "[c]", ref = "\ref[c]")) + data["rooms"] = rooms + + if(M.disconnected || !M.messaging_available(1)) + data["disconnected"] = 1 + else if(M.current_room) + data["current_room"] = "\ref[M.current_room]" + data["current_room_name"] = M.current_room.name + data["current_room_topic"] = M.current_room.topic + data["messages"] = M.current_room.logs + var/list/users[0] + for(var/U in M.current_room.users) + var/datum/data/pda/app/chatroom/ch = U + users += "[ch.pda.owner]" + for(var/U in (M.current_room.invites - M.current_room.users)) + var/datum/data/pda/app/chatroom/ch = U + users += "[ch.pda.owner]" + data["users"] = users + + return data + +/datum/pai_software/chatroom/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) + return + + if(!isnull(P.pda) && P.pda.can_use()) + var/datum/data/pda/app/chatroom/M = P.pda.find_program(/datum/data/pda/app/chatroom) if(!M) return - data["receiver_off"] = M.toff - data["ringer_off"] = M.notify_silent - - var/list/rooms[0] - for(var/datum/chatroom/c in chatrooms) - if((M in c.users) || (M in c.invites) || c.is_public) - rooms += list(list(name = "[c]", ref = "\ref[c]")) - data["rooms"] = rooms - - if(M.disconnected || !M.messaging_available(1)) - data["disconnected"] = 1 - else if(M.current_room) - data["current_room"] = "\ref[M.current_room]" - data["current_room_name"] = M.current_room.name - data["current_room_topic"] = M.current_room.topic - data["messages"] = M.current_room.logs - var/list/users[0] - for(var/U in M.current_room.users) - var/datum/data/pda/app/chatroom/ch = U - users += "[ch.pda.owner]" - for(var/U in (M.current_room.invites - M.current_room.users)) - var/datum/data/pda/app/chatroom/ch = U - users += "[ch.pda.owner]" - data["users"] = users - - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_chatroom.tmpl", "Digital Chatroom", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) - return - - if(!isnull(P.pda) && P.pda.can_use()) - var/datum/data/pda/app/chatroom/M = P.pda.find_program(/datum/data/pda/app/chatroom) - if(!M) - return - - if(href_list["toggler"]) - M.toff = href_list["toggler"] != "1" + if(href_list["toggler"]) + M.toff = href_list["toggler"] != "1" + return 1 + else if(href_list["ringer"]) + M.notify_silent = href_list["ringer"] != "1" + return 1 + else if(href_list["topic"]) + if(!M.current_room) return 1 - else if(href_list["ringer"]) - M.notify_silent = href_list["ringer"] != "1" - return 1 - else if(href_list["topic"]) - if(!M.current_room) - return 1 - var/t = input("Enter new topic:", M.current_room, M.current_room.topic) as text|null + var/t = input("Enter new topic:", M.current_room, M.current_room.topic) as text|null + spawn() + if(!t || !M.check_messaging_available() || !P.pda.can_use()) + return + t = sanitize(copytext(t, 1, MAX_MESSAGE_LEN)) + t = readd_quotes(t) + if(!t) + return + + M.current_room.topic = t + M.current_room.announce(M, "Topic has been changed to '[t]' by [P.pda.owner].") + return 1 + else if(href_list["select"]) + var/s = href_list["select"] + if(s == "*NONE*") + M.current_room = null + else + var/datum/chatroom/CR = locate(s) + if(istype(CR)) + if(!(M in CR.users)) + if(!CR.login(M)) + return + M.current_room = CR + return 1 + else if(href_list["target"]) + if(P.silence_time) + return alert("Communications circuits remain uninitialized.") + + var/datum/chatroom/target = locate(href_list["target"]) + if(istype(target)) + if(!(M in target.users)) + if(!target.login(M)) + return + var/t = input("Please enter message", target) as text|null spawn() - if(!t || !M.check_messaging_available() || !P.pda.can_use()) + if(!t || !M.check_messaging_available()) return t = sanitize(copytext(t, 1, MAX_MESSAGE_LEN)) t = readd_quotes(t) - if(!t) + if(!t || !P.pda.can_use()) return - M.current_room.topic = t - M.current_room.announce(M, "Topic has been changed to '[t]' by [P.pda.owner].") - return 1 - else if(href_list["select"]) - var/s = href_list["select"] - if(s == "*NONE*") - M.current_room = null - else - var/datum/chatroom/CR = locate(s) - if(istype(CR)) - if(!(M in CR.users)) - if(!CR.login(M)) - return - M.current_room = CR - return 1 - else if(href_list["target"]) - if(P.silence_time) - return alert("Communications circuits remain uninitialized.") - - var/datum/chatroom/target = locate(href_list["target"]) - if(istype(target)) - if(!(M in target.users)) - if(!target.login(M)) - return - var/t = input("Please enter message", target) as text|null - spawn() - if(!t || !M.check_messaging_available()) - return - t = sanitize(copytext(t, 1, MAX_MESSAGE_LEN)) - t = readd_quotes(t) - if(!t || !P.pda.can_use()) - return - - target.post(M, t) - return 1 - else if(href_list["reconnect"]) - spawn() - M.messaging_available() - return 1 + target.post(M, t) + return 1 + else if(href_list["reconnect"]) + spawn() + M.messaging_available() + return 1 /datum/pai_software/med_records name = "Medical Records" @@ -346,53 +349,52 @@ id = "med_records" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] + autoupdate = 1 + template_file = "pai_medrecords.tmpl" + ui_title = "Medical Records" - var/records[0] - for(var/datum/data/record/general in sortRecord(data_core.general)) - var/record[0] - record["name"] = general.fields["name"] - record["ref"] = "\ref[general]" - records[++records.len] = record - data["records"] = records +/datum/pai_software/med_records/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] - var/datum/data/record/G = user.medicalActive1 - var/datum/data/record/M = user.medicalActive2 - data["general"] = G ? G.fields : null - data["medical"] = M ? M.fields : null - data["could_not_find"] = user.medical_cannotfind + var/records[0] + for(var/datum/data/record/general in sortRecord(data_core.general)) + var/record[0] + record["name"] = general.fields["name"] + record["ref"] = "\ref[general]" + records[++records.len] = record - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["records"] = records - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return + var/datum/data/record/G = user.medicalActive1 + var/datum/data/record/M = user.medicalActive2 + data["general"] = G ? G.fields : null + data["medical"] = M ? M.fields : null + data["could_not_find"] = user.medical_cannotfind - if(href_list["select"]) - var/datum/data/record/record = locate(href_list["select"]) - if(record) - var/datum/data/record/R = record - var/datum/data/record/M = null - if(!( data_core.general.Find(R) )) - P.medical_cannotfind = 1 - else - P.medical_cannotfind = 0 - for(var/datum/data/record/E in data_core.medical) - if((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - M = E - P.medicalActive1 = R - P.medicalActive2 = M - else + return data + +/datum/pai_software/med_records/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(href_list["select"]) + var/datum/data/record/record = locate(href_list["select"]) + if(record) + var/datum/data/record/R = record + var/datum/data/record/M = null + if(!( data_core.general.Find(R) )) P.medical_cannotfind = 1 - return 1 + else + P.medical_cannotfind = 0 + for(var/datum/data/record/E in data_core.medical) + if((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + M = E + P.medicalActive1 = R + P.medicalActive2 = M + else + P.medical_cannotfind = 1 + return 1 /datum/pai_software/sec_records name = "Security Records" @@ -400,57 +402,56 @@ id = "sec_records" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] + autoupdate = 1 + template_file = "pai_secrecords.tmpl" + ui_title = "Security Records" - var/records[0] - for(var/datum/data/record/general in sortRecord(data_core.general)) - var/record[0] - record["name"] = general.fields["name"] - record["ref"] = "\ref[general]" - records[++records.len] = record - data["records"] = records +/datum/pai_software/sec_records/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] - var/datum/data/record/G = user.securityActive1 - var/datum/data/record/S = user.securityActive2 - data["general"] = G ? G.fields : null - data["security"] = S ? S.fields : null - data["could_not_find"] = user.security_cannotfind + var/records[0] + for(var/datum/data/record/general in sortRecord(data_core.general)) + var/record[0] + record["name"] = general.fields["name"] + record["ref"] = "\ref[general]" + records[++records.len] = record - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["records"] = records - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return + var/datum/data/record/G = user.securityActive1 + var/datum/data/record/S = user.securityActive2 + data["general"] = G ? G.fields : null + data["security"] = S ? S.fields : null + data["could_not_find"] = user.security_cannotfind - if(href_list["select"]) - var/datum/data/record/record = locate(href_list["select"]) - if(record) - var/datum/data/record/R = record - var/datum/data/record/S = null - if(!( data_core.general.Find(R) )) - P.securityActive1 = null - P.securityActive2 = null - P.security_cannotfind = 1 - else - P.security_cannotfind = 0 - for(var/datum/data/record/E in data_core.security) - if((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - S = E - P.securityActive1 = R - P.securityActive2 = S - else + return data + +/datum/pai_software/sec_records/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(href_list["select"]) + var/datum/data/record/record = locate(href_list["select"]) + if(record) + var/datum/data/record/R = record + var/datum/data/record/S = null + if(!( data_core.general.Find(R) )) P.securityActive1 = null P.securityActive2 = null P.security_cannotfind = 1 - return 1 + else + P.security_cannotfind = 0 + for(var/datum/data/record/E in data_core.security) + if((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + S = E + P.securityActive1 = R + P.securityActive2 = S + else + P.securityActive1 = null + P.securityActive2 = null + P.security_cannotfind = 1 + return 1 /datum/pai_software/door_jack name = "Door Jack" @@ -458,44 +459,44 @@ id = "door_jack" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] + autoupdate = 1 + template_file = "pai_doorjack.tmpl" + ui_title = "Door Jack" + ui_width = 300 + ui_height = 150 - data["cable"] = user.cable != null - data["machine"] = user.cable && (user.cable.machine != null) - data["inprogress"] = user.hackdoor != null - data["progress_a"] = round(user.hackprogress / 10) - data["progress_b"] = user.hackprogress % 10 - data["aborted"] = user.hack_aborted +/datum/pai_software/door_jack/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["cable"] = user.cable != null + data["machine"] = user.cable && (user.cable.machine != null) + data["inprogress"] = user.hackdoor != null + data["progress_a"] = round(user.hackprogress / 10) + data["progress_b"] = user.hackprogress % 10 + data["aborted"] = user.hack_aborted - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return + return data - if(href_list["jack"]) - if(P.cable && P.cable.machine) - P.hackdoor = P.cable.machine - P.hackloop() - return 1 - else if(href_list["cancel"]) - P.hackdoor = null - return 1 - else if(href_list["cable"]) - var/turf/T = get_turf_or_move(P.loc) - P.hack_aborted = 0 - P.cable = new /obj/item/weapon/pai_cable(T) - for(var/mob/M in viewers(T)) - M.show_message("A port on [P] opens to reveal [P.cable], which promptly falls to the floor.", 3, - "You hear the soft click of something light and hard falling to the ground.", 2) - return 1 +/datum/pai_software/door_jack/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(href_list["jack"]) + if(P.cable && P.cable.machine) + P.hackdoor = P.cable.machine + P.hackloop() + return 1 + else if(href_list["cancel"]) + P.hackdoor = null + return 1 + else if(href_list["cable"]) + var/turf/T = get_turf_or_move(P.loc) + P.hack_aborted = 0 + P.cable = new /obj/item/weapon/pai_cable(T) + for(var/mob/M in viewers(T)) + M.show_message("A port on [P] opens to reveal [P.cable], which promptly falls to the floor.", 3, + "You hear the soft click of something light and hard falling to the ground.", 2) + return 1 /mob/living/silicon/pai/proc/hackloop() var/turf/T = get_turf_or_move(src.loc) @@ -534,66 +535,68 @@ id = "atmos_sense" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] + template_file = "pai_atmosphere.tmpl" + ui_title = "Atmosphere Sensor" + ui_width = 350 + ui_height = 300 - var/turf/T = get_turf_or_move(user.loc) - if(!T) - data["reading"] = 0 - data["pressure"] = 0 - data["temperature"] = 0 - data["temperatureC"] = 0 - data["gas"] = list() - else - var/datum/gas_mixture/env = T.return_air() - data["reading"] = 1 - data["pressure"] = env.return_pressure() - data["temperature"] = round(env.temperature) - data["temperatureC"] = round(env.temperature-T0C) - var/t_moles = env.total_moles() - var/gases[0] - if(t_moles) - var/n2[0] - n2["name"] = "Nitrogen" - n2["percent"] = round((env.nitrogen/t_moles)*100) - var/o2[0] - o2["name"] = "Oxygen" - o2["percent"] = round((env.oxygen/t_moles)*100) - var/co2[0] - co2["name"] = "Carbon Dioxide" - co2["percent"] = round((env.carbon_dioxide/t_moles)*100) - var/plasma[0] - plasma["name"] = "Plasma" - plasma["percent"] = round((env.toxins/t_moles)*100) - var/other[0] - other["name"] = "Other" - other["percent"] = round(1-((env.oxygen/t_moles)+(env.nitrogen/t_moles)+(env.carbon_dioxide/t_moles)+(env.toxins/t_moles))) - gases[++gases.len] = n2 - gases[++gases.len] = o2 - gases[++gases.len] = co2 - gases[++gases.len] = plasma - gases[++gases.len] = other - data["gas"] = gases +/datum/pai_software/atmosphere_sensor/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300) - ui.set_initial_data(data) - ui.open() + var/turf/T = get_turf_or_move(user.loc) + if(!T) + data["reading"] = 0 + data["pressure"] = 0 + data["temperature"] = 0 + data["temperatureC"] = 0 + data["gas"] = list() + else + var/datum/gas_mixture/env = T.return_air() + data["reading"] = 1 + data["pressure"] = env.return_pressure() + data["temperature"] = round(env.temperature) + data["temperatureC"] = round(env.temperature-T0C) + + var/t_moles = env.total_moles() + var/gases[0] + if(t_moles) + var/n2[0] + n2["name"] = "Nitrogen" + n2["percent"] = round((env.nitrogen/t_moles)*100) + var/o2[0] + o2["name"] = "Oxygen" + o2["percent"] = round((env.oxygen/t_moles)*100) + var/co2[0] + co2["name"] = "Carbon Dioxide" + co2["percent"] = round((env.carbon_dioxide/t_moles)*100) + var/plasma[0] + plasma["name"] = "Plasma" + plasma["percent"] = round((env.toxins/t_moles)*100) + var/other[0] + other["name"] = "Other" + other["percent"] = round(1-((env.oxygen/t_moles)+(env.nitrogen/t_moles)+(env.carbon_dioxide/t_moles)+(env.toxins/t_moles))) + gases[++gases.len] = n2 + gases[++gases.len] = o2 + gases[++gases.len] = co2 + gases[++gases.len] = plasma + gases[++gases.len] = other + data["gas"] = gases + + return data /datum/pai_software/sec_hud name = "Security HUD" ram_cost = 20 id = "sec_hud" - toggle(mob/living/silicon/pai/user) - user.secHUD = !user.secHUD - user.remove_med_sec_hud() - if(user.secHUD) - user.add_sec_hud() - is_active(mob/living/silicon/pai/user) +/datum/pai_software/sec_hud/toggle(mob/living/silicon/pai/user) + user.secHUD = !user.secHUD + user.remove_med_sec_hud() + if(user.secHUD) + user.add_sec_hud() + +/datum/pai_software/sec_hud/is_active(mob/living/silicon/pai/user) return user.secHUD /datum/pai_software/med_hud @@ -601,48 +604,48 @@ ram_cost = 20 id = "med_hud" - toggle(mob/living/silicon/pai/user) - user.medHUD = !user.medHUD - user.remove_med_sec_hud() - if(user.medHUD) - user.add_med_hud() +/datum/pai_software/med_hud/toggle(mob/living/silicon/pai/user) + user.medHUD = !user.medHUD + user.remove_med_sec_hud() + if(user.medHUD) + user.add_med_hud() - is_active(mob/living/silicon/pai/user) - return user.medHUD +/datum/pai_software/med_hud/is_active(mob/living/silicon/pai/user) + return user.medHUD /datum/pai_software/translator name = "Universal Translator" ram_cost = 35 id = "translator" - toggle(mob/living/silicon/pai/user) - // Galactic Common, Sol Common, Tradeband, Gutter and Trinary are added with New() and are therefore the current default, always active languages - user.translator_on = !user.translator_on - if(user.translator_on) - user.add_language("Sinta'unathi") - user.add_language("Siik'tajr") - user.add_language("Canilunzt") - user.add_language("Skrellian") - user.add_language("Vox-pidgin") - user.add_language("Rootspeak") - user.add_language("Chittin") - user.add_language("Bubblish") - user.add_language("Orluum") - user.add_language("Clownish") - else - user.remove_language("Sinta'unathi") - user.remove_language("Siik'tajr") - user.remove_language("Canilunzt") - user.remove_language("Skrellian") - user.remove_language("Vox-pidgin") - user.remove_language("Rootspeak") - user.remove_language("Chittin") - user.remove_language("Bubblish") - user.remove_language("Orluum") - user.remove_language("Clownish") +/datum/pai_software/translator/toggle(mob/living/silicon/pai/user) + // Galactic Common, Sol Common, Tradeband, Gutter and Trinary are added with New() and are therefore the current default, always active languages + user.translator_on = !user.translator_on + if(user.translator_on) + user.add_language("Sinta'unathi") + user.add_language("Siik'tajr") + user.add_language("Canilunzt") + user.add_language("Skrellian") + user.add_language("Vox-pidgin") + user.add_language("Rootspeak") + user.add_language("Chittin") + user.add_language("Bubblish") + user.add_language("Orluum") + user.add_language("Clownish") + else + user.remove_language("Sinta'unathi") + user.remove_language("Siik'tajr") + user.remove_language("Canilunzt") + user.remove_language("Skrellian") + user.remove_language("Vox-pidgin") + user.remove_language("Rootspeak") + user.remove_language("Chittin") + user.remove_language("Bubblish") + user.remove_language("Orluum") + user.remove_language("Clownish") - is_active(mob/living/silicon/pai/user) - return user.translator_on +/datum/pai_software/translator/is_active(mob/living/silicon/pai/user) + return user.translator_on /datum/pai_software/signaller name = "Remote Signaller" @@ -650,42 +653,42 @@ id = "signaller" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] + template_file = "pai_signaller.tmpl" + ui_title = "Signaller" + ui_width = 320 + ui_height = 150 - data["frequency"] = format_frequency(user.sradio.frequency) - data["code"] = user.sradio.code +/datum/pai_software/signaller/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150) - ui.set_initial_data(data) - ui.open() + data["frequency"] = format_frequency(user.sradio.frequency) + data["code"] = user.sradio.code - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return + return data - if(href_list["send"]) - P.sradio.send_signal("ACTIVATE") - for(var/mob/O in hearers(1, P.loc)) - O.show_message("[bicon(P)] *beep* *beep*", 3, "*beep* *beep*", 2) - return 1 +/datum/pai_software/signaller/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return - else if(href_list["freq"]) - var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"])) - if(new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ) - new_frequency = sanitize_frequency(new_frequency) - P.sradio.set_frequency(new_frequency) - return 1 + if(href_list["send"]) + P.sradio.send_signal("ACTIVATE") + for(var/mob/O in hearers(1, P.loc)) + O.show_message("[bicon(P)] *beep* *beep*", 3, "*beep* *beep*", 2) + return 1 - else if(href_list["code"]) - P.sradio.code += text2num(href_list["code"]) - P.sradio.code = round(P.sradio.code) - P.sradio.code = min(100, P.sradio.code) - P.sradio.code = max(1, P.sradio.code) - return 1 + else if(href_list["freq"]) + var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"])) + if(new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ) + new_frequency = sanitize_frequency(new_frequency) + P.sradio.set_frequency(new_frequency) + return 1 + + else if(href_list["code"]) + P.sradio.code += text2num(href_list["code"]) + P.sradio.code = round(P.sradio.code) + P.sradio.code = min(100, P.sradio.code) + P.sradio.code = max(1, P.sradio.code) + return 1 /datum/pai_software/host_scan name = "Host Bioscan" @@ -693,36 +696,33 @@ id = "bioscan" toggle = 0 + template_file = "pai_bioscan.tmpl" + ui_title = "Host Bioscan" + ui_width = 400 + ui_height = 350 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) +/datum/pai_software/host_scan/on_ui_data(mob/living/silicon/pai/user, datum/topic_state/state = self_state) + var/data[0] + var/mob/living/held = user.loc + var/count = 0 - var/data[0] - var/mob/living/held = user.loc - var/count = 0 + // Find the carrier + while(!isliving(held)) + if(!held || !held.loc || count > 6) + //For a runtime where M ends up in nullspace (similar to bluespace but less colourful) + to_chat(user, "You are not being carried by anyone!") + return 0 + held = held.loc + count++ + if(isliving(held)) + data["holder"] = held + data["health"] = "[held.stat > 1 ? "dead" : "[held.health]% healthy"]" + data["brute"] = "[held.getBruteLoss() > 50 ? "" : ""][held.getBruteLoss()]" + data["oxy"] = "[held.getOxyLoss() > 50 ? "" : ""][held.getOxyLoss()]" + data["tox"] = "[held.getToxLoss() > 50 ? "" : ""][held.getToxLoss()]" + data["burn"] = "[held.getFireLoss() > 50 ? "" : ""][held.getFireLoss()]" + data["temp"] = "[held.bodytemperature-T0C]°C ([held.bodytemperature*1.8-459.67]°F)" + else + data["holder"] = 0 - // Find the carrier - while(!isliving(held)) - if(!held || !held.loc || count > 6) - //For a runtime where M ends up in nullspace (similar to bluespace but less colourful) - to_chat(user, "You are not being carried by anyone!") - return 0 - held = held.loc - count++ - if(isliving(held)) - data["holder"] = held - data["health"] = "[held.stat > 1 ? "dead" : "[held.health]% healthy"]" - data["brute"] = "[held.getBruteLoss() > 50 ? "" : ""][held.getBruteLoss()]" - data["oxy"] = "[held.getOxyLoss() > 50 ? "" : ""][held.getOxyLoss()]" - data["tox"] = "[held.getToxLoss() > 50 ? "" : ""][held.getToxLoss()]" - data["burn"] = "[held.getFireLoss() > 50 ? "" : ""][held.getFireLoss()]" - data["temp"] = "[held.bodytemperature-T0C]°C ([held.bodytemperature*1.8-459.67]°F)" - else - data["holder"] = 0 - - ui = nanomanager.try_update_ui(user, user, id, ui,data , force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_bioscan.tmpl", "Host Bioscan", 400, 350) - ui.set_initial_data(data) - ui.open() - //.set_auto_update(1) + return data diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 0e354b4c4a6..fdc1ace289c 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -285,6 +285,7 @@ if(player.mob && player.mob.mind) player.mob.mind.transfer_to(src) + player.mob.mind.assigned_role = "Drone" lawupdate = 0 to_chat(src, "Systems rebooted. Loading base pattern maintenance protocol... loaded.") diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index d713c6dcf23..5f1418fcae5 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -1,5 +1,5 @@ -/mob/living/simple_animal/construct +/mob/living/simple_animal/hostile/construct name = "Construct" real_name = "Construct" desc = "" @@ -19,24 +19,31 @@ faction = list("cult") flying = 1 universal_speak = 1 + AIStatus = AI_OFF //normal constructs don't have AI + var/const_type = "shade" var/list/construct_spells = list() + var/playstyle_string = "You are a generic construct! Your job is to not exist, and you should probably adminhelp this." loot = list(/obj/item/weapon/reagent_containers/food/snacks/ectoplasm) del_on_death = 1 deathmessage = "collapses in a shattered heap." -/mob/living/simple_animal/construct/New() +/mob/living/simple_animal/hostile/construct/New() ..() - name = text("[initial(name)] ([rand(1, 1000)])") - real_name = name + name = "[ticker.mode.cultdat.get_name(const_type)] ([rand(1, 1000)])" + real_name = ticker.mode.cultdat.get_name(const_type) + icon_living = ticker.mode.cultdat.get_icon(const_type) + icon_state = ticker.mode.cultdat.get_icon(const_type) for(var/spell in construct_spells) AddSpell(new spell(null)) - updateglow() -/mob/living/simple_animal/construct/examine(mob/user) + if(ticker.mode.cultdat.theme == "blood") + updateglow() + +/mob/living/simple_animal/hostile/construct/examine(mob/user) to_chat(user, "*---------*") ..(user) - var/msg = "" + var/msg = "" if(src.health < src.maxHealth) msg += "" if(src.health >= src.maxHealth/2) @@ -48,32 +55,34 @@ to_chat(user, msg) -/mob/living/simple_animal/construct/attack_animal(mob/living/simple_animal/M as mob) - if(istype(M, /mob/living/simple_animal/construct/builder)) - health += 5 - M.custom_emote(1,"mends some of \the [src]'s wounds.") - else - if(M.melee_damage_upper <= 0) - M.custom_emote(1, "[M.friendly] \the [src]") +/mob/living/simple_animal/hostile/construct/attack_animal(mob/living/simple_animal/M) + if(istype(M, /mob/living/simple_animal/hostile/construct/builder)) + if(health < maxHealth) + adjustBruteLoss(-5) + if(src != M) + Beam(M,icon_state="sendbeam",icon='icons/effects/effects.dmi',time=4) + M.visible_message("[M] repairs some of \the [src]'s dents.", \ + "You repair some of [src]'s dents, leaving [src] at [health]/[maxHealth] health.") + else + M.visible_message("[M] repairs some of its own dents.", \ + "You repair some of your own dents, leaving you at [M.health]/[M.maxHealth] health.") else - M.do_attack_animation(src) - if(M.attack_sound) - playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("\The [M] [M.attacktext] \the [src]!", 1) - add_logs(M, src, "attacked") - var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) - adjustBruteLoss(damage) + if(src != M) + to_chat(M, "You cannot repair [src]'s dents, as it has none!") + else + to_chat(M, "You cannot repair your own dents, as you have none!") + else if(src != M) + ..() -/mob/living/simple_animal/construct/narsie_act() +/mob/living/simple_animal/hostile/construct/narsie_act() return /////////////////Juggernaut/////////////// -/mob/living/simple_animal/construct/armoured +/mob/living/simple_animal/hostile/construct/armoured name = "Juggernaut" real_name = "Juggernaut" desc = "A possessed suit of armour driven by the will of the restless dead" @@ -91,11 +100,19 @@ environment_smash = 2 attack_sound = 'sound/weapons/punch3.ogg' status_flags = 0 + const_type = "juggernaut" mob_size = MOB_SIZE_LARGE construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall) force_threshold = 11 + playstyle_string = "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \ + create shield walls, rip apart enemies and walls alike, and even deflect energy weapons." -/mob/living/simple_animal/construct/armoured/bullet_act(var/obj/item/projectile/P) + +/mob/living/simple_animal/hostile/construct/armoured/hostile //actually hostile, will move around, hit things + AIStatus = AI_ON + environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP + +/mob/living/simple_animal/hostile/construct/armoured/bullet_act(var/obj/item/projectile/P) if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) var/reflectchance = 80 - round(P.damage/3) if(prob(reflectchance)) @@ -128,7 +145,7 @@ -/mob/living/simple_animal/construct/wraith +/mob/living/simple_animal/hostile/construct/wraith name = "Wraith" real_name = "Wraith" desc = "A wicked bladed shell contraption piloted by a bound spirit" @@ -142,15 +159,19 @@ attacktext = "slashes" see_in_dark = 7 attack_sound = 'sound/weapons/bladeslice.ogg' + const_type = "wraith" construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift) + retreat_distance = 2 //AI wraiths will move in and out of combat + playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." - +/mob/living/simple_animal/hostile/construct/wraith/hostile //actually hostile, will move around, hit things + AIStatus = AI_ON /////////////////////////////Artificer///////////////////////// -/mob/living/simple_animal/construct/builder +/mob/living/simple_animal/hostile/construct/builder name = "Artificer" real_name = "Artificer" desc = "A bulbous construct dedicated to building and maintaining The Cult of Nar-Sie's armies" @@ -165,18 +186,70 @@ melee_damage_upper = 5 attacktext = "rams" environment_smash = 2 + retreat_distance = 10 + minimum_distance = 10 //AI artificers will flee like fuck attack_sound = 'sound/weapons/punch2.ogg' + const_type = "builder" construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser, /obj/effect/proc_holder/spell/aoe_turf/conjure/wall, /obj/effect/proc_holder/spell/aoe_turf/conjure/floor, + /obj/effect/proc_holder/spell/aoe_turf/conjure/pylon, /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone, /obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser) + playstyle_string = "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \ + use magic missile, repair allied constructs (by clicking on them), \ + and, most important of all, create new constructs by producing soulstones to capture souls, \ + and shells to place those soulstones into." + + +/mob/living/simple_animal/hostile/construct/builder/Found(atom/A) //what have we found here? + if(istype(A, /mob/living/simple_animal/hostile/construct)) //is it a construct? + var/mob/living/simple_animal/hostile/construct/C = A + if(C.health < C.maxHealth) //is it hurt? let's go heal it if it is + return 1 + else + return 0 + else + return 0 + +/mob/living/simple_animal/hostile/construct/builder/CanAttack(atom/the_target) + if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it + return 0 + if(Found(the_target) || ..()) //If we Found it or Can_Attack it normally, we Can_Attack it as long as it wasn't invisible + return 1 //as a note this shouldn't be added to base hostile mobs because it'll mess up retaliate hostile mobs + +/mob/living/simple_animal/hostile/construct/builder/MoveToTarget(var/list/possible_targets) + ..() + if(isliving(target)) + var/mob/living/L = target + if(istype(L, /mob/living/simple_animal/hostile/construct) && L.health >= L.maxHealth) //is this target an unhurt construct? stop trying to heal it + LoseTarget() + return 0 + if(L.health <= melee_damage_lower+melee_damage_upper) //ey bucko you're hurt as fuck let's go hit you + retreat_distance = null + minimum_distance = 1 + +/mob/living/simple_animal/hostile/construct/builder/Aggro() + ..() + if(istype(target, /mob/living/simple_animal/hostile/construct)) //oh the target is a construct no need to flee + retreat_distance = null + minimum_distance = 1 + +/mob/living/simple_animal/hostile/construct/builder/LoseAggro() + ..() + retreat_distance = initial(retreat_distance) + minimum_distance = initial(minimum_distance) + +/mob/living/simple_animal/hostile/construct/builder/hostile //actually hostile, will move around, hit things, heal other constructs + AIStatus = AI_ON + environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP + /////////////////////////////Behemoth///////////////////////// -/mob/living/simple_animal/construct/behemoth +/mob/living/simple_animal/hostile/construct/behemoth name = "Behemoth" real_name = "Behemoth" desc = "The pinnacle of occult technology, Behemoths are the ultimate weapon in the Cult of Nar-Sie's arsenal." @@ -195,13 +268,22 @@ environment_smash = 2 attack_sound = 'sound/weapons/punch4.ogg' force_threshold = 11 + const_type = "behemoth" var/energy = 0 var/max_energy = 1000 +/mob/living/simple_animal/hostile/construct/behemoth/hostile //actually hostile, will move around, hit things + AIStatus = AI_ON + environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP + +/mob/living/simple_animal/hostile/construct/behemoth/Life() + weakened = 0 + return ..() + /////////////////////////////Harvester///////////////////////// -/mob/living/simple_animal/construct/harvester +/mob/living/simple_animal/hostile/construct/harvester name = "Harvester" real_name = "Harvester" desc = "A harbinger of Nar-Sie's enlightenment. It'll be all over soon." @@ -215,16 +297,25 @@ attacktext = "prods" speed = 0 environment_smash = 1 - see_in_dark = 7 + see_in_dark = 8 attack_sound = 'sound/weapons/tap.ogg' + const_type = "harvester" construct_spells = list(/obj/effect/proc_holder/spell/targeted/smoke/disable) + retreat_distance = 2 //AI harvesters will move in and out of combat, like wraiths, but shittier + playstyle_string = "You are a Harvester. You are not strong, but your powers of domination will assist you in your role: \ + Bring those who still cling to this world of illusion back to the master so they may know Truth." -/mob/living/simple_animal/construct/harvester/Process_Spacemove(var/movement_dir = 0) + +/mob/living/simple_animal/hostile/construct/harvester/Process_Spacemove(var/movement_dir = 0) return 1 +/mob/living/simple_animal/hostile/construct/harvester/hostile //actually hostile, will move around, hit things + AIStatus = AI_ON + + ////////////////Glow//////////////////// -/mob/living/simple_animal/construct/proc/updateglow() +/mob/living/simple_animal/hostile/construct/proc/updateglow() overlays = 0 var/overlay_layer = LIGHTING_LAYER + 1 if(layer != MOB_LAYER) @@ -233,32 +324,75 @@ overlays += image(icon,"glow-[icon_state]",overlay_layer) set_light(2, -2, l_color = "#FFFFFF") -////////////////Powers////////////////// +///ui stuff + +/mob/living/simple_animal/hostile/construct/armoured/handle_hud_icons_health() + ..() + if(healths) + switch(health) + if(250 to INFINITY) healths.icon_state = "juggernaut_health0" + if(208 to 249) healths.icon_state = "juggernaut_health1" + if(167 to 207) healths.icon_state = "juggernaut_health2" + if(125 to 166) healths.icon_state = "juggernaut_health3" + if(84 to 124) healths.icon_state = "juggernaut_health4" + if(42 to 83) healths.icon_state = "juggernaut_health5" + if(1 to 41) healths.icon_state = "juggernaut_health6" + else healths.icon_state = "juggernaut_health7" -/* -/client/proc/summon_cultist() - set category = "Behemoth" - set name = "Summon Cultist (300)" - set desc = "Teleport a cultist to your location" - if(istype(usr,/mob/living/simple_animal/constructbehemoth)) +/mob/living/simple_animal/hostile/construct/behemoth/handle_hud_icons_health() + ..() + if(healths) + switch(health) + if(750 to INFINITY) healths.icon_state = "juggernaut_health0" + if(625 to 749) healths.icon_state = "juggernaut_health1" + if(500 to 624) healths.icon_state = "juggernaut_health2" + if(375 to 499) healths.icon_state = "juggernaut_health3" + if(250 to 374) healths.icon_state = "juggernaut_health4" + if(125 to 249) healths.icon_state = "juggernaut_health5" + if(1 to 124) healths.icon_state = "juggernaut_health6" + else healths.icon_state = "juggernaut_health7" - if(usr.energy<300) - to_chat(usr, "\red You do not have enough power stored!") - return +/mob/living/simple_animal/hostile/construct/builder/handle_hud_icons_health() + ..() + if(healths) + switch(health) + if(50 to INFINITY) healths.icon_state = "artificer_health0" + if(42 to 49) healths.icon_state = "artificer_health1" + if(34 to 41) healths.icon_state = "artificer_health2" + if(26 to 33) healths.icon_state = "artificer_health3" + if(18 to 25) healths.icon_state = "artificer_health4" + if(10 to 17) healths.icon_state = "artificer_health5" + if(1 to 9) healths.icon_state = "artificer_health6" + else healths.icon_state = "artificer_health7" - if(usr.stat) - return - usr.energy -= 300 - var/list/mob/living/cultists = new - for(var/datum/mind/H in ticker.mode.cult) - if(istype(H.current,/mob/living)) - cultists+=H.current - var/mob/cultist = input("Choose the one who you want to summon", "Followers of Geometer") as null|anything in (cultists - usr) - if(!cultist) - return - if(cultist == usr) //just to be sure. - return - cultist.loc = usr.loc - usr.visible_message("/red [cultist] appears in a flash of red light as [usr] glows with power")*/ + +/mob/living/simple_animal/hostile/construct/wraith/handle_hud_icons_health() + + ..() + if(healths) + switch(health) + if(75 to INFINITY) healths.icon_state = "wraith_health0" + if(62 to 74) healths.icon_state = "wraith_health1" + if(50 to 61) healths.icon_state = "wraith_health2" + if(37 to 49) healths.icon_state = "wraith_health3" + if(25 to 36) healths.icon_state = "wraith_health4" + if(12 to 24) healths.icon_state = "wraith_health5" + if(1 to 11) healths.icon_state = "wraith_health6" + else healths.icon_state = "wraith_health7" + + +/mob/living/simple_animal/hostile/construct/harvester/handle_hud_icons_health() + + ..() + if(healths) + switch(health) + if(150 to INFINITY) healths.icon_state = "harvester_health0" + if(125 to 149) healths.icon_state = "harvester_health1" + if(100 to 124) healths.icon_state = "harvester_health2" + if(75 to 99) healths.icon_state = "harvester_health3" + if(50 to 74) healths.icon_state = "harvester_health4" + if(25 to 49) healths.icon_state = "harvester_health5" + if(1 to 24) healths.icon_state = "harvester_health6" + else healths.icon_state = "harvester_health7" \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/__defines.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/__defines.dm new file mode 100644 index 00000000000..fafd30a4ae4 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/__defines.dm @@ -0,0 +1,11 @@ + +#define SPINNING_WEB 1 +#define LAYING_EGGS 2 +#define MOVING_TO_TARGET 3 +#define SPINNING_COCOON 4 + +#define TS_TIER_1 1 +#define TS_TIER_2 2 +#define TS_TIER_3 3 +#define TS_TIER_4 4 +#define TS_TIER_5 5 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm new file mode 100644 index 00000000000..2111f350b0b --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm @@ -0,0 +1,127 @@ + + +/datum/action/innate/terrorspider/web + name = "Web" + icon_icon = 'icons/effects/effects.dmi' + button_icon_state = "stickyweb1" + +/datum/action/innate/terrorspider/web/Activate() + var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner + user.Web() + +/datum/action/innate/terrorspider/wrap + name = "Wrap" + icon_icon = 'icons/effects/effects.dmi' + button_icon_state = "cocoon_large1" + +/datum/action/innate/terrorspider/wrap/Activate() + var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner + user.FindWrapTarget() + user.DoWrap() + + +// ---------- WEB + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/Web() + visible_message("[src] begins to secrete a sticky substance.") + if(do_after(src, 40, target = loc)) + var/obj/effect/spider/terrorweb/T = locate() in get_turf(src) + if(T) + to_chat(src, "There is already a web here.") + else + new /obj/effect/spider/terrorweb(loc) + +/obj/effect/spider/terrorweb + name = "terror web" + desc = "it's stringy and sticky" + icon = 'icons/effects/effects.dmi' + anchored = 1 // prevents people dragging it + density = 0 // prevents it blocking all movement + health = 20 // two welders, or one laser shot (15 for the normal spider webs) + icon_state = "stickyweb1" + + +/obj/effect/spider/terrorweb/New() + ..() + if(prob(50)) + icon_state = "stickyweb2" + + +/obj/effect/spider/terrorweb/CanPass(atom/movable/mover, turf/target) + if(istype(mover, /mob/living/simple_animal/hostile/poison/terror_spider)) + return 1 + if(isliving(mover)) + if(prob(80)) + to_chat(mover, "You get stuck in [src] for a moment.") + var/mob/living/M = mover + M.Stun(4) // 8 seconds. + M.Weaken(4) // 8 seconds. + return 1 + else + return 0 + if(istype(mover, /obj/item/projectile)) + return prob(20) + return ..() + + + + +// ---------- WRAP + + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/FindWrapTarget() + if(!cocoon_target) + var/list/choices = list() + for(var/mob/living/L in oview(1,src)) + if(Adjacent(L)) + if(L.stat == DEAD) + choices += L + for(var/obj/O in oview(1,src)) + if(Adjacent(O) && !O.anchored) + if(!istype(O, /obj/effect/spider/terrorweb) && !istype(O, /obj/effect/spider/cocoon)) + choices += O + if(choices.len) + cocoon_target = input(src,"What do you wish to cocoon?") in null|choices + else + to_chat(src, "There is nothing nearby you can wrap.") + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoWrap() + if(cocoon_target && busy != SPINNING_COCOON) + busy = SPINNING_COCOON + visible_message("[src] begins to secrete a sticky substance around [cocoon_target].") + stop_automated_movement = 1 + walk(src,0) + if(do_after(src, 40, target = cocoon_target.loc)) + if(busy == SPINNING_COCOON) + if(cocoon_target && isturf(cocoon_target.loc) && get_dist(src,cocoon_target) <= 1) + var/obj/effect/spider/cocoon/C = new(cocoon_target.loc) + var/large_cocoon = 0 + C.pixel_x = cocoon_target.pixel_x + C.pixel_y = cocoon_target.pixel_y + for(var/obj/O in C.loc) + if(istype(O, /obj/item)) + O.loc = C + else if(istype(O, /obj/machinery) || istype(O, /obj/structure)) + O.loc = C + large_cocoon = 1 + for(var/mob/living/L in C.loc) + if(istype(L, /mob/living/simple_animal/hostile/poison/terror_spider)) + continue + if(L.stat != DEAD) + continue + if(iscarbon(L)) + regen_points += regen_points_per_kill + fed++ + large_cocoon = 1 + last_cocoon_object = 0 + L.loc = C + C.pixel_x = L.pixel_x + C.pixel_y = L.pixel_y + visible_message("[src] sticks a proboscis into [L] and sucks a viscous substance out.") + break + if(large_cocoon) + C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3") + cocoon_target = null + busy = 0 + stop_automated_movement = 0 + diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/black.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/black.dm new file mode 100644 index 00000000000..68d25a29492 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/black.dm @@ -0,0 +1,38 @@ + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: T2 BLACK TERROR ------------------------------ +// -------------------------------------------------------------------------------- +// -------------: ROLE: assassin, poisoner, DoT expert +// -------------: AI: attacks to inject its venom, then retreats. Will inject its enemies multiple times then hang back to ensure they die. +// -------------: SPECIAL: venom that does more damage the more of it is in you +// -------------: TO FIGHT IT: if bitten once, retreat, get charcoal/etc treatment, and come back with a gun. +// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386 + +/mob/living/simple_animal/hostile/poison/terror_spider/black + name = "Black Terror spider" + desc = "An ominous-looking spider, black as the darkest night, and with merciless eyes and a blood-red hourglass pattern on its back." + spider_role_summary = "Hit-and-run attacker with extremely venomous bite." + + icon_state = "terror_widow" + icon_living = "terror_widow" + icon_dead = "terror_widow_dead" + maxHealth = 120 // same health as hunter spider, aka, pretty weak.. but its bite will kill you! + health = 120 + melee_damage_lower = 5 + melee_damage_upper = 10 + move_to_delay = 5 + stat_attack = 1 // ensures they will target people in crit, too! + spider_tier = TS_TIER_2 + +/mob/living/simple_animal/hostile/poison/terror_spider/black/spider_specialattack(mob/living/carbon/human/L, poisonable) + if(!poisonable) + return ..() + if(L.reagents.has_reagent("terror_black_toxin", 50)) + return ..() + var/inject_target = pick("chest", "head") + if(L.stunned || L.can_inject(null, 0, inject_target, 0)) + L.reagents.add_reagent("terror_black_toxin", 15) // inject our special poison + visible_message("[src] buries its long fangs deep into the [inject_target] of [target]!") + else + visible_message("[src] bites [target], but cannot inject venom into their [inject_target]!") + L.attack_animal(src) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm new file mode 100644 index 00000000000..8ad926a8729 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm @@ -0,0 +1,33 @@ +// Terror Spider, Black, Deadly Venom + +/datum/reagent/terror_black_toxin + name = "Black Widow venom" + id = "terror_black_toxin" + description = "An incredibly toxic venom injected by the Black Widow spider." + color = "#CF3600" + metabolization_rate = 0.1 + +/datum/reagent/terror_black_toxin/on_mob_life(mob/living/M) + if(volume < 15) + // bitten once, die slowly. Easy to survive a single bite - just go to medbay. + // total damage: 2/tick, human health 150 until crit, = 75 ticks, = 150 seconds = 2.5 minutes to get to medbay. + M.adjustToxLoss(2) // same damage/tick as tabun cycle 0 to 60 + else if(volume < 30) + // bitten twice, die more quickly, muscle cramps make movement difficult. Call medics immediately. + // total damage: 4, human health 150 until crit, = 37.5 ticks, = 75s = 1m15s until death + M.adjustToxLoss(4) + M.Confused(3) + M.EyeBlurry(3) + else if(volume < 45) + // bitten thrice, die very quickly, severe muscle cramps make movement very difficult. Even calling for help probably won't save you. + // total damage: 8, human health 150 until crit, = 18.75 ticks, = 37s until death + M.adjustToxLoss(8) // a bit worse than coiine + M.Confused(6) + M.EyeBlurry(6) + else + // bitten 4 or more times, whole body goes into shock/death + // total damage: 12, human health 150 until crit, = 12.5 ticks, = 25s until death + M.adjustToxLoss(12) + M.EyeBlurry(6) + M.Paralyse(5) + ..() diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm new file mode 100644 index 00000000000..06703cc2106 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm @@ -0,0 +1,43 @@ + +/mob/living/simple_animal/hostile/poison/terror_spider/Topic(href, href_list) + if(href_list["activate"]) + var/mob/dead/observer/ghost = usr + if(istype(ghost)) + humanize_spider(ghost) + +/mob/living/simple_animal/hostile/poison/terror_spider/attack_ghost(mob/user) + humanize_spider(user) + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/humanize_spider(mob/user) + if(key)//Someone is in it + return + var/error_on_humanize = "" + var/humanize_prompt = "Take direct control of [src]?" + humanize_prompt += "Role: [spider_role_summary]" + if(user.ckey in ts_ckey_blacklist) + error_on_humanize = "You are not able to control any terror spider this round." + else if(!ai_playercontrol_allowingeneral) + error_on_humanize = "Terror spiders cannot currently be player-controlled." + else if(spider_awaymission) + error_on_humanize = "Terror spiders that are part of an away mission cannot be controlled by ghosts." + else if(!ai_playercontrol_allowtype) + error_on_humanize = "This specific type of terror spider is not player-controllable." + else if(stat == DEAD) + error_on_humanize = "Dead spiders are not player-controllable." + if(jobban_isbanned(user, "Syndicate") || jobban_isbanned(user, "alien")) + to_chat(user,"You are jobbanned from role of syndicate and/or alien lifeform.") + return + if(error_on_humanize == "") + var/spider_ask = alert(humanize_prompt, "Join as Terror Spider?", "Yes", "No") + if(spider_ask == "No" || !src || qdeleted(src)) + return + else + to_chat(user, "Cannot inhabit spider: [error_on_humanize]") + return + if(key) + to_chat(user, "Someone else already took this spider.") + return + key = user.key + for(var/mob/dead/observer/G in player_list) + G.show_message("A ghost has taken control of [src]. ([ghost_follow_link(src, ghost=G)]).") + diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm new file mode 100644 index 00000000000..42c16cc7666 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm @@ -0,0 +1,40 @@ + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: T1 GRAY TERROR ------------------------------- +// -------------------------------------------------------------------------------- +// -------------: ROLE: fast, weak terror spider +// -------------: SPECIAL: silences targets +// -------------: TO FIGHT IT: shoot it! +// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386 + +/mob/living/simple_animal/hostile/poison/terror_spider/gray + name = "Gray Terror spider" + desc = "An ominous-looking gray spider, it seems jittery." + spider_role_summary = "Fast-moving but weak spider." + icon_state = "terror_gray" + icon_living = "terror_gray" + icon_dead = "terror_gray_dead" + maxHealth = 120 // same health as hunter spider, aka, pretty weak.. but silences its targets + health = 120 + melee_damage_lower = 10 + melee_damage_upper = 20 + ventcrawler = 1 + move_to_delay = 5 // normal speed + stat_attack = 1 // ensures they will target people in crit, too! + environment_smash = 1 + + +/mob/living/simple_animal/hostile/poison/terror_spider/gray/spider_specialattack(mob/living/carbon/human/L, poisonable) + if(!poisonable) + ..() + return + if(L.silent >= 10) + L.attack_animal(src) + else + var/inject_target = pick("chest","head") + if(L.stunned || L.can_inject(null,0,inject_target,0)) + L.Silence(20) // instead of having a venom that only lasts seconds, we just add the silence directly. + visible_message("[src] buries grey fangs deep into the [inject_target] of [target]!") + else + visible_message("[src] bites [target], but cannot inject venom into their [inject_target]!") + L.attack_animal(src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm new file mode 100644 index 00000000000..669449a6ae3 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm @@ -0,0 +1,35 @@ + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: T3 PRINCE OF TERROR -------------------------- +// -------------------------------------------------------------------------------- +// -------------: ROLE: boss +// -------------: AI: no special ai +// -------------: SPECIAL: massive health +// -------------: TO FIGHT IT: a squad of at least 4 people with laser rifles. +// -------------: SPRITES FROM: Travelling Merchant, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=2766 + +/mob/living/simple_animal/hostile/poison/terror_spider/prince + name = "Prince of Terror spider" + desc = "An enormous, terrifying spider. It looks like it is judging everything it sees. Its hide seems armored, and it bears the scars of many battles." + spider_role_summary = "Boss-level terror spider. Lightning bruiser. Capable of taking on a squad by itself." + icon_state = "terror_allblack" + icon_living = "terror_allblack" + icon_dead = "terror_allblack_dead" + maxHealth = 400 // 20 laser shots. + health = 400 + melee_damage_lower = 15 + melee_damage_upper = 25 + move_to_delay = 5 + ventcrawler = 1 + loot = list(/obj/item/clothing/accessory/medal) + spider_tier = TS_TIER_3 + spider_opens_doors = 2 + + +/mob/living/simple_animal/hostile/poison/terror_spider/prince/spider_specialattack(mob/living/carbon/human/L) + if(prob(15)) + visible_message("[src] rams into [L], knocking them to the floor!") + L.Weaken(5) + L.Stun(5) + else + ..() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/red.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/red.dm new file mode 100644 index 00000000000..33480f9509c --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/red.dm @@ -0,0 +1,60 @@ + + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: T1 RED TERROR -------------------------------- +// -------------------------------------------------------------------------------- +// -------------: ROLE: generic attack spider +// -------------: AI: uses very powerful fangs to wreck people in melee +// -------------: SPECIAL: the more you hurt it, the harder it bites you +// -------------: TO FIGHT IT: shoot it from range. Kite it. +// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386 + +/mob/living/simple_animal/hostile/poison/terror_spider/red + name = "Red Terror spider" + desc = "An ominous-looking red spider, it has eight beady red eyes, and nasty, big, pointy fangs! It looks like it has a vicious streak a mile wide." + + spider_role_summary = "High health, high damage, very slow, melee juggernaut" + + icon_state = "terror_red" + icon_living = "terror_red" + icon_dead = "terror_red_dead" + maxHealth = 200 + health = 200 + melee_damage_lower = 15 + melee_damage_upper = 20 + move_to_delay = 20 + spider_opens_doors = 2 + var/enrage = 0 + var/melee_damage_lower_rage0 = 15 + var/melee_damage_upper_rage0 = 20 + var/melee_damage_lower_rage1 = 15 + var/melee_damage_upper_rage1 = 35 + var/melee_damage_lower_rage2 = 35 + var/melee_damage_upper_rage2 = 40 + + +/mob/living/simple_animal/hostile/poison/terror_spider/red/AttackingTarget() + if(enrage == 0) + if(health < maxHealth) + enrage = 1 + visible_message("[src] growls, flexing its fangs!") + melee_damage_lower = melee_damage_lower_rage1 + melee_damage_upper = melee_damage_upper_rage1 + else if(enrage == 1) + if(health == maxHealth) + enrage = 0 + visible_message("[src] retracts its fangs a little.") + melee_damage_lower = melee_damage_lower_rage0 + melee_damage_upper = melee_damage_upper_rage0 + else if(health < (maxHealth/2)) + enrage = 2 + visible_message("[src] growls, spreading its fangs wide!") + melee_damage_lower = melee_damage_lower_rage2 + melee_damage_upper = melee_damage_upper_rage2 + else if(enrage == 2) + if(health > (maxHealth/2)) + enrage = 1 + visible_message("[src] retracts its fangs a little.") + melee_damage_lower = melee_damage_lower_rage0 + melee_damage_upper = melee_damage_upper_rage0 + ..() diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm new file mode 100644 index 00000000000..67683d39b39 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm @@ -0,0 +1,329 @@ + +var/global/list/ts_ckey_blacklist = list() +var/global/ts_count_dead = 0 +var/global/ts_count_alive_awaymission = 0 +var/global/ts_count_alive_station = 0 +var/global/ts_death_last = 0 +var/global/ts_death_window = 9000 // 15 minutes +var/global/list/ts_spiderlist = list() + +// -------------------------------------------------------------------------------- +// --------------------- TERROR SPIDERS: DEFAULTS --------------------------------- +// -------------------------------------------------------------------------------- +// Because: http://tvtropes.org/pmwiki/pmwiki.php/Main/SpidersAreScary + +/mob/living/simple_animal/hostile/poison/terror_spider + // Name / Description + name = "terror spider" + desc = "The generic parent of all other terror spider types. If you see this in-game, it is a bug." + + // Icons + icon = 'icons/mob/terrorspider.dmi' + icon_state = "terror_red" + icon_living = "terror_red" + icon_dead = "terror_red_dead" + + // Health + maxHealth = 120 + health = 120 + + // Melee attacks + melee_damage_lower = 15 + melee_damage_upper = 20 + attacktext = "bites" + attack_sound = 'sound/weapons/bite.ogg' + poison_type = "" // we do not use that silly system. + + // Movement + move_to_delay = 6 + turns_per_move = 5 + pass_flags = PASSTABLE + + // Ventcrawling + ventcrawler = 1 // allows player ventcrawling + + // Speech + speak_chance = 0 // quiet but deadly + speak_emote = list("hisses") + emote_hear = list("hisses") + + // Languages are handled in terror_spider/New() + + // Interaction keywords + response_help = "pets" + response_disarm = "gently pushes aside" + + // regeneration settings - overridable by child classes + var/regen_points = 0 // number of regen points they have by default + var/regen_points_max = 100 // max number of points they can accumulate + var/regen_points_per_tick = 1 // gain one regen point per tick + var/regen_points_per_kill = 90 // gain extra regen points if you kill something + var/regen_points_per_hp = 3 // every X regen points = 1 health point you can regen + // desired: 20hp/minute unmolested, 40hp/min on food boost, assuming one tick every 2 seconds + // 90/kill means bonus 30hp/kill regenerated over the next 1-2 minutes + + // Vision + idle_vision_range = 10 + aggro_vision_range = 10 + see_in_dark = 10 + nightvision = 1 + vision_type = new /datum/vision_override/nightvision/thermals/ling_augmented_eyesight + see_invisible = 5 + + // player control by ghosts + var/ai_playercontrol_allowingeneral = 1 // if 0, no spiders are player controllable. Default set in code, can be changed by queens. + var/ai_playercontrol_allowtype = 1 // if 0, this specific class of spider is not player-controllable. Default set in code for each class, cannot be changed. + + var/spider_opens_doors = 1 // all spiders can open firedoors (they have no security). 1 = can open depowered doors. 2 = can open powered doors + faction = list("terrorspiders") + var/spider_awaymission = 0 // if 1, limits certain behavior in away missions + var/spider_role_summary = "UNDEFINED" + var/spider_placed = 0 + + // AI variables designed for use in procs + var/atom/cocoon_target // for queen and nurse + var/obj/machinery/atmospherics/unary/vent_pump/entry_vent // nearby vent they are going to try to get to, and enter + var/obj/machinery/atmospherics/unary/vent_pump/exit_vent // remote vent they intend to come out of + var/obj/machinery/atmospherics/unary/vent_pump/nest_vent // home vent, usually used by queens + var/fed = 0 + var/travelling_in_vent = 0 + var/busy = 0 // leave this alone! + var/spider_tier = TS_TIER_1 // 1 for red,gray,green. 2 for purple,black,white, 3 for prince, mother. 4 for queen, 5 for empress. + var/hasdied = 0 + var/attackstep = 0 + var/attackcycles = 0 + var/mylocation = null + var/chasecycles = 0 + var/last_cocoon_object = 0 // leave this, changed by procs. + var/killcount = 0 + + // Breathing, Pressure & Fire + // - No breathing / cannot be suffocated (spiders can hold their breath, look it up) + // - No pressure damage either - they have effectively exoskeletons + // - HOWEVER they can be burned to death! + // - Normal SPACE spiders should probably be immune to SPACE too, but meh, we try to leave the base spiders alone. + atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minbodytemp = 0 + maxbodytemp = 1500 + heat_damage_per_tick = 5 //amount of damage applied if animal's body temperature is higher than maxbodytemp + + // DEBUG OPTIONS & COMMANDS + var/spider_debug = 0 + + var/datum/action/innate/terrorspider/web/web_action + var/datum/action/innate/terrorspider/wrap/wrap_action + + +// -------------------------------------------------------------------------------- +// --------------------- TERROR SPIDERS: SHARED ATTACK CODE ----------------------- +// -------------------------------------------------------------------------------- + + + +/mob/living/simple_animal/hostile/poison/terror_spider/AttackingTarget() + if(istype(target, /mob/living/simple_animal/hostile/poison/terror_spider)) + var/mob/living/simple_animal/hostile/poison/terror_spider/T = target + if(T.spider_tier > spider_tier) + visible_message("[src] bows in respect for the terrifying presence of [target].") + else if(T.spider_tier == spider_tier) + visible_message("[src] nuzzles [target].") + else if(T.spider_tier < spider_tier && spider_tier >= 4) + visible_message("[src] gives [target] a stern look.") + else + visible_message("[src] harmlessly nuzzles [target].") + T.CheckFaction() + CheckFaction() + else if(istype(target, /obj/effect/spider/cocoon)) + to_chat(src, "Destroying our own cocoons would not help us.") + else if(istype(target, /obj/machinery/door/firedoor)) + var/obj/machinery/door/firedoor/F = target + if(F.density) + if(F.blocked) + to_chat(src, "The fire door is welded shut.") + else + visible_message("\The [src] pries open the firedoor!") + F.open() + else + to_chat(src, "Closing fire doors does not help.") + else if(istype(target, /obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/A = target + if(A.density) + try_open_airlock(A) + else if(isliving(target)) + var/mob/living/G = target + if(issilicon(G)) + G.attack_animal(src) + return + else if(G.reagents && (iscarbon(G))) + var/can_poison = 1 + if(ishuman(G)) + var/mob/living/carbon/human/H = G + if(!(H.species.reagent_tag & PROCESS_ORG) || (H.species.flags & NO_POISON)) + can_poison = 0 + spider_specialattack(G,can_poison) + else + G.attack_animal(src) + else + target.attack_animal(src) + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_specialattack(mob/living/carbon/human/L, var/poisonable) + L.attack_animal(src) + + + + + + +// -------------------------------------------------------------------------------- +// --------------------- TERROR SPIDERS: PROC OVERRIDES --------------------------- +// -------------------------------------------------------------------------------- + + +/mob/living/simple_animal/hostile/poison/terror_spider/examine(mob/user) + ..() + var/list/msgs = list() + if(stat == DEAD) + msgs += "It appears to be dead.\n" + else + if(key) + msgs += "Its eyes regard you with a curious intelligence." + if(health > (maxHealth*0.95)) + msgs += "It is in excellent health." + else if(health > (maxHealth*0.75)) + msgs += "It has a few injuries." + else if(health > (maxHealth*0.55)) + msgs += "It has many injuries." + else if(health > (maxHealth*0.25)) + msgs += "It is barely clinging on to life!" + else if(health < maxHealth && regen_points > regen_points_per_kill) + msgs += "It appears to be regenerating quickly." + if(killcount >= 1) + msgs += "It has blood dribbling from its mouth." + to_chat(usr,msgs.Join("
")) + + +/mob/living/simple_animal/hostile/poison/terror_spider/New() + ..() + ts_spiderlist += src + add_language("Spider Hivemind") + add_language("Galactic Common") + default_language = all_languages["Spider Hivemind"] + + web_action = new() + web_action.Grant(src) + wrap_action = new() + wrap_action.Grant(src) + + name += " ([rand(1, 1000)])" + msg_terrorspiders("[src] has grown in [get_area(src)].") + if(is_away_level(z)) + spider_awaymission = 1 + ts_count_alive_awaymission++ + else + ts_count_alive_station++ + // after 30 seconds, assuming nobody took control of it yet, offer it to ghosts. + addtimer(src, "CheckFaction", 150) + addtimer(src, "announcetoghosts", 300) + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/announcetoghosts() + if(spider_awaymission) + return + if(stat == DEAD) + return + if(ckey) + var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state) + notify_ghosts("[src] has appeared in [get_area(src)]. (already player-controlled)", source = src, alert_overlay = alert_overlay) + else if(ai_playercontrol_allowingeneral && ai_playercontrol_allowtype) + var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state) + notify_ghosts("[src] has appeared in [get_area(src)].", enter_link = "(Click to control)", source = src, alert_overlay = alert_overlay, attack_not_jump = 1) + +/mob/living/simple_animal/hostile/poison/terror_spider/Destroy() + ts_spiderlist -= src + handle_dying() + return ..() + +/mob/living/simple_animal/hostile/poison/terror_spider/Life() + ..() + if(stat == DEAD) + if(prob(2)) + // 2% chance every cycle to decompose + visible_message("\The dead body of the [src] decomposes!") + gib() + else + if(regen_points < regen_points_max) + regen_points += regen_points_per_tick + if((bruteloss > 0) || (fireloss > 0)) + if(regen_points > regen_points_per_hp) + if(bruteloss > 0) + adjustBruteLoss(-1) + regen_points -= regen_points_per_hp + else if(fireloss > 0) + adjustFireLoss(-1) + regen_points -= regen_points_per_hp + if(prob(5)) + CheckFaction() + + + + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/handle_dying() + if(!hasdied) + hasdied = 1 + ts_count_dead++ + ts_death_last = world.time + if(spider_awaymission) + ts_count_alive_awaymission-- + else + ts_count_alive_station-- + +/mob/living/simple_animal/hostile/poison/terror_spider/death(gibbed) + if(!gibbed) + msg_terrorspiders("[src] has died in [get_area(src)].") + handle_dying() + ..() + + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_special_action() + return + +/mob/living/simple_animal/hostile/poison/terror_spider/Bump(atom/A) + if(istype(A, /obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/L = A + if(L.density) + try_open_airlock(L) + if(istype(A, /obj/machinery/door/firedoor)) + var/obj/machinery/door/firedoor/F = A + if(F.density && !F.blocked) + F.open() + ..() + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/msg_terrorspiders(msgtext) + for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in ts_spiderlist) + if(T.stat != DEAD) + to_chat(T, "TerrorSense: [msgtext]") + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/CheckFaction() + if(faction.len != 1 || (!("terrorspiders" in faction)) || master_commander != null) + visible_message("[src] writhes in pain!") + log_runtime(EXCEPTION("Terror spider created with incorrect faction list at: [atom_loc_line(src)]")) + death() + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/try_open_airlock(obj/machinery/door/airlock/D) + if(D.operating) + return + if(!D.density) + to_chat(src, "Closing doors does not help us.") + else if(D.welded) + to_chat(src, "The door is welded shut.") + else if(D.locked) + to_chat(src, "The door is bolted shut.") + else if(D.allowed(src)) + D.open(1) + else if(D.arePowerSystemsOn() && (spider_opens_doors != 2)) + to_chat(src, "The door's motors resist your efforts to force it.") + else if(!spider_opens_doors) + to_chat(src, "Your type of spider is not strong enough to force open doors.") + else + visible_message("[src] pries open the door!") + playsound(src.loc, "sparks", 100, 1) + D.open(1) \ No newline at end of file diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index 45207fd5426..402f94e837e 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -67,6 +67,8 @@ Your character moves slower. * Slurring * Your character cannot enunciate clearly. + * CultSlurring * + Your character cannot enunciate clearly while mumbling about elder codes. * Stunned * Your character is unable to move, and drops stuff in their hands. They keep standing, though. * Stuttering * @@ -108,6 +110,7 @@ /mob // On `/mob` for now, to support legacy code var/confused = 0 + var/cultslurring = 0 var/dizziness = 0 var/drowsyness = 0 var/druggy = 0 @@ -387,6 +390,18 @@ var/new_value = directional_bounded_sum(slurring, amount, bound_lower, bound_upper) SetSlur(new_value) +// CULTSLURRING + +/mob/living/CultSlur(amount) + SetSlur(max(slurring, amount)) + +/mob/living/SetCultSlur(amount) + slurring = max(amount, 0) + +/mob/living/AdjustCultSlur(amount, bound_lower = 0, bound_upper = INFINITY) + var/new_value = directional_bounded_sum(cultslurring, amount, bound_lower, bound_upper) + SetCultSlur(new_value) + // STUN /mob/living/Stun(amount, updating = 1, force = 0) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index ddb4d2beb60..44ba3cb99c3 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -894,45 +894,6 @@ var/list/slot_equipment_priority = list( \ if(!Adjacent(usr)) return show_inv(usr) -//this and stop_pulling really ought to be /mob/living procs -/mob/proc/start_pulling(atom/movable/AM) - if(src == AM) // Trying to pull yourself is a shortcut to stop pulling - stop_pulling() - return - if(!AM || !isturf(AM.loc)) //if there's no object or the object being pulled is inside something: abort! - return - if(!(AM.anchored)) - AM.add_fingerprint(src) - - // If we're pulling something then drop what we're currently pulling and pull this instead. - if(pulling) - // Are we trying to pull something we are already pulling? Then just stop here, no need to continue. - if(AM == pulling) - return - stop_pulling() - - src.pulling = AM - AM.pulledby = src - if(pullin) - pullin.update_icon(src) - if(ismob(AM)) - var/mob/M = AM - if(!iscarbon(src)) - M.LAssailant = null - else - M.LAssailant = usr - -/mob/verb/stop_pulling() - - set name = "Stop Pulling" - set category = "IC" - - if(pulling) - pulling.pulledby = null - pulling = null - if(pullin) - pullin.update_icon(src) - /mob/proc/can_use_hands() return diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index b39d014e4cc..c20b28191f3 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -411,7 +411,7 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HARM) name = realname for(var/mob/M in player_list) - if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || check_rights(R_ADMIN|R_MOD,0,M)) && (M.client.prefs.toggles & CHAT_DEAD)) + if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || check_rights(R_ADMIN|R_MOD,0,M)) && M.get_preference(CHAT_DEAD)) var/follow var/lname if(subject) @@ -546,3 +546,53 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HARM) return rename_character(oldname, newname) + +/proc/cultslur(n) // Inflicted on victims of a stun talisman + var/phrase = html_decode(n) + var/leng = lentext(phrase) + var/counter=lentext(phrase) + var/newphrase="" + var/newletter="" + while(counter>=1) + newletter=copytext(phrase,(leng-counter)+1,(leng-counter)+2) + if(rand(1,2)==2) + if(lowertext(newletter)=="o") + newletter="u" + if(lowertext(newletter)=="t") + newletter="ch" + if(lowertext(newletter)=="a") + newletter="ah" + if(lowertext(newletter)=="u") + newletter="oo" + if(lowertext(newletter)=="c") + newletter=" NAR " + if(lowertext(newletter)=="s") + newletter=" SIE " + if(rand(1,4)==4) + if(newletter==" ") + newletter=" no hope... " + if(newletter=="H") + newletter=" IT COMES... " + + switch(rand(1,15)) + if(1) + newletter="'" + if(2) + newletter+="agn" + if(3) + newletter="fth" + if(4) + newletter="nglu" + if(5) + newletter="glor" + newphrase+="[newletter]";counter-=1 + return newphrase + +/mob/proc/get_preference(toggleflag) + if(!client) + return FALSE + if(!client.prefs) + log_runtime(EXCEPTION("Mob '[src]', ckey '[ckey]' is missing a prefs datum on the client!")) + return FALSE + // Cast to 1/0 + return !!(client.prefs.toggles & toggleflag) diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index d99fc342c2b..74c9528071c 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -164,11 +164,6 @@ if(mob.stat==DEAD) return -// handle possible spirit movement - if(istype(mob,/mob/spirit)) - var/mob/spirit/currentSpirit = mob - return currentSpirit.Spirit_Move(direct) - if(mob.notransform) return//This is sota the goto stop mobs from moving var if(isliving(mob)) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index f8a73364264..3c5e3ac0130 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -244,8 +244,10 @@ if(!job.is_position_available()) return 0 if(jobban_isbanned(src,rank)) return 0 if(!is_job_whitelisted(src, rank)) return 0 - if(!job.player_old_enough(src.client)) return 0 + if(!job.player_old_enough(client)) return 0 if(job.admin_only && !(check_rights(R_EVENT, 0))) return 0 + if(job.available_in_playtime(client)) + return 0 if(config.assistantlimit) if(job.title == "Civilian") diff --git a/code/modules/mob/pulling.dm b/code/modules/mob/pulling.dm new file mode 100644 index 00000000000..6a6a66675b0 --- /dev/null +++ b/code/modules/mob/pulling.dm @@ -0,0 +1,41 @@ +//this and stop_pulling really ought to be /mob/living procs +/mob/proc/start_pulling(atom/movable/AM) + if(src == AM) // Trying to pull yourself is a shortcut to stop pulling + stop_pulling() + return + if(!AM || !isturf(AM.loc)) //if there's no object or the object being pulled is inside something: abort! + return + if(!(AM.anchored)) + AM.add_fingerprint(src) + + // If we're pulling something then drop what we're currently pulling and pull this instead. + if(pulling) + // Are we trying to pull something we are already pulling? Then just stop here, no need to continue. + if(AM == pulling) + return + stop_pulling() + + src.pulling = AM + AM.pulledby = src + if(pullin) + pullin.update_icon(src) + if(ismob(AM)) + var/mob/M = AM + if(!iscarbon(src)) + M.LAssailant = null + else + M.LAssailant = usr + +/mob/verb/stop_pulling() + set name = "Stop Pulling" + set category = "IC" + + if(pulling) + pulling.pulledby = null + pulling = null + if(pullin) + pullin.update_icon(src) + +/mob/living/proc/check_pull() + if(pulling && !(pulling in orange(1))) + stop_pulling() diff --git a/code/modules/mob/spirit/cultnet.dm b/code/modules/mob/spirit/cultnet.dm deleted file mode 100644 index b43ee46b842..00000000000 --- a/code/modules/mob/spirit/cultnet.dm +++ /dev/null @@ -1,32 +0,0 @@ -/* - -This file contains the code necessary to do the display code for cult spirits. - -It reuses a lot of code from the AIEye cameraNetwork. In order to work properly, some of those files needed to be modified as well. - -*/ - - -/proc/isCultRune(var/viewpoint) - var/obj/effect/rune/test_rune = viewpoint - if(test_rune) - return TRUE - return FALSE - - -/proc/isCultViewpoint(var/viewpoint) - var/obj/cult_viewpoint/vp = viewpoint - if(vp) - return TRUE - return FALSE - -/* -RUNE JUNK -*/ - -/obj/effect/rune/proc/can_use() - return TRUE - -/obj/effect/rune/proc/can_see() - return hear(view_range, get_turf(src)) - diff --git a/code/modules/mob/spirit/mask/mask.dm b/code/modules/mob/spirit/mask/mask.dm deleted file mode 100644 index d0cba0a130d..00000000000 --- a/code/modules/mob/spirit/mask/mask.dm +++ /dev/null @@ -1,227 +0,0 @@ -/mob/spirit/mask - icon = 'icons/mob/spirits/mask.dmi' - icon_state = "depressurized" - -/mob/spirit/mask/New() - ..() - AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/create_talisman(null)) - AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/blood_speech(null)) - AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/shatter_lights(null)) - - -/mob/spirit/mask/verb/go_to_follower() - set category = "Mask" - set name = "Go to follower" - set desc = "Select who you would like to go too." - - var/obj/cult_viewpoint/cultist = pick_cultist() - if(cultist) - follow_cultist(cultist.owner) - cult_log("[key_name(src)] started following [key_name(cultist)].") - to_chat(src, "You start following [cultist.get_display_name()].") - - -/mob/spirit/mask/verb/urge_cultist() - set category = "Mask" - set name = "Urge cultist" - set desc = "Push your cultists to do something." - - var/obj/cult_viewpoint/cultist = pick_cultist() - if(cultist) - if(cultist.owner) - var/newUrge = stripped_input(usr, "", "Set Urge", "") - cultist.set_urge(newUrge) - to_chat(src, "You urge [cultist.owner.name] to [newUrge].") - cult_log("The mask controlled by [key_name(src)] has urged [key_name(cultist.owner)] to [newUrge].") - -/mob/spirit/mask/verb/set_cult_name() - set category = "Mask" - set name = "Set Cult Name" - set desc = "Grant a cultist a name." - - var/obj/cult_viewpoint/cultist = pick_cultist() - if(cultist) - var/newName = stripped_input(usr, "", "Set Cult Name", "") - if(!newName) - return - cultist.set_cult_name(newName) - to_chat(src, "You grant [cultist.owner.name] the secret name of [newName].") - if(cultist.owner) - cult_log("[key_name(src)] has set [key_name(cultist.owner)] to \'[newName]\'") - - -/mob/spirit/mask/verb/urge_cult() - set category = "Mask" - set name = "Urge Cult" - set desc = "Set urge on the entire cult." - - var/newUrge = stripped_input(usr, "Please choose an urge.", "Set Urge", "") - for(var/obj/cult_viewpoint/viewpoint in cult_viewpoints) - viewpoint.set_urge(newUrge) - to_chat(src, "You urge the entire cult to [newUrge].") - cult_log("[key_name(src)] has urged the entire cult to [newUrge]") - - -/mob/spirit/mask/verb/set_favor_for_cultist() - set category = "Mask" - set name = "Show your favor" - set desc = "Set the favor for a cultist" - - var/obj/cult_viewpoint/cultist = pick_cultist() - if(cultist) - if(cultist.owner) - var/list/favor = list("Pleased", "Displeased", "Indifference") - var/emotion = input("Pick your emotion", "Mask", null, null) in favor - switch(emotion) - if("Pleased") - cultist.set_favor(1) - cult_log("[key_name(src)] is pleased with [key_name(cultist.owner)]") - if("Displeased") - cultist.set_favor(-1) - cult_log("[key_name(src)] is displeased with [key_name(cultist.owner)]") - if("Indifference") - cultist.set_favor(0) - cult_log("[key_name(src)] is indifferent too [key_name(cultist.owner)]") - - -/mob/spirit/mask/proc/set_name() - spawn(0) - var/newName = stripped_input(src, "Please pick a name.", "Pick Name for Mask", "") - name = newName ? newName : "Mask of Nar'sie" - to_chat(src, "You have set your name to [name].") - - -/mob/spirit/mask/proc/pick_cultist() - var/list/cultists = list() - for(var/obj/cult_viewpoint/viewpoint in cult_viewpoints) - cultists[viewpoint.get_display_name()]=viewpoint - var/input = input("Please, select a cultist!", "Cult", null, null) as null|anything in cultists - var/obj/cult_viewpoint/result = cultists[input] - return result - - -// this proc makes the mask visible very briefly -/mob/spirit/mask/proc/flicker() - spawn(0) - alpha = 127 - invisibility=0 - sleep(5) - invisibility=initial(invisibility) - alpha = 255 - -/proc/flicker_mask(mob/spirit/mask/target) - if(istype(target)) - target.flicker() - -// SPELLS -/obj/effect/proc_holder/spell/aoe_turf/blood_speech - name = "Speak to your Acolytes" - desc = "This spell allows you to speak to your flock." - school = "unknown evil" - charge_type = "recharge" - charge_max = 2000 - clothes_req = 0 - invocation = "none" - invocation_type = "none" - range = 0 - -/obj/effect/proc_holder/spell/aoe_turf/blood_speech/cast(list/targets, mob/user = usr) - var/input = stripped_input(user, "Please choose a message to tell your acolytes.", "Voice of Blood", "") - if(!input) - revert_cast(user) - cult_log("[key_name(user)] says: [input]") - flicker_mask(user) - for(var/datum/mind/H in ticker.mode.cult) - if(H.current) - to_chat(H.current, "[user.name]: [input]") - for(var/mob/spirit/spirit in spirits) - to_chat(spirit, "[user.name]: [input]") - - -/obj/effect/proc_holder/spell/aoe_turf/shatter_lights - name = "Spread Shadows" - desc = "This spell breaks lights near the mask." - school = "unknown evil" - charge_type = "recharge" - charge_max = 1000 - clothes_req = 0 - invocation = "none" - invocation_type = "none" - range = 0 - -/obj/effect/proc_holder/spell/aoe_turf/shatter_lights/cast(list/targets, mob/user = usr) - cult_log("[key_name(user)] used Spread Shadows.") - flicker_mask(user) - spawn(0) - for(var/area/A in range(3,get_turf(user))) - for(var/obj/machinery/light/L in A) - L.on = 1 - L.broken() - sleep(1) - for(var/obj/item/device/flashlight/F in A) - F.on = 0 - - -/obj/effect/proc_holder/spell/aoe_turf/conjure/create_talisman - name = "Create Talisman" - desc = "This spell conjures a talisman" - - school = "conjuration" - charge_type = "recharge" - charge_max = 3000 - clothes_req = 0 - invocation = "none" - invocation_type = "none" - range = 0 - summon_type = list(/obj/item/weapon/paper/talisman) - - var/list/talismans = list( "Armor"="armor", - "Blind"="blind", - "Conceal"="conceal", - "Communicate"="communicate", - "Deafen"="deafen", - "EMP"="emp", - "Teleport"="teleport", - "Tome"="newtome", - "Reveal Runes", - "Stun"="runestun", - "Soul Stone"="soulstone", - "Construct"="construct") - - -/obj/effect/proc_holder/spell/aoe_turf/conjure/create_talisman/cast(list/targets, mob/user = usr) - - var/talisman = input("Pick a talisman type", "Talisman", null, null) as null|anything in talismans - var/imbue_value = talismans[talisman] - if(!talisman) - to_chat(user, "You choose not to create a talisman.") - revert_cast(user) - return - - cult_log("[key_name(user)] created a talisman of type [talisman].") - flicker_mask(user) - - switch(talisman) - - if("Teleport") - var/target_rune = input("Pick a teleport target", "Teleport Rune", null, null) as null|anything in engwords - if(!target_rune) - to_chat(user, "You choose not to create a talisman.") - revert_cast(user) - return - summon_type = list(/obj/item/weapon/paper/talisman) - newVars = list("imbue" = "[target_rune]", "info" = "[target_rune]") - - if("Soul Stone") - summon_type = list(/obj/item/device/soulstone) - newVars = list() - - if("Construct") - summon_type = list(/obj/structure/constructshell) - newVars = list() - - else - summon_type = list(/obj/item/weapon/paper/talisman) - newVars = list("imbue" = "[imbue_value]") - - ..() \ No newline at end of file diff --git a/code/modules/mob/spirit/mask/respawn.dm b/code/modules/mob/spirit/mask/respawn.dm deleted file mode 100644 index 60330de917d..00000000000 --- a/code/modules/mob/spirit/mask/respawn.dm +++ /dev/null @@ -1,20 +0,0 @@ -/proc/there_can_be_only_one_mask(var/mob/spirit/mask/target) - if(!istype(target)) - return - for(var/mob/spirit/mask/currentSpirit in spirits) - if(currentSpirit) - if(currentSpirit!=target) - // create the ghost - var/mob/dead/observer/ghost = currentSpirit.ghostize(TRUE) - // let the deposed mask respawn immediately, the poor dear - ghost.timeofdeath = world.time - 20000 - ghost.newPlayerType = /mob/new_player/cultist - // remove old mask body - qdel(currentSpirit) - - -/mob/new_player/cultist/AttemptLateSpawn(rank) - var/mob/newCharacter = ..(rank) - if(ticker.mode) - if(is_convertable_to_cult(newCharacter.mind)) - ticker.mode.add_cultist(newCharacter.mind) \ No newline at end of file diff --git a/code/modules/mob/spirit/movement.dm b/code/modules/mob/spirit/movement.dm deleted file mode 100644 index b014fb42927..00000000000 --- a/code/modules/mob/spirit/movement.dm +++ /dev/null @@ -1,61 +0,0 @@ -// spirits are not moved by airflow -mob/spirit/Move() - return 0 - -// this is the main move proc for spirits, it uses their 'setLoc' function to handle all the visibility shenanigans -// this, like most movement code for these guys, is cribbed from the AIEye movement code -mob/spirit/proc/Spirit_Move(direct) - - var/initial = initial(sprint) - var/max_sprint = 50 - - // if we haven't moved in a while, we stop sprinting - if(cooldown && cooldown < world.timeofday) // 3 seconds - sprint = initial - - for(var/i = 0; i < max(sprint, initial); i += 20) - var/turf/step = get_turf(get_step(src, direct)) - if(step) - setLoc(step) - - dir = direct // update our sprite - - cooldown = world.timeofday + 5 - if(acceleration) - sprint = min(sprint + 0.5, max_sprint) - else - sprint = initial - - // if we're trying to move, we want to stop following our target - follow_target = null - - -/mob/spirit/proc/follow_cultist(mob/living/target as mob) - if(!istype(target)) return - var/obj/cult_viewpoint/currentView = getCultViewpoint(target) - var/mob/spirit/U = usr - - if(!currentView) - to_chat(U, "As a spirit, you may only track cultists.") - - U.follow_target = target - to_chat(U, "Now following [currentView.get_cult_name()].") - - spawn (0) - while(U.follow_target == target) - if(U.follow_target == null) - return - U.setLoc(get_turf(target)) - sleep(10) - - -mob/spirit/setLoc(var/T) - T = get_turf(T) - loc = T - -mob/spirit/verb/toggle_acceleration() - set category = "Spirit" - set name = "Toggle Acceleration" - - acceleration = !acceleration - to_chat(usr, "Acceleration has been toggled [acceleration ? "on" : "off"].") diff --git a/code/modules/mob/spirit/spirit.dm b/code/modules/mob/spirit/spirit.dm deleted file mode 100644 index a42d9e6817e..00000000000 --- a/code/modules/mob/spirit/spirit.dm +++ /dev/null @@ -1,70 +0,0 @@ -/* -This mob type is used for entities that exist within the Cult's spirit world. They share the same visibility network and are intangible. -*/ - -mob/spirit - name = "spirit" - desc = "A spirit" - icon = 'icons/mob/mob.dmi' - icon_state = "ghost" - layer = 4 - stat = CONSCIOUS - status_flags = GODMODE // spirits cannot be killed - density = 0 - canmove = 0 - blinded = 0 - anchored = 1 - mouse_opacity = 0 - invisibility = INVISIBILITY_SPIRIT - universal_speak = 1 - - // pseudo-movement values - var/sprint = 10 - var/cooldown = 0 - var/acceleration = 1 - var/follow_target = null - - -mob/spirit/proc/is_active() - if(client && client.inactivity <= 10 * 60 * 10) - return TRUE - return FALSE - - -mob/spirit/New() - sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF - see_invisible = SEE_SPIRITS - see_in_dark = 100 - - loc = pick(latejoin) - - // no nameless spirits - if(!name) - name = "Boogyman" - - spirits+=src - - ..() - -mob/spirit/Destroy() - spirits-=src - return ..() - - -mob/spirit/Topic(href, href_list) - - if(usr != src) - return - ..() - - to_chat(usr, "Spirit Href = [href]") - for(var/tempref in href_list) - to_chat(usr, "Spirit href list [tempref] = [href_list[tempref]]") - - if(href_list["track"]) - to_chat(usr, "Got to tracking.") - var/mob/target = locate(href_list["track"]) in mob_list - var/mob/spirit/A = locate(href_list["track2"]) in spirits - if(A && target) - A.follow_cultist(target) - return \ No newline at end of file diff --git a/code/modules/mob/spirit/viewpoint.dm b/code/modules/mob/spirit/viewpoint.dm deleted file mode 100644 index 53761d6ed57..00000000000 --- a/code/modules/mob/spirit/viewpoint.dm +++ /dev/null @@ -1,203 +0,0 @@ -#define FAVOR_PLEASED 1 -#define FAVOR_INDIFFERENT 0 -#define FAVOR_DISPLEASED -1 - - -var/obj/cult_viewpoint/list/cult_viewpoints = list() - - -/obj/cult_viewpoint - var/view_range = 7 - var/updating = 0 - var/mob/owner = null - var/urge = "" - var/favor = FAVOR_INDIFFERENT - var/cult_name = null - - -/obj/cult_viewpoint/New(var/mob/target) - owner = target - //src.loc = owner - cult_viewpoints+=src - //handle_missing_mask() - ..() - - -/obj/cult_viewpoint/Destroy() - processing_objects.Remove(src) - cult_viewpoints-=src - return ..() - - -// VERBS -/obj/cult_viewpoint/verb/check_urge() - set category = "Cult" - set desc = "Discover what your god commands of you." - set name = "Check Urge" - set src in usr - if(src.urge) - to_chat(owner, "\red \b You feel the urge to [src.urge]") - else - to_chat(owner, "\b You feel no supernatural compulsions.") - - -/obj/cult_viewpoint/verb/reach_out() - set category = "Cult" - set desc = "Reach out for your gods presence." - set name = "Reach Out" - set src in usr - - for(var/mob/spirit/mask/currentMask in spirits) - if(currentMask.is_active()) - to_chat(owner, "\red \b You feel the reassuring presence of your god.") - to_chat(currentMask, "[get_display_name()] has reached out to you.") - - return - to_chat(owner, "\b You feel a chilling absence.") - handle_missing_mask() - - -/obj/cult_viewpoint/verb/check_favor() - set category = "Cult" - set desc = "Check your favor with your god." - set name = "Check Favor" - set src in usr - switch(favor) - if(FAVOR_PLEASED) - to_chat(owner, "\red \b You bask in your gods favor.") - if(FAVOR_INDIFFERENT) - to_chat(owner, "\red \b You feel nothing.") - if(FAVOR_DISPLEASED) - to_chat(owner, "\red \b You cringe at your gods displeasure.") - - -/obj/cult_viewpoint/verb/pray_to_mask() - set category = "Cult" - set desc = "Pray to your god" - set name = "Pray to Nar'Sie" - set src in usr - - var/input = stripped_input(usr, "Please choose a message to say to your god.", "Pray to Nar'Sie", "") - if(!input) - return - - cult_log("[key_name(usr,0)] (Pray): [input]") - to_chat(owner, "You pray to Nar'Sie: [input]") - - for(var/mob/spirit/spirit in spirits) - to_chat(spirit, "[get_display_name()] prays : [input]") - - -// PROCS -/obj/cult_viewpoint/proc/set_favor(var/newFavor) - favor = newFavor - check_favor() - - -/obj/cult_viewpoint/proc/set_urge(var/newUrge) - if(!newUrge) - src.urge = null - src.urge = copytext(newUrge, 1, MAX_MESSAGE_LEN) - check_urge() - - -/obj/cult_viewpoint/proc/can_use() - if(owner.stat != DEAD) - return TRUE - return FALSE - - -/obj/cult_viewpoint/proc/can_see() - return hear(view_range, get_turf(owner)) - - -/obj/cult_viewpoint/proc/get_cult_name() - if(cult_name) - return cult_name - return "An Unknown Servant" - - -/obj/cult_viewpoint/proc/set_cult_name(var/newName) - if(!owner) - return FALSE - if(newName) - cult_name = newName - to_chat(owner, "\red \b You have been blessed with the secret name of '[newName]'.") - else - cult_name = null - to_chat(owner, "\red \b Your god has taken your secret name.") - - -/obj/cult_viewpoint/proc/get_display_name() - if(istype(src,/obj/effect/rune)) - return name - if(!owner) - return - if(cult_name) - return cult_name - return owner.name - - -/obj/cult_viewpoint/proc/become_mask() - set category = "Cult" - set name = "Become Mask" - set desc = "Sacrifice your life and become a Mask of Nar'sie." - set src in usr - - cult_log("[key_name(usr,0)] has tried to become a Mask of Nar'sie.") - - if(!active_mask()) - var/confirm = alert(owner.client, "You are about to become a Mask of Nar'sie. This will destroy your body, and you will only be able to guide the other cultists through communication. Are you sure?", "Confirm Your Sacrifice", "Yes", "No") - if(confirm == "Yes") - var/transformation_type = alert(owner.client, "You are about to become a Mask. Do you want it to be subtle or violent?", "Mask", "Subtle", "Violent") - if(!active_mask()) - cult_log("[key_name(usr,0)] has become a Mask of Nar'sie.") - if(transformation_type=="Subtle") - log_admin("[key_name_admin(owner)] has subtly become a Mask of Nar'sie") - owner.make_into_mask(0,0) - else - log_admin("[key_name_admin(owner)] has violently become a Mask of Nar'sie") - owner.make_into_mask(1,1) - else - return - else - to_chat(owner, "\b You cannot become a mask of Nar'Sie because a Mask already exists.") - mask_has_been_found() - return - - -/obj/cult_viewpoint/proc/active_mask() - for(var/mob/spirit/mask/currentMask in spirits) - if(currentMask.is_active()) - return TRUE - return FALSE - - -/obj/cult_viewpoint/proc/handle_missing_mask() - if(active_mask()) - mask_has_been_found() - else - mask_is_missing() - - -/obj/cult_viewpoint/proc/mask_has_been_found() - for(var/obj/cult_viewpoint/viewpoint in cult_viewpoints) - if(viewpoint.verbs.Find(/obj/cult_viewpoint/proc/become_mask)) - viewpoint.verbs-=/obj/cult_viewpoint/proc/become_mask - - -/obj/cult_viewpoint/proc/mask_is_missing() - for(var/obj/cult_viewpoint/viewpoint in cult_viewpoints) - if(!viewpoint.verbs.Find(/obj/cult_viewpoint/proc/become_mask)) - viewpoint.verbs+=/obj/cult_viewpoint/proc/become_mask - - -/proc/getCultViewpoint(var/mob/currentMob) - for(var/obj/cult_viewpoint/currentView in currentMob) - return currentView - return FALSE - - -#undef FAVOR_PLEASED -#undef FAVOR_INDIFFERENT -#undef FAVOR_DISPLEASED \ No newline at end of file diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm index 7358486deee..ace8ab1b621 100644 --- a/code/modules/mob/status_procs.dm +++ b/code/modules/mob/status_procs.dm @@ -171,6 +171,14 @@ /mob/proc/AdjustSlur() return +/mob/proc/CultSlur() + return + +/mob/proc/SetCultSlur() + return + +/mob/proc/AdjustCultSlur() + return /mob/proc/Stun() return diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 9033d6438cd..8adc505102b 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -42,56 +42,6 @@ qdel(src) return O -/mob/living/carbon/human/make_into_mask(var/should_gib = 0) - for(var/t in organs) - qdel(t) - return ..(should_gib) - - -/mob/proc/make_into_mask(var/should_gib = 0, var/should_remove_items = 0) - - if(!should_gib) - icon = null - invisibility = 101 - - if(!should_remove_items) - for(var/obj/item/W in src) - unEquip(W) - - var/mob/spirit/mask/new_spirit = new() - - if(mind) - new_spirit.mind = mind - new_spirit.mind.assigned_role = "Mask" - new_spirit.mind.original = new_spirit - - new_spirit.key = key - new_spirit.loc=loc - - if(should_gib) - spawn(0) - src.gib() // gib the body - else - spawn(0)//To prevent the proc from returning null. - src.visible_message( \ - "[src] disappears into the shadows, never to be seen again.", \ - "You disappear into the shadows, never to be seen again.", \ - "You hear strange noise, you can't quite place it.") - qdel(src) - - to_chat(new_spirit, "You are a Mask of Nar'sie now. You are a tiny fragment of the unknowable entity that is the god.") - to_chat(new_spirit, "Your job is to help your acolytes complete their goals. Be spooky. Do evil.") - - new_spirit.set_name() - - // let spirits identify cultists - if(ticker.mode) - ticker.mode.add_cult_icon_to_spirit(new_spirit) - - // highlander test - there_can_be_only_one_mask(new_spirit) - - return new_spirit //human -> robot diff --git a/code/modules/nano/modules/alarm_monitor.dm b/code/modules/nano/modules/alarm_monitor.dm index cf90b61bf29..015d0990ee7 100644 --- a/code/modules/nano/modules/alarm_monitor.dm +++ b/code/modules/nano/modules/alarm_monitor.dm @@ -62,7 +62,7 @@ ui.open() ui.set_auto_update(1) -/datum/nano_module/alarm_monitor/ui_data(mob/user, datum/topic_state/state = default_state) +/datum/nano_module/alarm_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/categories[0] diff --git a/code/modules/nano/modules/atmos_control.dm b/code/modules/nano/modules/atmos_control.dm index ee776ba4467..0670193e498 100644 --- a/code/modules/nano/modules/atmos_control.dm +++ b/code/modules/nano/modules/atmos_control.dm @@ -39,7 +39,7 @@ ui.set_auto_update(1) ui_ref = ui -/datum/nano_module/atmos_control/ui_data(mob/user, datum/topic_state/state = default_state) +/datum/nano_module/atmos_control/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["alarms"] = air_alarm_repository.air_alarm_data(monitored_alarms) return data diff --git a/code/modules/nano/modules/crew_monitor.dm b/code/modules/nano/modules/crew_monitor.dm index c5f8f6ecfb8..05749741461 100644 --- a/code/modules/nano/modules/crew_monitor.dm +++ b/code/modules/nano/modules/crew_monitor.dm @@ -31,7 +31,7 @@ // should make the UI auto-update; doesn't seem to? ui.set_auto_update(1) -/datum/nano_module/crew_monitor/ui_data(mob/user, datum/topic_state/state = default_state) +/datum/nano_module/crew_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/turf/T = get_turf(nano_host()) diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm index 8bc9058db37..21636465d4a 100644 --- a/code/modules/nano/modules/human_appearance.dm +++ b/code/modules/nano/modules/human_appearance.dm @@ -217,7 +217,7 @@ ui.open() ui.set_auto_update(1) -/datum/nano_module/appearance_changer/ui_data(mob/user, datum/topic_state/state = default_state) +/datum/nano_module/appearance_changer/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) generate_data(check_whitelist, whitelist, blacklist) var/data[0] diff --git a/code/modules/nano/modules/law_manager.dm b/code/modules/nano/modules/law_manager.dm index 0d79f719677..92378e3abcc 100644 --- a/code/modules/nano/modules/law_manager.dm +++ b/code/modules/nano/modules/law_manager.dm @@ -154,7 +154,7 @@ ui.open() ui.set_auto_update(1) -/datum/nano_module/law_manager/ui_data(mob/user, datum/topic_state/state = default_state) +/datum/nano_module/law_manager/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] owner.lawsync() diff --git a/code/modules/nano/modules/power_monitor.dm b/code/modules/nano/modules/power_monitor.dm index 1ebe6e99c9f..33e08b00e83 100644 --- a/code/modules/nano/modules/power_monitor.dm +++ b/code/modules/nano/modules/power_monitor.dm @@ -18,7 +18,7 @@ ui.open() ui.set_auto_update(1) -/datum/nano_module/power_monitor/ui_data(mob/user, datum/topic_state/state = default_state) +/datum/nano_module/power_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["powermonitor"] = powermonitor diff --git a/code/modules/nano/nanoexternal.dm b/code/modules/nano/nanoexternal.dm index 288a9df2255..6864c834f3a 100644 --- a/code/modules/nano/nanoexternal.dm +++ b/code/modules/nano/nanoexternal.dm @@ -44,11 +44,12 @@ * The ui_data proc is used to get data for the interface * * @param user /mob The mob who is viewing this ui + * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main") * @param state /datum/topic_state Current topic state of the UI * * @return list() */ -/datum/proc/ui_data(mob/user, datum/topic_state/state = default_state) +/datum/proc/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) return list() // Used by the Nano UI Manager (/datum/nanomanager) to track UIs opened by this mob diff --git a/code/modules/nano/nanomanager.dm b/code/modules/nano/nanomanager.dm index 2d0fe09c887..774aa875b89 100644 --- a/code/modules/nano/nanomanager.dm +++ b/code/modules/nano/nanomanager.dm @@ -23,7 +23,7 @@ ui = get_open_ui(user, src_object, ui_key) if(!isnull(ui)) - var/data = src_object.ui_data(user, ui.state) // Get data from src_object. + var/data = src_object.ui_data(user, ui_key, ui.state) // Get data from src_object. if(!force_open) ui.push_data(data) else diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index be5ad871a36..1622fe1700e 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -415,7 +415,7 @@ nanoui is used to open and update nano browser uis return if(!initial_data) - set_initial_data(src_object.ui_data(user, state)) // Get the UI data. + set_initial_data(src_object.ui_data(user, ui_key, state)) // Get the UI data. user << browse(get_html(), "window=[window_id];[window_size][window_options]") winset(user, "mapwindow.map", "focus=true") // return keyboard focus to map diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index 27a671590db..80f45fa0eaf 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -62,7 +62,7 @@ var/list/alldepartments = list() ui = new(user, src, ui_key, "faxmachine.tmpl", "Fax Machine UI", 540, 450) ui.open() -/obj/machinery/photocopier/faxmachine/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/photocopier/faxmachine/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] if(scan) @@ -109,16 +109,18 @@ var/list/alldepartments = list() if(href_list["paper"]) if(copyitem) - copyitem.loc = usr.loc - usr.put_in_hands(copyitem) - to_chat(usr, "You take \the [copyitem] out of \the [src].") + copyitem.forceMove(get_turf(src)) + if(ishuman(usr)) + if(!usr.get_active_hand()) + usr.put_in_hands(copyitem) + to_chat(usr, "You eject \the [copyitem] from \the [src].") copyitem = null else var/obj/item/I = usr.get_active_hand() if(istype(I, /obj/item/weapon/paper) || istype(I, /obj/item/weapon/photo) || istype(I, /obj/item/weapon/paper_bundle)) usr.drop_item() copyitem = I - I.loc = src + I.forceMove(src) to_chat(usr, "You insert \the [I] into \the [src].") flick(insert_anim, src) @@ -163,24 +165,24 @@ var/list/alldepartments = list() /obj/machinery/photocopier/faxmachine/proc/scan(var/obj/item/weapon/card/id/card = null) if(scan) // Card is in machine if(ishuman(usr)) - scan.loc = usr.loc + scan.forceMove(get_turf(usr)) if(!usr.get_active_hand()) usr.put_in_hands(scan) scan = null else - scan.loc = src.loc + scan.forceMove(get_turf(src)) scan = null else if(!card) var/obj/item/I = usr.get_active_hand() if(istype(I, /obj/item/weapon/card/id)) usr.drop_item() - I.loc = src + I.forceMove(src) scan = I else if(istype(card)) usr.drop_item() - card.loc = src + card.forceMove(src) scan = card nanomanager.update_uis(src) diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 104de41520e..d333ed1cf47 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -79,8 +79,10 @@ updateUsrDialog() else if(href_list["remove"]) if(copyitem) - copyitem.loc = usr.loc - usr.put_in_hands(copyitem) + copyitem.forceMove(get_turf(src)) + if(ishuman(usr)) + if(!usr.get_active_hand()) + usr.put_in_hands(copyitem) to_chat(usr, "You take \the [copyitem] out of \the [src].") copyitem = null updateUsrDialog() @@ -125,7 +127,7 @@ if(!copyitem) user.drop_item() copyitem = O - O.loc = src + O.forceMove(src) to_chat(user, "You insert \the [O] into \the [src].") flick(insert_anim, src) updateUsrDialog() @@ -150,10 +152,10 @@ if(ismob(G.affecting) && G.affecting != ass) var/mob/GM = G.affecting visible_message("[usr] drags [GM.name] onto the photocopier!") - GM.loc = get_turf(src) + GM.forceMove(get_turf(src)) ass = GM if(copyitem) - copyitem.loc = src.loc + copyitem.forceMove(get_turf(src)) copyitem = null updateUsrDialog() return @@ -290,10 +292,10 @@ W = copy(W) else if(istype(W, /obj/item/weapon/photo)) W = photocopy(W) - W.loc = p + W.forceMove(p) p.amount++ p.amount-- - p.loc = src.loc + p.forceMove(get_turf(src)) p.update_icon() p.icon_state = "paper_words" p.name = bundle.name @@ -313,10 +315,10 @@ if(target.anchored) return if(!ishuman(user)) return visible_message("[usr] drags [target.name] onto the photocopier!") - target.loc = get_turf(src) + target.forceMove(get_turf(src)) ass = target if(copyitem) - copyitem.loc = src.loc + copyitem.forceMove(get_turf(src)) visible_message("[copyitem] is shoved out of the way by [ass]!") copyitem = null updateUsrDialog() diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index 4cae827dd8e..c24dec2413f 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -514,7 +514,7 @@ var/list/SpookyGhosts = list("ghost","shade","shade2","ghost-narsie","horror","s if(on==0) src.icon_state = icon_off camera.c_tag = null - camera.network = null + camera.network = list() else src.icon_state = icon_on camera.network = list("news") diff --git a/code/modules/pda/PDA.dm b/code/modules/pda/PDA.dm index ed7c380c426..6874593f33a 100755 --- a/code/modules/pda/PDA.dm +++ b/code/modules/pda/PDA.dm @@ -129,7 +129,7 @@ var/global/list/obj/item/device/pda/PDAs = list() // auto update every Master Controller tick ui.set_auto_update(auto_update) -/obj/item/device/pda/ui_data(mob/user, datum/topic_state/state = inventory_state) +/obj/item/device/pda/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state) var/data[0] data["owner"] = owner // Who is your daddy... @@ -427,6 +427,9 @@ var/global/list/obj/item/device/pda/PDAs = list() user.drop_item() C.forceMove(src) to_chat(user, "You slide \the [C] into \the [src].") + else if(istype(C, /obj/item/weapon/nanomob_card)) + if(cartridge && istype(cartridge, /obj/item/weapon/cartridge/mob_hunt_game)) + cartridge.attackby(C, user, params) /obj/item/device/pda/attack(mob/living/C as mob, mob/living/user as mob) if(istype(C, /mob/living/carbon) && scanmode) @@ -498,3 +501,12 @@ var/global/list/obj/item/device/pda/PDAs = list() else close(usr) return 0 + +/obj/item/device/pda/process() + if(current_app) + current_app.program_process() + +/obj/item/device/pda/hit_check(speed) + if(current_app) + current_app.program_hit_check() + ..() \ No newline at end of file diff --git a/code/modules/pda/app.dm b/code/modules/pda/app.dm index e7c433c65a6..4ad6c40ae24 100644 --- a/code/modules/pda/app.dm +++ b/code/modules/pda/app.dm @@ -1,6 +1,6 @@ // Base class for anything that can show up on home screen /datum/data/pda - var/icon = "tasks" + var/icon = "tasks" //options comes from http://fontawesome.io/icons/ var/notify_icon = "exclamation-circle" var/notify_silent = 0 var/hidden = 0 // program not displayed in main menu @@ -12,6 +12,16 @@ return ..() /datum/data/pda/proc/start() + return + +/datum/data/pda/proc/stop() + return + +/datum/data/pda/proc/program_process() + return + +/datum/data/pda/proc/program_hit_check() + return /datum/data/pda/proc/notify(message, blink = 1) if(message) @@ -56,6 +66,8 @@ title = name /datum/data/pda/app/start() + if(pda.current_app) + pda.current_app.stop() pda.current_app = src return 1 diff --git a/code/modules/pda/cart.dm b/code/modules/pda/cart.dm index c96a8cfb11c..30d26607113 100644 --- a/code/modules/pda/cart.dm +++ b/code/modules/pda/cart.dm @@ -22,7 +22,7 @@ if(radio) radio.initialize() ..() - + /obj/item/weapon/cartridge/Destroy() if(radio) qdel(radio) @@ -53,8 +53,7 @@ /obj/item/weapon/cartridge/atmos name = "BreatheDeep Cartridge" icon_state = "cart-a" - programs = list( - new/datum/data/pda/utility/scanmode/gas) + programs = list(new/datum/data/pda/utility/scanmode/gas) /obj/item/weapon/cartridge/medical name = "Med-U Cartridge" @@ -66,8 +65,7 @@ /obj/item/weapon/cartridge/chemistry name = "ChemWhiz Cartridge" icon_state = "cart-chem" - programs = list( - new/datum/data/pda/utility/scanmode/reagent) + programs = list(new/datum/data/pda/utility/scanmode/reagent) /obj/item/weapon/cartridge/security name = "R.O.B.U.S.T. Cartridge" @@ -94,30 +92,25 @@ name = "CustodiPRO Cartridge" desc = "The ultimate in clean-room design." icon_state = "cart-j" - programs = list( - new/datum/data/pda/app/janitor) + programs = list(new/datum/data/pda/app/janitor) /obj/item/weapon/cartridge/lawyer name = "P.R.O.V.E. Cartridge" icon_state = "cart-s" - programs = list( - new/datum/data/pda/app/crew_records/security) + programs = list(new/datum/data/pda/app/crew_records/security) /obj/item/weapon/cartridge/clown name = "Honkworks 5.0" icon_state = "cart-clown" charges = 5 - programs = list( - new/datum/data/pda/utility/honk) - messenger_plugins = list( - new/datum/data/pda/messenger_plugin/virus/clown) + programs = list(new/datum/data/pda/utility/honk) + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/clown) /obj/item/weapon/cartridge/mime name = "Gestur-O 1000" icon_state = "cart-mi" charges = 5 - messenger_plugins = list( - new/datum/data/pda/messenger_plugin/virus/mime) + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/mime) /* /obj/item/weapon/cartridge/botanist @@ -129,8 +122,7 @@ /obj/item/weapon/cartridge/signal name = "generic signaler cartridge" desc = "A data cartridge with an integrated radio signaler module." - programs = list( - new/datum/data/pda/app/signaller) + programs = list(new/datum/data/pda/app/signaller) /obj/item/weapon/cartridge/signal/initialize() radio = new /obj/item/radio/integrated/signal(src) @@ -162,8 +154,7 @@ /obj/item/weapon/cartridge/head name = "Easy-Record DELUXE" icon_state = "cart-h" - programs = list( - new/datum/data/pda/app/status_display) + programs = list(new/datum/data/pda/app/status_display) /obj/item/weapon/cartridge/hop name = "HumanResources9001" @@ -303,12 +294,38 @@ icon_state = "cart" var/initial_remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. charges = 4 - programs = list( - new/datum/data/pda/utility/toggle_door) - messenger_plugins = list( - new/datum/data/pda/messenger_plugin/virus/detonate) + programs = list(new/datum/data/pda/utility/toggle_door) + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/detonate) /obj/item/weapon/cartridge/syndicate/New() var/datum/data/pda/utility/toggle_door/D = programs[1] if(istype(D)) - D.remote_door_id = initial_remote_door_id \ No newline at end of file + D.remote_door_id = initial_remote_door_id + +/obj/item/weapon/cartridge/mob_hunt_game + name = "Nano-Mob Hunter GO! Cartridge" + desc = "The hit new PDA game that lets you track down and capture your favorite Nano-Mobs living in your world!" + icon_state = "cart-eye" + programs = list(new/datum/data/pda/app/mob_hunter_game) + var/emagged = 0 + +/obj/item/weapon/cartridge/mob_hunt_game/attackby(obj/item/O, mob/user, params) + if(istype(O, /obj/item/weapon/nanomob_card)) + var/obj/item/weapon/nanomob_card/card = O + var/datum/data/pda/app/mob_hunter_game/my_game = programs[1] + if(my_game.register_capture(card.mob_data)) + to_chat(user, "Transfer successful!") + qdel(card) + else + to_chat(user, "Transfer failed. Could not read mob data from card.") + else + ..() + +/obj/item/weapon/cartridge/mob_hunt_game/emag_act(mob/user) + if(!emagged) + emagged = 1 + var/datum/data/pda/app/mob_hunter_game/my_game = programs[1] + my_game.hacked = 1 + to_chat(user, "TR4P_M45T3R.mod successfully initialized. ToS violated. User Agreement nullified. Gotta pwn them all.") + to_chat(user, "You can now create trapped versions of any mob in your collection that will damage hunters who attempt to capture it.") + description_antag = "This copy of Nano-Mob Hunter GO! has been hacked to allow the creation of trap mobs which will cause any PDA that attempts to capture it to shock anyone holding it. Hacked copies of the game will not trigger the trap." \ No newline at end of file diff --git a/code/modules/pda/mob_hunt_game_app.dm b/code/modules/pda/mob_hunt_game_app.dm new file mode 100644 index 00000000000..9b8e3225976 --- /dev/null +++ b/code/modules/pda/mob_hunt_game_app.dm @@ -0,0 +1,182 @@ + +/* + This stuff isn't included with in core_apps.dm because it is so distinct and would end up making the file huge (more than it already is). + I put it in it's own file in order to help it stay organized and easier to locate the procs and such. + For reference, the other Nano-mob Hunter GO files are in /code/game/modules/arcade/mob_hunt +*/ + +/datum/data/pda/app/mob_hunter_game + name = "Nano-Mob Hunter GO" + icon = "gamepad" + template = "pda_mob_hunt" + category = "Games" + + var/list/my_collection = list() + var/current_index = 0 + var/connected = 0 + var/hacked = 0 //if set, this cartridge is able to spawn trap mobs from its collection (set via emag_act on the cartridge) + var/catch_mod = 0 //used to adjust the likelihood of a mob running from this client, a negative value means it is less likely to run (support for temporary bonuses) + var/wild_captures = 0 //used to track the total number of mobs captured from the wild (does not count card mobs) by this client + var/scan_range = 3 //maximum distance (in tiles) from which the client can reveal nearby mobs + +/datum/data/pda/app/mob_hunter_game/start() + ..() + processing_objects.Add(pda) + +/datum/data/pda/app/mob_hunter_game/stop() + ..() + disconnect("Program Terminated") + processing_objects.Remove(pda) + +/datum/data/pda/app/mob_hunter_game/proc/scan_nearby() + if(!mob_hunt_server || !connected) + return + for(var/turf/T in range(scan_range, get_turf(pda))) + for(var/obj/effect/nanomob/N in T.contents) + if(src in N.clients_encountered) + //hide the mob + N.conceal() + else + //reveal the mob + N.reveal() + +/datum/data/pda/app/mob_hunter_game/proc/reconnect() + if(!mob_hunt_server || !mob_hunt_server.server_status || connected) + //show a message about the server being unavailable (because it doesn't exist / didn't get set to the global var / is offline) + return 0 + mob_hunt_server.connected_clients += src + connected = 1 + if(pda) + pda.audible_message("[bicon(pda)] Connection established. Capture all of the mobs, [pda.owner ? pda.owner : "hunter"]!", null, 2) + return 1 + +/datum/data/pda/app/mob_hunter_game/proc/get_player() + if(!pda) + return null + if(ishuman(pda.loc)) + var/mob/living/carbon/human/H = pda.loc + return H + return null + +/datum/data/pda/app/mob_hunter_game/proc/disconnect(reason = null) + if(!mob_hunt_server || !connected) + return + mob_hunt_server.connected_clients -= src + for(var/obj/effect/nanomob/N in (mob_hunt_server.normal_spawns + mob_hunt_server.trap_spawns)) + N.conceal(list(get_player())) + connected = 0 + //show a disconnect message if we were disconnected involuntarily (reason argument provided) + if(pda && reason) + pda.audible_message("[bicon(pda)] Disconnected from server. Reason: [reason].", null, 2) + +/datum/data/pda/app/mob_hunter_game/program_process() + if(!mob_hunt_server || !connected) + return + scan_nearby() + +/datum/data/pda/app/mob_hunter_game/program_hit_check() + if(!pda) + return + for(var/obj/effect/nanomob/hit_mob in get_turf(pda)) + hit_mob.hitby(pda) + +/datum/data/pda/app/mob_hunter_game/proc/register_capture(datum/mob_hunt/captured, wild = 0) + if(!captured) + return 0 + my_collection.Add(captured) + if(wild) + wild_captures++ + return 1 + +/datum/data/pda/app/mob_hunter_game/update_ui(mob/user, list/data) + if(!mob_hunt_server || !(src in mob_hunt_server.connected_clients)) + data["connected"] = 0 + else + data["connected"] = 1 + data["wild_captures"] = wild_captures + data["no_collection"] = 0 + if(!my_collection.len) + data["no_collection"] = 1 + return + var/datum/mob_hunt/mob_info + if(!current_index) + current_index = 1 + if(current_index > my_collection.len) + current_index = 1 + if(current_index < 1) + current_index = my_collection.len + mob_info = my_collection[current_index] + var/list/entry = list( + "nickname" = mob_info.nickname, + "real_name" = mob_info.mob_name, + "level" = mob_info.level, + "type1" = mob_info.get_type1(), + "type2" = mob_info.get_type2(), + "sprite" = "[mob_info.icon_state_normal].png", + "is_hacked" = hacked + ) + if(mob_info.is_shiny) + entry["sprite"] = "[mob_info.icon_state_shiny].png" + data["entry"] = entry + +/datum/data/pda/app/mob_hunter_game/proc/assign_nickname() + if(!my_collection.len) + return + var/datum/mob_hunt/mob_info = my_collection[current_index] + var/old_name = mob_info.mob_name + if(mob_info.nickname) + old_name = mob_info.nickname + mob_info.nickname = input("Give a nickname to [old_name]?", "Nickname", old_name) + +/datum/data/pda/app/mob_hunter_game/proc/release() + if(!my_collection.len) + return + if(alert("Are you sure you want to release this mob back into the wild?", "Confirm Release", "Yes", "No") == "Yes") + remove_mob() + +/datum/data/pda/app/mob_hunter_game/proc/print_card() + if(!pda || !my_collection.len) + return + var/obj/item/weapon/nanomob_card/card = new/obj/item/weapon/nanomob_card(null) + var/datum/mob_hunt/mob_info = my_collection[current_index] + card.mob_data = mob_info + card.update_info() + card.forceMove(get_turf(pda)) + remove_mob() + +/datum/data/pda/app/mob_hunter_game/proc/remove_mob() + if(!my_collection.len) + return + my_collection.Remove(my_collection[current_index]) + if(current_index > my_collection.len) + current_index = my_collection.len + +/datum/data/pda/app/mob_hunter_game/proc/set_trap() + if(!my_collection.len || !pda || !hacked) + return + var/datum/mob_hunt/bait = my_collection[current_index] + bait = bait.type + new bait(1, get_turf(pda)) + +/datum/data/pda/app/mob_hunter_game/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Rename") + assign_nickname() + if("Release") + release() + if("Next") + current_index++ + if(current_index > my_collection.len) + current_index = 1 + if("Prev") + current_index-- + if(current_index < 1) + current_index = my_collection.len + if("Reconnect") + reconnect() + if("Disconnect") + disconnect() + if("Transfer") + print_card() + if("Set_Trap") + set_trap() \ No newline at end of file diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 675cbcdfac6..ae931484524 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -787,7 +787,7 @@ // Auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/power/apc/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/power/apc/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["locked"] = is_locked(user) data["isOperating"] = operating diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index 4a35e57764c..0abb033e3e8 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -327,7 +327,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/power/port_gen/pacman/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/power/port_gen/pacman/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["active"] = active diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index cf5698bc531..43782f8b2ce 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -24,7 +24,9 @@ /obj/singularity/narsie/large/New() ..() - to_chat(world, "NAR-SIE HAS RISEN") + icon_state = ticker.mode.cultdat.entity_icon_state + name = ticker.mode.cultdat.entity_name + to_chat(world, " [name] HAS RISEN") world << pick(sound('sound/hallucinations/im_here1.ogg'), sound('sound/hallucinations/im_here2.ogg')) var/area/A = get_area(src) @@ -38,7 +40,7 @@ shuttle_master.emergency.request(null, 0.3) // Cannot recall /obj/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob) - makeNewConstruct(/mob/living/simple_animal/construct/harvester, user, null, 1) + makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, user, null, 1) new /obj/effect/effect/sleep_smoke(user.loc) @@ -121,12 +123,12 @@ /obj/singularity/narsie/proc/acquire(var/mob/food) - to_chat(target, "NAR-SIE HAS LOST INTEREST IN YOU") + to_chat(target, "[uppertext(ticker.mode.cultdat.entity_name)] HAS LOST INTEREST IN YOU") target = food if(ishuman(target)) - to_chat(target, "NAR-SIE HUNGERS FOR YOUR SOUL") + to_chat(target, "[uppertext(ticker.mode.cultdat.entity_name)] HUNGERS FOR YOUR SOUL") else - to_chat(target, "NAR-SIE HAS CHOSEN YOU TO LEAD HIM TO HIS NEXT MEAL") + to_chat(target, "[uppertext(ticker.mode.cultdat.entity_name)] HAS CHOSEN YOU TO LEAD HER TO HER NEXT MEAL") //Wizard narsie /obj/singularity/narsie/wizard diff --git a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm index a75bdd3ec80..7fba50784b8 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm @@ -95,10 +95,10 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin if(usr.stat || !usr.canmove || usr.restrained()) return - if(src.anchored) + if(anchored) to_chat(usr, "It is fastened to the floor!") return 0 - src.dir = turn(src.dir, 270) + dir = turn(dir, 270) return 1 /obj/structure/particle_accelerator/AltClick(mob/user) @@ -116,29 +116,29 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin if(usr.stat || !usr.canmove || usr.restrained()) return - if(src.anchored) + if(anchored) to_chat(usr, "It is fastened to the floor!") return 0 - src.dir = turn(src.dir, 90) + dir = turn(dir, 90) return 1 /obj/structure/particle_accelerator/examine(mob/user) - switch(src.construction_state) + switch(construction_state) if(0) - src.desc = text("A [name], looks like it's not attached to the flooring") + desc = text("A [name], looks like it's not attached to the flooring") if(1) - src.desc = text("A [name], it is missing some cables") + desc = text("A [name], it is missing some cables") if(2) - src.desc = text("A [name], the panel is open") + desc = text("A [name], the panel is open") if(3) - src.desc = text("The [name] is assembled") + desc = text("The [name] is assembled") if(powered) - src.desc = src.desc_holder + desc = desc_holder ..(user) /obj/structure/particle_accelerator/attackby(obj/item/W, mob/user, params) if(istool(W)) - if(src.process_tool_hit(W,user)) + if(process_tool_hit(W,user)) return ..() return @@ -208,7 +208,7 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin /obj/structure/particle_accelerator/proc/connect_master(var/obj/O) if(O && istype(O,/obj/machinery/particle_accelerator/control_box)) - if(O.dir == src.dir) + if(O.dir == dir) master = O return 1 return 0 @@ -219,51 +219,51 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin return 0 if(!ismob(user) || !isobj(O)) return 0 - var/temp_state = src.construction_state + var/temp_state = construction_state - switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps + switch(construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps if(0) if(iswrench(O) && !isinspace()) - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - src.anchored = 1 - user.visible_message("[user.name] secures the [src.name] to the floor.", \ + playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) + anchored = 1 + user.visible_message("[user.name] secures the [name] to the floor.", \ "You secure the external bolts.") temp_state++ if(1) if(iswrench(O)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - src.anchored = 0 - user.visible_message("[user.name] detaches the [src.name] from the floor.", \ + playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) + anchored = 0 + user.visible_message("[user.name] detaches the [name] from the floor.", \ "You remove the external bolts.") temp_state-- else if(iscoil(O)) var/obj/item/stack/cable_coil/C = O if(C.use(1)) - user.visible_message("[user.name] adds wires to the [src.name].", \ + user.visible_message("[user.name] adds wires to the [name].", \ "You add some wires.") temp_state++ else - to_chat(user, "You need one length of cable to wire the [src.name]!") + to_chat(user, "You need one length of cable to wire the [name]!") return if(2) if(iswirecutter(O))//TODO:Shock user if its on? - user.visible_message("[user.name] removes some wires from the [src.name].", \ + user.visible_message("[user.name] removes some wires from the [name].", \ "You remove some wires.") temp_state-- else if(isscrewdriver(O)) - user.visible_message("[user.name] closes the [src.name]'s access panel.", \ + user.visible_message("[user.name] closes the [name]'s access panel.", \ "You close the access panel.") temp_state++ if(3) if(isscrewdriver(O)) - user.visible_message("[user.name] opens the [src.name]'s access panel.", \ + user.visible_message("[user.name] opens the [name]'s access panel.", \ "You open the access panel.") temp_state-- - if(temp_state == src.construction_state)//Nothing changed + if(temp_state == construction_state)//Nothing changed return 0 else - src.construction_state = temp_state - if(src.construction_state < 3)//Was taken apart, update state + construction_state = temp_state + if(construction_state < 3)//Was taken apart, update state update_state() update_icon() return 1 @@ -296,10 +296,10 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin if(usr.stat || !usr.canmove || usr.restrained()) return - if(src.anchored) + if(anchored) to_chat(usr, "It is fastened to the floor!") return 0 - src.dir = turn(src.dir, 270) + dir = turn(dir, 270) return 1 /obj/machinery/particle_accelerator/verb/rotateccw() @@ -309,10 +309,10 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin if(usr.stat || !usr.canmove || usr.restrained()) return - if(src.anchored) + if(anchored) to_chat(usr, "It is fastened to the floor!") return 0 - src.dir = turn(src.dir, 90) + dir = turn(dir, 90) return 1 /obj/machinery/particle_accelerator/update_icon() @@ -320,7 +320,7 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin /obj/machinery/particle_accelerator/attackby(obj/item/W, mob/user, params) if(istool(W)) - if(src.process_tool_hit(W,user)) + if(process_tool_hit(W,user)) return ..() return @@ -357,51 +357,53 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin return 0 if(!ismob(user) || !isobj(O)) return 0 - var/temp_state = src.construction_state - switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps + var/temp_state = construction_state + switch(construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps if(0) if(iswrench(O)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - src.anchored = 1 - user.visible_message("[user.name] secures the [src.name] to the floor.", \ + playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) + anchored = 1 + user.visible_message("[user.name] secures the [name] to the floor.", \ "You secure the external bolts.") temp_state++ + power_change() if(1) if(iswrench(O)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - src.anchored = 0 - user.visible_message("[user.name] detaches the [src.name] from the floor.", \ + playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) + anchored = 0 + user.visible_message("[user.name] detaches the [name] from the floor.", \ "You remove the external bolts.") temp_state-- + power_change() else if(iscoil(O)) if(O:use(1)) - user.visible_message("[user.name] adds wires to the [src.name].", \ + user.visible_message("[user.name] adds wires to the [name].", \ "You add some wires.") temp_state++ if(2) if(iswirecutter(O))//TODO:Shock user if its on? - user.visible_message("[user.name] removes some wires from the [src.name].", \ + user.visible_message("[user.name] removes some wires from the [name].", \ "You remove some wires.") temp_state-- else if(isscrewdriver(O)) - user.visible_message("[user.name] closes the [src.name]'s access panel.", \ + user.visible_message("[user.name] closes the [name]'s access panel.", \ "You close the access panel.") temp_state++ if(3) if(isscrewdriver(O)) - user.visible_message("[user.name] opens the [src.name]'s access panel.", \ + user.visible_message("[user.name] opens the [name]'s access panel.", \ "You open the access panel.") temp_state-- active = 0 - if(temp_state == src.construction_state)//Nothing changed + if(temp_state == construction_state)//Nothing changed return 0 else - if(src.construction_state < 3)//Was taken apart, update state + if(construction_state < 3)//Was taken apart, update state update_state() if(use_power) use_power = 0 - src.construction_state = temp_state - if(src.construction_state >= 3) + construction_state = temp_state + if(construction_state >= 3) use_power = 1 update_icon() return 1 diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm index ed2fb257015..636fe7d338b 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_control.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm @@ -24,6 +24,7 @@ /obj/machinery/particle_accelerator/control_box/New() wires = new(src) connected_parts = list() + update_icon() ..() /obj/machinery/particle_accelerator/control_box/Destroy() @@ -34,7 +35,7 @@ return ..() /obj/machinery/particle_accelerator/control_box/attack_ghost(user as mob) - return src.attack_hand(user) + return attack_hand(user) /obj/machinery/particle_accelerator/control_box/attack_hand(mob/user as mob) if(construction_state >= 3) @@ -62,9 +63,12 @@ /obj/machinery/particle_accelerator/control_box/update_icon() if(active) - icon_state = "[reference]p1" + icon_state = "[reference]p[strength]" else - if(use_power) + if(stat & NOPOWER) + icon_state = "[reference]w" + return + else if(use_power) if(assembled) icon_state = "[reference]p" else @@ -89,16 +93,16 @@ to_chat(usr, "ERROR: Request timed out. Check wire contacts.") return - if( href_list["close"] ) + if(href_list["close"]) usr << browse(null, "window=pacontrol") usr.unset_machine() return if(href_list["togglep"]) if(!wires.IsIndexCut(PARTICLE_TOGGLE_WIRE)) - src.toggle_power() + toggle_power() else if(href_list["scan"]) - src.part_scan() + part_scan() else if(href_list["strengthup"]) if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE)) @@ -108,8 +112,8 @@ if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE)) remove_strength() - src.updateDialog() - src.update_icon() + updateDialog() + update_icon() return @@ -152,32 +156,39 @@ use_power = 0 else if(!stat && construction_state <= 3) use_power = 1 + update_icon() + + if((stat & NOPOWER) || (!stat && construction_state <= 3)) //Only update the part icons if something's changed (i.e. any of the above condition sets are met). + for(var/obj/structure/particle_accelerator/part in connected_parts) + part.strength = null + part.powered = 0 + part.update_icon() return /obj/machinery/particle_accelerator/control_box/process() - if(src.active) + if(active) //a part is missing! - if( length(connected_parts) < 6 ) + if(length(connected_parts) < 6) investigate_log("lost a connected part; It powered down.","singulo") - src.toggle_power() + toggle_power() return //emit some particles for(var/obj/structure/particle_accelerator/particle_emitter/PE in connected_parts) if(PE) - PE.emit_particle(src.strength) + PE.emit_particle(strength) return /obj/machinery/particle_accelerator/control_box/proc/part_scan() for(var/obj/structure/particle_accelerator/fuel_chamber/F in orange(1,src)) - src.dir = F.dir + dir = F.dir connected_parts = list() var/tally = 0 var/ldir = turn(dir,-90) var/rdir = turn(dir,90) var/odir = turn(dir,180) - var/turf/T = src.loc + var/turf/T = loc T = get_step(T,rdir) if(check_part(T,/obj/structure/particle_accelerator/fuel_chamber)) tally++ @@ -213,26 +224,26 @@ if(istype(PA, type)) if(PA.connect_master(src)) if(PA.report_ready(src)) - src.connected_parts.Add(PA) + connected_parts.Add(PA) return 1 return 0 /obj/machinery/particle_accelerator/control_box/proc/toggle_power() - src.active = !src.active + active = !active investigate_log("turned [active?"ON":"OFF"] by [usr ? usr.key : "outside forces"]","singulo") if(active) msg_admin_attack("PA Control Computer turned ON by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) log_game("PA Control Computer turned ON by [usr.ckey]([usr]) in ([x],[y],[z])") use_log += text("\[[time_stamp()]\] [usr.name] ([usr.ckey]) has turned on the PA Control Computer.") - if(src.active) - src.use_power = 2 + if(active) + use_power = 2 for(var/obj/structure/particle_accelerator/part in connected_parts) - part.strength = src.strength + part.strength = strength part.powered = 1 part.update_icon() else - src.use_power = 1 + use_power = 1 for(var/obj/structure/particle_accelerator/part in connected_parts) part.strength = null part.powered = 0 @@ -262,13 +273,13 @@ else dat += "Off
" dat += "Toggle Power

" - dat += "Particle Strength: [src.strength] " + dat += "Particle Strength: [strength] " dat += "--|++

" //user << browse(dat, "window=pacontrol;size=420x500") //onclose(user, "pacontrol") var/datum/browser/popup = new(user, "pacontrol", name, 420, 500) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() return \ No newline at end of file diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index 62557e85384..02597b46840 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -375,7 +375,7 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/power/smes/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/power/smes/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["nameTag"] = name_tag diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 98d899cdbca..5f137f4cb74 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -395,7 +395,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/power/solar_control/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/power/solar_control/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["generated"] = round(lastgen) diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 8eaa784493d..c1a202fa134 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -268,7 +268,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/power/supermatter_shard/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/power/supermatter_shard/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["integrity_percentage"] = round(get_integrity()) diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index acbdc19b659..9a3ecffedb6 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -121,7 +121,7 @@ // open the new ui window ui.open() -/obj/machinery/chem_dispenser/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/chem_dispenser/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["amount"] = amount diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm index bd32fcee6cd..e9025a2aa3d 100644 --- a/code/modules/reagents/chemistry/machinery/chem_heater.dm +++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm @@ -136,7 +136,7 @@ ui = new(user, src, ui_key, "chem_heater.tmpl", "ChemHeater", 350, 270) ui.open() -/obj/machinery/chem_heater/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/chem_heater/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["targetTemp"] = desired_temp diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 3ef20cff9b3..569bdb3f4e1 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -328,7 +328,7 @@ ui = new(user, src, ui_key, "chem_master.tmpl", name, 575, 400) ui.open() -/obj/machinery/chem_master/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/chem_master/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["condi"] = condi diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm index ef00ea54c61..f5e409a1cb4 100644 --- a/code/modules/reagents/chemistry/reagents/water.dm +++ b/code/modules/reagents/chemistry/reagents/water.dm @@ -278,6 +278,7 @@ M.AdjustStuttering(4, bound_lower = 0, bound_upper = 20) M.Dizzy(5) if(iscultist(M) && prob(5)) + M.AdjustCultSlur(5)//5 seems like a good number... M.say(pick("Av'te Nar'sie","Pa'lid Mors","INO INO ORA ANA","SAT ANA!","Daim'niodeis Arc'iai Le'eones","Egkau'haom'nai en Chaous","Ho Diak'nos tou Ap'iron","R'ge Na'sie","Diabo us Vo'iscum","Si gn'um Co'nu")) if(current_cycle >= 75 && prob(33)) // 30 units, 150 seconds M.AdjustConfused(3) @@ -359,6 +360,7 @@ M.adjustFireLoss(2) M.adjustOxyLoss(2) M.adjustBruteLoss(2) + M.AdjustCultSlur(10)//CUASE WHY THE HELL NOT ..() /datum/reagent/fuel/unholywater/on_mob_delete(mob/living/M) diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index feb350d4d91..6691df19a1d 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -247,7 +247,7 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/disposal/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/disposal/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] var/pressure = Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index a39c6485fc7..121eb0ee2d3 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -652,7 +652,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, ui = new(user, src, ui_key, "r_n_d.tmpl", src.name, 800, 550) ui.open() -/obj/machinery/computer/rdconsole/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/rdconsole/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] files.RefreshResearch() diff --git a/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm b/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm index 69b9d449f2c..031e23c260d 100644 --- a/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm +++ b/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm @@ -117,7 +117,7 @@ continue //skip monkeys and leavers if(istype(M, /mob/new_player)) continue - if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) + if(M.stat == DEAD && M.get_preference(CHAT_GHOSTEARS)) listening|=M for(var/mob/M in listening) diff --git a/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm b/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm index c231912484b..bd2c704f21f 100644 --- a/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm +++ b/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm @@ -126,7 +126,7 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/radiocarbon_spectrometer/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/radiocarbon_spectrometer/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["scanned_item"] = (scanned_item ? scanned_item.name : "") data["scanned_item_desc"] = (scanned_item ? (scanned_item.desc ? scanned_item.desc : "No information on record.") : "") diff --git a/code/modules/security_levels/keycard authentication.dm b/code/modules/security_levels/keycard authentication.dm index f2d36842504..8435d8cf992 100644 --- a/code/modules/security_levels/keycard authentication.dm +++ b/code/modules/security_levels/keycard authentication.dm @@ -75,7 +75,7 @@ ui = new(user, src, ui_key, "keycard_auth.tmpl", "Keycard Authentication Device UI", 540, 320) ui.open() -/obj/machinery/keycard_auth/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/keycard_auth/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["screen"] = screen data["event"] = event diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 815541f36bc..4d5e38d17ec 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -8,10 +8,13 @@ /atom/movable/lighting_overlay/onShuttleMove() return 0 -/obj/onShuttleMove() - if(invisibility >= 101) - return 0 - . = ..() +/obj/effect/landmark/shuttle_import/onShuttleMove() + // Used for marking where to preview/load shuttles + return 0 + +/obj/docking_port/onShuttleMove() + // Stationary ports shouldn't move, mobile ones move themselves + return 0 /obj/machinery/door/onShuttleMove() . = ..() diff --git a/code/modules/shuttle/shuttle_manipulator.dm b/code/modules/shuttle/shuttle_manipulator.dm index 9259ac5051e..34196c888b0 100644 --- a/code/modules/shuttle/shuttle_manipulator.dm +++ b/code/modules/shuttle/shuttle_manipulator.dm @@ -59,13 +59,12 @@ ui_interact(user) /obj/machinery/shuttle_manipulator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - // update the ui if it exists, returns null if no ui is passed/found ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) // the ui does not exist, so we'll create a new() one // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "shuttle_manipulator.tmpl", "Shuttle Manipulator", 660, 700) + ui = new(user, src, ui_key, "shuttle_manipulator.tmpl", "Shuttle Manipulator", 660, 700, null, null, admin_state) // when the ui is first opened this is the data it will use // open the new ui window ui.open() diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index 23d2fe52787..970daf16e80 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -430,7 +430,7 @@ ui = new(user, src, ui_key, "order_console.tmpl", name, ORDER_SCREEN_WIDTH, ORDER_SCREEN_HEIGHT) ui.open() -/obj/machinery/computer/ordercomp/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/ordercomp/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["last_viewed_group"] = last_viewed_group @@ -579,7 +579,7 @@ ui = new(user, src, ui_key, "supply_console.tmpl", name, SUPPLY_SCREEN_WIDTH, SUPPLY_SCREEN_HEIGHT) ui.open() -/obj/machinery/computer/supplycomp/ui_data(mob/user, datum/topic_state/state = default_state) +/obj/machinery/computer/supplycomp/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] data["last_viewed_group"] = last_viewed_group diff --git a/code/modules/spacepods/parts.dm b/code/modules/spacepods/parts.dm index 0747f1c5a14..d1aefb535e6 100644 --- a/code/modules/spacepods/parts.dm +++ b/code/modules/spacepods/parts.dm @@ -30,7 +30,7 @@ var/turf/T var/obj/item/pod_parts/pod_frame/linked var/obj/item/pod_parts/pod_frame/pointer - var/connectedparts = list() + var/list/connectedparts = list() neededparts -= src //log_admin("Starting with [src]") linked = src @@ -44,7 +44,8 @@ connectedparts += pointer linked = pointer pointer = null - //log_admin("Parts left: [neededparts.len]") //len not working + if(connectedparts.len < 4) + return 0 for(var/i = 1; i <=4; i++) var/obj/item/pod_parts/pod_frame/F = connectedparts[i] if(F.type in neededparts) //if one of the items can be founded in neededparts @@ -122,4 +123,4 @@ name = "civilian pod armor" icon = 'icons/goonstation/pods/pod_parts.dmi' icon_state = "pod_armor_civ" - desc = "Spacepod armor. This is the civilian version. It looks rather flimsy." \ No newline at end of file + desc = "Spacepod armor. This is the civilian version. It looks rather flimsy." diff --git a/code/modules/store/items.dm b/code/modules/store/items.dm index c67ed43fd92..4fc51d7fb8d 100644 --- a/code/modules/store/items.dm +++ b/code/modules/store/items.dm @@ -57,6 +57,12 @@ typepath = /obj/item/weapon/storage/box/dice cost = 200 +/datum/storeitem/nanomob_booster + name = "Nano-Mob Hunter Trading Card Booster Pack" + desc = "Contains 6 random Nano-Mob Hunter Trading Cards. May contain a holographic card!" + typepath = /obj/item/weapon/storage/box/nanomob_booster_pack + cost = 250 + /datum/storeitem/crayons name = "Crayons" desc = "Let security know how they're doing by scrawling lovenotes all over their hallways." diff --git a/config/example/config.txt b/config/example/config.txt index c8066d03833..0efba2b8540 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -17,6 +17,13 @@ JOBS_HAVE_MINIMAL_ACCESS ## you have noone older than 0 days, since noone has been logged yet. Only turn this on once you have had the database up for 30 days. #USE_AGE_RESTRICTION_FOR_JOBS +##Unhash this to track player playtime in the database. Requires database to be enabled. +#USE_EXP_TRACKING +##Unhash this to enable playtime requirements for jobs that have them defined. +#USE_EXP_RESTRICTIONS +##Allows admins to bypass job playtime requirements. +USE_EXP_RESTRICTIONS_ADMIN_BYPASS + ## Unhash this entry to have certain antagonist roles require your account to be at least a certain number of days old to select. You can configure the exact age requirement for different antag roles by editing special_role_times in /code/modules/client/preferences.dm. ## See USE_AGE_RESTRICTION_FOR_JOBS for more information #USE_AGE_RESTRICTION_FOR_ANTAGS @@ -153,6 +160,9 @@ GUEST_JOBBAN ## Uncomment this to stop people connecting to your server without a registered ckey. (i.e. guest-* are all blocked from connecting) GUEST_BAN +## Comment to disable checking for the cid randomizer dll. (disabled if database isn't enabled or connected) +CHECK_RANDOMIZER + ## the whitelist #USEWHITELIST @@ -251,6 +261,9 @@ GHOST_INTERACTION ## IRC channel to send direct messages to admins to. Leave blank to disable. #ADMIN_NOTIFY_IRC #paradiseStaff +## IRC channel to log CID randomizer blocker hits to. Leave blank to silence +#CIDRANDOMIZER_IRC #cidrandomizer + ## Path to the python2 executable on the system. Leave blank for default. ## Default is "python" on Windows, "/usr/bin/env python2" on UNIX. #PYTHON_PATH pythonw diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css index 8d00fca2d54..d1669591f82 100644 --- a/goon/browserassets/css/browserOutput.css +++ b/goon/browserassets/css/browserOutput.css @@ -291,6 +291,8 @@ h1.alert, h2.alert {color: #000000;} .alien {color: #543354;} .noticealien {color: #00c000;} .alertalien {color: #00c000; font-weight: bold;} +.terrorspider {color: #320E32;} + .sinister {color: #800080; font-weight: bold; font-style: italic;} /* /vg/ */ .blob {color: #006221; font-weight: bold; font-style: italic;} @@ -320,6 +322,9 @@ h1.alert, h2.alert {color: #000000;} .say_quote {font-family: Georgia, Verdana, sans-serif;} .cult {color: #800080; font-weight: bold; font-style: italic;} .cultspeech {color: #7F0000; font-style: italic;} +.cultitalic {color: #960000; font-style: italic;} +.cultlarge {color: #960000; font-weight: bold; font-size: 3;} +.narsie {color: #960000; font-weight: bold; font-size: 15;} .interface {color: #330033;} .big {font-size: 150%;} .reallybig {font-size: 175%;} diff --git a/html/changelog.html b/html/changelog.html index 5e5007eae87..ad5adf00e12 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,74 @@ -->
+

06 January 2017

+

Crazylemon64 updated:

+
    +
  • pAI UIs no longer break
  • +
  • The chem dispenser's UI now displays the remaining energy again
  • +
+

Kyep updated:

+
    +
  • Mobs in vents no longer see vents/scrubbers as unwelded when they are welded, and vice versa.
  • +
+ +

03 January 2017

+

KasparoVy updated:

+
    +
  • The Vulpkanin Anita hairstyle no longer has rogue extra-bright pixels.
  • +
+

Kyep updated:

+
    +
  • Added tracking for how much playtime each player has.
  • +
  • Added the ability to lock jobs based on playtime. E.g: must play for 10 hours to unlock HoS.
  • +
+ +

02 January 2017

+

KasparoVy updated:

+
    +
  • Particle Accelerators ordered from Cargo can now function.
  • +
  • Wrenching powerless machines in a powered area will no longer require you to toggle the lights (or whatever you did before to sort this).
  • +
+

Krausus updated:

+
    +
  • The syndicate nuke and pinpointer locker will once again spawn into their ship, rather than into space near the station.
  • +
+

Kyep updated:

+
    +
  • Terror Spiders can no longer create more than one web on a tile.
  • +
+ +

01 January 2017

+

Kyep updated:

+
    +
  • Added basic, AI-less versions of some Terror Spiders.
  • +
+ +

31 December 2016

+

Crazylemon64 updated:

+
    +
  • The home gateway now will send ghosts to the other end by default, now
  • +
+ +

30 December 2016

+

Crazylemon updated:

+
    +
  • The shuttle manipulator can now only be used by admins
  • +
+

FalseIncarnate updated:

+
    +
  • Adds Nano-Mob Hunter GO! PDA game cartridges and related stuff. Grab a cartridge from the cartridge vendor or loadout and join in on the hunt!
  • +
  • Adds Nano-Mob Hunter GO! Battle Terminals to the Holodeck and a Nano-Mob Hunter GO! Restoration Terminal to medbay's lobby.
  • +
+

Fox McCloud updated:

+
    +
  • Fixes cyborg cryo oddities
  • +
+

KasparoVy updated:

+
    +
  • Taking off noir glasses while noir mode is on will now give you your colour vision back.
  • +
+

29 December 2016

Fethas updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index fff174d9e41..2e2a987390e 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -3222,3 +3222,46 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - tweak: The camera console has been refactored so there's no longer a delay when switching cameras. - bugfix: The camera console should no longer lag for several seconds. +2016-12-30: + Crazylemon: + - bugfix: The shuttle manipulator can now only be used by admins + FalseIncarnate: + - rscadd: Adds Nano-Mob Hunter GO! PDA game cartridges and related stuff. Grab a + cartridge from the cartridge vendor or loadout and join in on the hunt! + - rscadd: Adds Nano-Mob Hunter GO! Battle Terminals to the Holodeck and a Nano-Mob + Hunter GO! Restoration Terminal to medbay's lobby. + Fox McCloud: + - bugfix: Fixes cyborg cryo oddities + KasparoVy: + - bugfix: Taking off noir glasses while noir mode is on will now give you your colour + vision back. +2016-12-31: + Crazylemon64: + - bugfix: The home gateway now will send ghosts to the other end by default, now +2017-01-01: + Kyep: + - rscadd: Added basic, AI-less versions of some Terror Spiders. +2017-01-02: + KasparoVy: + - bugfix: Particle Accelerators ordered from Cargo can now function. + - bugfix: Wrenching powerless machines in a powered area will no longer require + you to toggle the lights (or whatever you did before to sort this). + Krausus: + - bugfix: The syndicate nuke and pinpointer locker will once again spawn into their + ship, rather than into space near the station. + Kyep: + - bugfix: Terror Spiders can no longer create more than one web on a tile. +2017-01-03: + KasparoVy: + - bugfix: The Vulpkanin Anita hairstyle no longer has rogue extra-bright pixels. + Kyep: + - rscadd: Added tracking for how much playtime each player has. + - rscadd: 'Added the ability to lock jobs based on playtime. E.g: must play for + 10 hours to unlock HoS.' +2017-01-06: + Crazylemon64: + - bugfix: pAI UIs no longer break + - bugfix: The chem dispenser's UI now displays the remaining energy again + Kyep: + - bugfix: Mobs in vents no longer see vents/scrubbers as unwelded when they are + welded, and vice versa. diff --git a/html/changelogs/AutoChangeLog-pr-4392.yml b/html/changelogs/AutoChangeLog-pr-4392.yml new file mode 100644 index 00000000000..9202b4256f7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4392.yml @@ -0,0 +1,5 @@ +author: "Fethas" +delete-after: True +changes: + - rscadd: "ports parts TG neo-oldcult +rscadd:Ports parts of cult from VG" diff --git a/html/changelogs/AutoChangeLog-pr-6053.yml b/html/changelogs/AutoChangeLog-pr-6053.yml new file mode 100644 index 00000000000..7e3d32275c8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6053.yml @@ -0,0 +1,4 @@ +author: "Crazylemon64" +delete-after: True +changes: + - bugfix: "Shuttles no longer make buckling useless" diff --git a/html/changelogs/AutoChangeLog-pr-6064.yml b/html/changelogs/AutoChangeLog-pr-6064.yml new file mode 100644 index 00000000000..bd8b2386e35 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6064.yml @@ -0,0 +1,4 @@ +author: "Krausus" +delete-after: True +changes: + - bugfix: "SDQL2 can now directly manipulate clients." diff --git a/html/changelogs/AutoChangeLog-pr-6065.yml b/html/changelogs/AutoChangeLog-pr-6065.yml new file mode 100644 index 00000000000..d4f9dfcfd61 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6065.yml @@ -0,0 +1,4 @@ +author: "Crazylemon64" +delete-after: True +changes: + - bugfix: "You should no longer go mute randomly" diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi index 003e142eebe..01729aa70af 100644 Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 8e7ea6571d4..2551e6b1849 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/effects/mob_hunt.dmi b/icons/effects/mob_hunt.dmi new file mode 100644 index 00000000000..1eea83a9afa Binary files /dev/null and b/icons/effects/mob_hunt.dmi differ diff --git a/icons/effects/uristrunes.dmi b/icons/effects/uristrunes.dmi index e3d0afa06e5..e9675c48a90 100644 Binary files a/icons/effects/uristrunes.dmi and b/icons/effects/uristrunes.dmi differ diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi index a745dd9f1f3..325d886af8a 100644 Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ diff --git a/icons/mob/eyes.dmi b/icons/mob/eyes.dmi index 9d8462c03c5..f74ebda9d34 100644 Binary files a/icons/mob/eyes.dmi and b/icons/mob/eyes.dmi differ diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index bf6507c412c..c61955bf778 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index 491349985d4..fd305492464 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ diff --git a/icons/mob/screen_construct.dmi b/icons/mob/screen_construct.dmi new file mode 100644 index 00000000000..67a37ccd738 Binary files /dev/null and b/icons/mob/screen_construct.dmi differ diff --git a/icons/mob/species/vox/eyes.dmi b/icons/mob/species/vox/eyes.dmi index e1345302358..99ee47ac1fa 100644 Binary files a/icons/mob/species/vox/eyes.dmi and b/icons/mob/species/vox/eyes.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index 31be4923470..de27e629ee8 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/mob/terrorspider.dmi b/icons/mob/terrorspider.dmi new file mode 100644 index 00000000000..a5d678f3f38 Binary files /dev/null and b/icons/mob/terrorspider.dmi differ diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi index 00588161a65..4799f8736d2 100644 Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi index 0fc42d7bd4d..938d810a612 100644 Binary files a/icons/obj/clothing/glasses.dmi and b/icons/obj/clothing/glasses.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index e45908cb152..2016309aaff 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/computer.dmi b/icons/obj/computer.dmi index 09380373db8..9ad68e22072 100644 Binary files a/icons/obj/computer.dmi and b/icons/obj/computer.dmi differ diff --git a/icons/obj/cult.dmi b/icons/obj/cult.dmi index 768d22193c2..6901e1c25a2 100644 Binary files a/icons/obj/cult.dmi and b/icons/obj/cult.dmi differ diff --git a/icons/obj/doors/Doorcultruned.dmi b/icons/obj/doors/Doorcultruned.dmi new file mode 100644 index 00000000000..f9f4aa92466 Binary files /dev/null and b/icons/obj/doors/Doorcultruned.dmi differ diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi index d0c6f7591ac..0d503c324e3 100644 Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ diff --git a/icons/obj/narsie.dmi b/icons/obj/narsie.dmi index b367734cff5..ac11a2730cb 100644 Binary files a/icons/obj/narsie.dmi and b/icons/obj/narsie.dmi differ diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi index 76457e6049a..680c93f360f 100644 Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ diff --git a/icons/obj/wizard.dmi b/icons/obj/wizard.dmi index 14c227f8251..8cf3b48100c 100644 Binary files a/icons/obj/wizard.dmi and b/icons/obj/wizard.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index 581b345b5ec..01e97eec587 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/icons/turf/walls/cult_wall.dmi b/icons/turf/walls/cult_wall.dmi index 5239f7b1e06..052b3f4f8cd 100644 Binary files a/icons/turf/walls/cult_wall.dmi and b/icons/turf/walls/cult_wall.dmi differ diff --git a/interface/skin.dmf b/interface/skin.dmf index eef051bcc53..6a6d616832f 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -1374,7 +1374,7 @@ menu "menu" group = "" is-disabled = false saved-params = "is-checked" - elem + elem "reconnectbutton" name = "&Reconnect" command = ".reconnect" category = "&File" diff --git a/nano/assets/nanoui.css b/nano/assets/nanoui.css index d8746687b44..d91a6ece4ae 100644 --- a/nano/assets/nanoui.css +++ b/nano/assets/nanoui.css @@ -1,2 +1,2 @@ -@font-face{font-family:FontAwesome;src:url(fontawesome-webfont.eot?v=4.5.0);src:url(fontawesome-webfont.eot?#iefix&v=4.5.0) format("embedded-opentype"),url(fontawesome-webfont.woff2?v=4.5.0) format("woff2"),url(fontawesome-webfont.woff?v=4.5.0) format("woff"),url(fontawesome-webfont.ttf?v=4.5.0) format("truetype"),url(fontawesome-webfont.svg?v=4.5.0#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:a 2s infinite linear;animation:a 2s infinite linear}.fa-pulse{-webkit-animation:a 1s infinite steps(8);animation:a 1s infinite steps(8)}@-webkit-keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0,mirror=1);-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2,mirror=1);-webkit-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-close:before,.fa-remove:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-repeat:before,.fa-rotate-right:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-exclamation-triangle:before,.fa-warning:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-floppy-o:before,.fa-save:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-bolt:before,.fa-flash:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-chain-broken:before,.fa-unlink:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\f150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\f151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\f152"}.fa-eur:before,.fa-euro:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-inr:before,.fa-rupee:before{content:"\f156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\f158"}.fa-krw:before,.fa-won:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-try:before,.fa-turkish-lira:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\f19c"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\f1c5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\f1c6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-empire:before,.fa-ge:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-paper-plane:before,.fa-send:before{content:"\f1d8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-bed:before,.fa-hotel:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-y-combinator:before,.fa-yc:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-television:before,.fa-tv:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"} -.displayBar{position:relative;width:236px;height:16px;border:1px solid #666;float:left;margin:0 5px 0 0;overflow:hidden;background:#000}.displayBarText{position:absolute;top:-2px;left:5px;width:100%;height:100%;color:#fff;font-weight:400}.displayBarFill{width:0;height:100%;background:#40628a;overflow:hidden;float:left}.displayBarFill.alignRight{float:right}.displayBarFill.good{color:#fff;background:#4f7529}.displayBarFill.notgood{color:#fff;background:#ffb400}.displayBarFill.average{color:#fff;background:#cd6500}.displayBarFill.bad{color:#fff;background:#e00}.displayBarFill.highlight{color:#fff;background:#8ba5c4}.disabled,.link,.linkOff,.linkOn,.redButton,.selected,.yellowButton{float:left;min-width:15px;height:16px;text-align:center;color:#fff;text-decoration:none;background:#40628a;border:1px solid #161616;padding:0 4px 4px;margin:0 2px 2px 0;cursor:default;white-space:nowrap}.hasIcon{padding:0 4px 4px 0}.linkActive.hover,.zoomLink.hover,a.hover{background:#507aac}@keyframes a{to{color:#fff;background:#507aac}}.linkPending,.linkPending.hover{animation-name:a;animation-duration:.25s}a.white,a.white:active,a.white:link,a.white:visited{color:#40628a;text-decoration:none;background:#fff;border:1px solid #161616;padding:1px 4px;margin:0 2px 0 0;cursor:default}a.white.hover{color:#fff;background:#40628a}.linkOn,.selected,a.linkOn.hover,a.linkOn:active,a.linkOn:link,a.linkOn:visited,a.selected.hover,a.selected:active,a.selected:link,a.selected:visited{color:#fff;background:#2f943c}.disabled,.linkOff,a.disabled.hover,a.disabled:active,a.disabled:link,a.disabled:visited,a.linkOff.hover,a.linkOff:active,a.linkOff:link,a.linkOff:visited{color:#fff;background:#999;border-color:#666}.disabled.icon,.linkOff.icon,.linkOn.icon,.selected.icon,a.icon{position:relative;padding:1px 4px 2px 20px}.disabled.icon img,.linkOff.icon img,.linkOn.icon img,.selected.icon img,a.icon img{position:absolute;top:0;left:0;width:18px;height:18px}.linkDanger,a.linkDanger:active,a.linkDanger:link,a.linkDanger:visited{color:#fff;background-color:red;border-color:#a00}.linkDanger.hover{background-color:#f66}.inactive,a.inactive.hover,a.inactive:active,a.inactive:link,a.inactive:visited{color:#fff;background:#999;border-color:#666}.white{color:#fff}.good,.white{font-weight:700}.good{color:#4f7529}.average{color:#cd6500}.average,.bad{font-weight:700}.bad{color:#e00}.idle{color:#272727;font-weight:700}.redButton{background:#ea0000}.yellowButton{background:#cacc00}.highlight{color:#8ba5c4}.dark{color:#272727}.burn{color:orange}.brute{color:red}.toxin{color:green}.toxin_light{color:#3adf00}.oxyloss{color:blue}.oxyloss_light{color:#6698ff}.Red{color:red}.Blue{color:#00f}.Green{color:#0f0}.Marigold{color:#fda505}.Fuschia{color:#ff0080}.Black{color:#000}.Pearl{color:#c6cacb}.cold1{color:#94b8ff}.cold2{color:#69f}.cold3{color:#293d66}.hot1{color:#f96}.hot2{color:#993d00}.hot3{color:#f60}.itemGroup{border:1px solid #e9c183;background:#2c2c2c;padding:4px;clear:both}.item{width:100%;margin:4px 0 0;clear:both;overflow:auto}.itemContent,.itemContentNarrow{float:left}.itemContentNarrow{width:30%}.itemContent{width:69%}.itemLabel,.itemLabelNarrow,.itemLabelWide,.itemLabelWider,.itemLabelWidest{float:left;color:#e9c183}.itemLabelNarrow{width:20%}.itemLabel{width:30%}.itemLabelWide{width:45%}.itemLabelWider{width:69%}.itemLabelWidest{width:100%}.itemContentWide{float:left;width:79%}.itemContentSmall{float:left;width:33%}.itemContentMedium{float:left;width:55%}.block{padding:8px;margin:10px 4px 4px;border:1px solid #40628a;background-color:#202020}.block h3{padding:0}.clearBoth{clear:both}.clearLeft{clear:left}.clearRight{clear:right}.line{width:100%;clear:both}.fixedLeft{width:110px;float:left}.fixedLeftWide{width:165px;float:left}.fixedLeftWider{width:220px;float:left}.fixedLeftWidest{width:250px;float:left}.floatRight{float:right}.floatLeft{float:left}.hidden{display:none}.statusDisplay{overflow:hidden}.statusDisplay,.statusDisplayRecords{background:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background:rgba(0,0,0,.5);color:#fff;border:1px solid #40628a;padding:4px;margin:3px 0}.statusDisplayRecords{overflow-x:hidden;overflow-y:auto}.statusLabel{width:138px;float:left;overflow:hidden;color:#98b0c3}.statusValue{float:left}.fancy{display:none}.minimize{color:#e9c183;position:absolute;top:6px;right:46px}.minimize.hover{color:#b8c9d6}.close{color:#e9c183;position:absolute;top:4px;right:12px}.close.hover{color:#b8c9d6}div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 30px 30px;border-color:transparent transparent #363636;transform:rotate(1turn)}.uiLinkPendingIcon{display:none;float:left;width:16px;height:16px;margin:2px 2px 0;background-image:url(uiLinkPendingIcon.gif)}.linkPending .fa{display:none}.linkPending .uiLinkPendingIcon{display:block}.mapIcon16{position:absolute;width:16px;height:16px;background-image:url(uiIcons16Green.png);background-position:-144px -96px;background-repeat:no-repeat;zoom:.125;margin-left:-1px}.mapIcon16.bad,.mapIcon16.dead{background-image:url(uiIcons16Red.png)}.mapIcon16.average{background-image:url(uiIcons16Orange.png)}.mapIcon16.good{background-image:url(uiIcons16Green.png)}.mapIcon16.icon-airalarm{background-position:0 -144px}.mapIcon16.rank-captain{background-position:-224px -112px}.mapIcon16.rank-headofpersonnel{background-position:-112px -96px}.mapIcon16.rank-headofsecurity{background-position:-112px -128px}.mapIcon16.rank-chiefengineer{background-position:-176px -112px}.mapIcon16.rank-researchdirector{background-position:-128px -128px}.mapIcon16.rank-chiefmedicalofficer{background-position:-32px -128px}.mapIcon16.rank-atmospherictechnician,.mapIcon16.rank-stationengineer{background-position:-176px -112px}.mapIcon16.rank-chemist,.mapIcon16.rank-geneticist,.mapIcon16.rank-medicaldoctor,.mapIcon16.rank-psychiatrist{background-position:-32px -128px}.mapIcon16.rank-geneticist,.mapIcon16.rank-roboticist,.mapIcon16.rank-scientist,.mapIcon16.rank-xenobiologist{background-position:-128px -128px}.mapIcon16.rank-detective,.mapIcon16.rank-securityofficer,.mapIcon16.rank-warden{background-position:-112px -128px}ul{padding:4px 0 0 10px;margin:0;list-style-type:none}li{padding:0 0 2px}table.fixed{table-layout:fixed}table.fixed td{overflow:hidden}table.pmon{border:2px solid #4169e1}table.pmon td,table.pmon th{border-bottom:1px dotted #000;padding:0 5px}th.command{background:#33f}th.command,th.sec{font-weight:700;color:#fff}th.sec{background:#8e0000}th.med{background:#060}th.eng,th.med{font-weight:700;color:#fff}th.eng{background:#b27300}th.sci{background:#a65ba6}th.sci,th.ser{font-weight:700;color:#fff}th.ser{background:#7100aa}th.sup{background:#666621}th.civ,th.sup{font-weight:700;color:#fff}th.civ{background:#a32800}th.misc{background:#666;font-weight:700;color:#fff}span.qm-job{color:#b77a41;font-weight:700}.striped:not(table)>:nth-child(even),.striped tr:nth-child(even){background-color:#404040}#uiNoScript{position:fixed;top:50%;left:50%;margin:-60px 0 0 -150px;width:280px;height:120px;background:#fff;border:2px solid red;color:#000;font-size:10px;font-weight:700;z-index:1;padding:0 10px;text-align:center}.notice{background:url(uiNoticeBackground.jpg) 50% 50%;color:#000}.notice,.noticePlaceholder{position:relative;font-size:12px;font-style:italic;font-weight:700;padding:3px 4px;margin:4px 0}.notice.icon{padding:2px 4px 0 20px}.notice img{position:absolute;top:0;left:0;width:16px;height:16px}div.notice{clear:both}.wholeScreen{position:absolute;color:#517087;font-size:16px;font-weight:700;text-align:center}.pdalink{float:left;white-space:nowrap;cursor:default!important}.pdalink.disabled{background:none;border:none;color:#999;text-align:left}.pdanote{color:#cd6500;font-weight:700}.item.mainmenu{padding-bottom:.5em}div.clock{color:#fff;font-weight:700;float:right;padding-right:2em}#pdaFooter{position:fixed;left:0;bottom:0;width:100%;background:#272727}.pdaFooterButton{width:33%;padding:.5em 0;font-size:200%;border:none;background:none;color:#fff}.pdaFooterButton.hover{background:#507aac}.pdaFooterButton.disabled{background:none!important;color:#555!important}.pdaFooterButton .uiLinkPendingIcon{position:absolute;width:33%;background-repeat:no-repeat;background-position:50%}.dnaBlock{float:left;width:90px;padding:0 0 5px}.dnaBlockNumber{color:#fff;background:#363636;min-width:20px}.dnaBlockNumber,.dnaSubBlock{font-family:Fixed,monospace;float:left;height:20px;padding:0;text-align:center}.dnaSubBlock{min-width:16px}.mask{position:fixed;left:0;top:0;width:100%;height:100%;background:url(uiMaskBackground.png)}.maskContent{width:100%;height:200px;margin:200px 0;text-align:center}body{background:#272727;color:#fff;font-family:Verdana,Geneva,sans-serif;font-size:12px;line-height:170%;margin:0;padding:0}hr{background-color:#40628a;height:1px;border:none}a img,img{border-style:none}h1,h2,h3,h4,h5,h6{margin:0;padding:12px 0 6px;color:#fff;clear:both}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1' viewBox='0 0 425 200' opacity='.25'%3E%3Cpath d='M178.004.039H106.8a6.761 6.026 0 0 0-6.761 6.025v187.872a6.761 6.026 0 0 0 6.761 6.025h53.107a6.761 6.026 0 0 0 6.762-6.025V92.392l72.216 104.7a6.761 6.026 0 0 0 5.76 2.87H318.2a6.761 6.026 0 0 0 6.761-6.026V6.064A6.761 6.026 0 0 0 318.2.04h-54.717a6.761 6.026 0 0 0-6.76 6.025v102.62L183.763 2.909a6.761 6.026 0 0 0-5.76-2.87zM4.845 22.109A13.412 12.502 0 0 1 13.478.039h66.118A5.365 5 0 0 1 84.96 5.04v79.88zM420.155 177.891a13.412 12.502 0 0 1-8.633 22.07h-66.118a5.365 5 0 0 1-5.365-5.001v-79.88z'/%3E%3C/svg%3E") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020) no-repeat fixed 50%/100% 100%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}#uiWrapper{width:100%;height:100%;-ms-user-select:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}#uiTitleWrapper{position:relative;height:30px}#uiTitleText{position:absolute;top:6px;left:44px;width:66%;overflow:hidden;color:#e9c183;font-size:16px}#uiTitle.icon{padding:6px 8px 6px 42px;background-position:2px 50%;background-repeat:no-repeat}#uiTitleFluff{position:absolute;top:4px;right:12px;width:42px;height:24px;background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1' viewBox='0 0 425 200' opacity='.25'%3E%3Cpath d='M178.004.039H106.8a6.761 6.026 0 0 0-6.761 6.025v187.872a6.761 6.026 0 0 0 6.761 6.025h53.107a6.761 6.026 0 0 0 6.762-6.025V92.392l72.216 104.7a6.761 6.026 0 0 0 5.76 2.87H318.2a6.761 6.026 0 0 0 6.761-6.026V6.064A6.761 6.026 0 0 0 318.2.04h-54.717a6.761 6.026 0 0 0-6.76 6.025v102.62L183.763 2.909a6.761 6.026 0 0 0-5.76-2.87zM4.845 22.109A13.412 12.502 0 0 1 13.478.039h66.118A5.365 5 0 0 1 84.96 5.04v79.88zM420.155 177.891a13.412 12.502 0 0 1-8.633 22.07h-66.118a5.365 5 0 0 1-5.365-5.001v-79.88z'/%3E%3C/svg%3E") 50% 50% no-repeat}.statusicon{position:absolute;top:4px;left:12px}#uiMapWrapper{clear:both;padding:8px}#uiMapHeader{position:relative;clear:both}#uiMapContainer{position:relative;width:100%;height:600px;overflow:hidden;border:1px solid #40628a;background:url(nanomapBackground.png)}#uiMap{top:50%;left:50%;margin:-512px 0 0 -512px;overflow:hidden;zoom:4}#uiMap,#uiMapImage{position:absolute;width:256px;height:256px}#uiMapImage{bottom:1px;left:1px}#uiMapContent{position:absolute;bottom:-13.5px;left:0;width:256px;height:256px}#uiMapFooter{position:relative;clear:both}#uiContent{clear:both;padding:8px}#uiMapTooltip{position:absolute;right:10px;top:10px;border:1px solid #40628a;background-color:#272727;padding:8px;display:none;z-index:1}#uiLoadingNotice{position:relative;background:url(uiNoticeBackground.jpg) 50% 50%;color:#000;font-size:14px;font-style:italic;font-weight:700;padding:3px 4px;margin:4px 0} \ No newline at end of file +@font-face{font-family:FontAwesome;src:url(fontawesome-webfont.eot?v=4.5.0);src:url(fontawesome-webfont.eot?#iefix&v=4.5.0) format('embedded-opentype'),url(fontawesome-webfont.woff2?v=4.5.0) format('woff2'),url(fontawesome-webfont.woff?v=4.5.0) format('woff'),url(fontawesome-webfont.ttf?v=4.5.0) format('truetype'),url(fontawesome-webfont.svg?v=4.5.0#fontawesomeregular) format('svg');font-weight:400;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:a 2s infinite linear;animation:a 2s infinite linear}.fa-pulse{-webkit-animation:a 1s infinite steps(8);animation:a 1s infinite steps(8)}@-webkit-keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0,mirror=1);-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2,mirror=1);-webkit-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-close:before,.fa-remove:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-repeat:before,.fa-rotate-right:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-exclamation-triangle:before,.fa-warning:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-floppy-o:before,.fa-save:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-bolt:before,.fa-flash:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-chain-broken:before,.fa-unlink:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\f150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\f151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\f152"}.fa-eur:before,.fa-euro:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-inr:before,.fa-rupee:before{content:"\f156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\f158"}.fa-krw:before,.fa-won:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-try:before,.fa-turkish-lira:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\f19c"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\f1c5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\f1c6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-empire:before,.fa-ge:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-paper-plane:before,.fa-send:before{content:"\f1d8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-bed:before,.fa-hotel:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-y-combinator:before,.fa-yc:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-television:before,.fa-tv:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"} +.displayBar{position:relative;width:236px;height:16px;border:1px solid #666;float:left;margin:0 5px 0 0;overflow:hidden;background:#000}.displayBarText{position:absolute;top:-2px;left:5px;width:100%;height:100%;color:#fff;font-weight:400}.displayBarFill{width:0;height:100%;background:#40628a;overflow:hidden;float:left}.displayBarFill.alignRight{float:right}.displayBarText.average,.displayBarText.bad,.displayBarText.good,.displayBarText.notgood{color:#fff}.displayBarText.highlight{color:#000}.displayBarFill.good{color:#fff;background:#4f7529}.displayBarFill.notgood{color:#fff;background:#ffb400}.displayBarFill.average{color:#fff;background:#cd6500}.displayBarFill.bad{color:#fff;background:#e00}.displayBarFill.highlight{color:#fff;background:#8ba5c4}.disabled,.link,.linkOff,.linkOn,.redButton,.selected,.yellowButton{float:left;min-width:15px;height:16px;text-align:center;color:#fff;text-decoration:none;background:#40628a;border:1px solid #161616;padding:0 4px 4px;margin:0 2px 2px 0;cursor:default;white-space:nowrap}.hasIcon{padding:0 4px 4px 0}.linkActive.hover,.zoomLink.hover,a.hover{background:#507aac}@keyframes a{to{color:#fff;background:#507aac}}.linkPending,.linkPending.hover{animation-name:a;animation-duration:.25s}a.white,a.white:active,a.white:link,a.white:visited{color:#40628a;text-decoration:none;background:#fff;border:1px solid #161616;padding:1px 4px;margin:0 2px 0 0;cursor:default}a.white.hover{color:#fff;background:#40628a}.linkOn,.selected,a.linkOn.hover,a.linkOn:active,a.linkOn:link,a.linkOn:visited,a.selected.hover,a.selected:active,a.selected:link,a.selected:visited{color:#fff;background:#2f943c}.disabled,.linkOff,a.disabled.hover,a.disabled:active,a.disabled:link,a.disabled:visited,a.linkOff.hover,a.linkOff:active,a.linkOff:link,a.linkOff:visited{color:#fff;background:#999;border-color:#666}.disabled.icon,.linkOff.icon,.linkOn.icon,.selected.icon,a.icon{position:relative;padding:1px 4px 2px 20px}.disabled.icon img,.linkOff.icon img,.linkOn.icon img,.selected.icon img,a.icon img{position:absolute;top:0;left:0;width:18px;height:18px}.linkDanger,a.linkDanger:active,a.linkDanger:link,a.linkDanger:visited{color:#fff;background-color:red;border-color:#a00}.linkDanger.hover{background-color:#f66}.inactive,a.inactive.hover,a.inactive:active,a.inactive:link,a.inactive:visited{color:#fff;background:#999;border-color:#666}.white{color:#fff}.good,.white{font-weight:700}.good{color:#4f7529}.average{color:#cd6500}.average,.bad{font-weight:700}.bad{color:#e00}.idle{color:#272727;font-weight:700}.redButton{background:#ea0000}.yellowButton{background:#cacc00}.highlight{color:#8ba5c4}.dark{color:#272727}.burn{color:orange}.brute{color:red}.toxin{color:green}.toxin_light{color:#3adf00}.oxyloss{color:blue}.oxyloss_light{color:#6698ff}.Red{color:red}.Blue{color:#00f}.Green{color:#0f0}.Marigold{color:#fda505}.Fuschia{color:#ff0080}.Black{color:#000}.Pearl{color:#c6cacb}.cold1{color:#94b8ff}.cold2{color:#69f}.cold3{color:#293d66}.hot1{color:#f96}.hot2{color:#993d00}.hot3{color:#f60}.itemGroup{border:1px solid #e9c183;background:#2c2c2c;padding:4px;clear:both}.item{width:100%;margin:4px 0 0;clear:both;overflow:auto}.itemContent,.itemContentNarrow{float:left}.itemContentNarrow{width:30%}.itemContent{width:69%}.itemLabel,.itemLabelNarrow,.itemLabelWide,.itemLabelWider,.itemLabelWidest{float:left;color:#e9c183}.itemLabelNarrow{width:20%}.itemLabel{width:30%}.itemLabelWide{width:45%}.itemLabelWider{width:69%}.itemLabelWidest{width:100%}.itemContentWide{float:left;width:79%}.itemContentSmall{float:left;width:33%}.itemContentMedium{float:left;width:55%}.block{padding:8px;margin:10px 4px 4px;border:1px solid #40628a;background-color:#202020}.block h3{padding:0}.clearBoth{clear:both}.clearLeft{clear:left}.clearRight{clear:right}.line{width:100%;clear:both}.fixedLeft{width:110px;float:left}.fixedLeftWide{width:165px;float:left}.fixedLeftWider{width:220px;float:left}.fixedLeftWidest{width:250px;float:left}.floatRight{float:right}.floatLeft{float:left}.hidden{display:none}.statusDisplay{overflow:hidden}.statusDisplay,.statusDisplayRecords{background:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background:rgba(0,0,0,.5);color:#fff;border:1px solid #40628a;padding:4px;margin:3px 0}.statusDisplayRecords{overflow-x:hidden;overflow-y:auto}.statusLabel{width:138px;float:left;overflow:hidden;color:#98b0c3}.statusValue{float:left}.fancy{display:none}.minimize{color:#e9c183;position:absolute;top:6px;right:46px}.minimize.hover{color:#b8c9d6}.close{color:#e9c183;position:absolute;top:4px;right:12px}.close.hover{color:#b8c9d6}div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 30px 30px;border-color:transparent transparent #363636;transform:rotate(1turn)}.uiLinkPendingIcon{display:none;float:left;width:16px;height:16px;margin:2px 2px 0;background-image:url(uiLinkPendingIcon.gif)}.linkPending .fa{display:none}.linkPending .uiLinkPendingIcon{display:block}.mapIcon16{position:absolute;width:16px;height:16px;background-image:url(uiIcons16Green.png);background-position:-144px -96px;background-repeat:no-repeat;zoom:.125;margin-left:-1px}.mapIcon16.bad,.mapIcon16.dead{background-image:url(uiIcons16Red.png)}.mapIcon16.average{background-image:url(uiIcons16Orange.png)}.mapIcon16.good{background-image:url(uiIcons16Green.png)}.mapIcon16.icon-airalarm{background-position:0 -144px}.mapIcon16.rank-captain{background-position:-224px -112px}.mapIcon16.rank-headofpersonnel{background-position:-112px -96px}.mapIcon16.rank-headofsecurity{background-position:-112px -128px}.mapIcon16.rank-chiefengineer{background-position:-176px -112px}.mapIcon16.rank-researchdirector{background-position:-128px -128px}.mapIcon16.rank-chiefmedicalofficer{background-position:-32px -128px}.mapIcon16.rank-atmospherictechnician,.mapIcon16.rank-stationengineer{background-position:-176px -112px}.mapIcon16.rank-chemist,.mapIcon16.rank-geneticist,.mapIcon16.rank-medicaldoctor,.mapIcon16.rank-psychiatrist{background-position:-32px -128px}.mapIcon16.rank-geneticist,.mapIcon16.rank-roboticist,.mapIcon16.rank-scientist,.mapIcon16.rank-xenobiologist{background-position:-128px -128px}.mapIcon16.rank-detective,.mapIcon16.rank-securityofficer,.mapIcon16.rank-warden{background-position:-112px -128px}ul{padding:4px 0 0 10px;margin:0;list-style-type:none}li{padding:0 0 2px}table.fixed{table-layout:fixed}table.fixed td{overflow:hidden}table.pmon{border:2px solid #4169e1}table.pmon td,table.pmon th{border-bottom:1px dotted #000;padding:0 5px}th.command{background:#33f}th.command,th.sec{font-weight:700;color:#fff}th.sec{background:#8e0000}th.med{background:#060}th.eng,th.med{font-weight:700;color:#fff}th.eng{background:#b27300}th.sci{background:#a65ba6}th.sci,th.ser{font-weight:700;color:#fff}th.ser{background:#7100aa}th.sup{background:#666621}th.civ,th.sup{font-weight:700;color:#fff}th.civ{background:#a32800}th.misc{background:#666;font-weight:700;color:#fff}span.qm-job{color:#b77a41;font-weight:700}.striped:not(table)>:nth-child(even),.striped tr:nth-child(even){background-color:#404040}#uiNoScript{position:fixed;top:50%;left:50%;margin:-60px 0 0 -150px;width:280px;height:120px;background:#fff;border:2px solid red;color:#000;font-size:10px;font-weight:700;z-index:1;padding:0 10px;text-align:center}.notice{background:url(uiNoticeBackground.jpg) 50% 50%;color:#000}.notice,.noticePlaceholder{position:relative;font-size:12px;font-style:italic;font-weight:700;padding:3px 4px;margin:4px 0}.notice.icon{padding:2px 4px 0 20px}.notice img{position:absolute;top:0;left:0;width:16px;height:16px}div.notice{clear:both}.wholeScreen{position:absolute;color:#517087;font-size:16px;font-weight:700;text-align:center}.pdalink{float:left;white-space:nowrap;cursor:default!important}.pdalink.disabled{background:none;border:none;color:#999;text-align:left}.pdanote{color:#cd6500;font-weight:700}.item.mainmenu{padding-bottom:.5em}div.clock{color:#fff;font-weight:700;float:right;padding-right:2em}#pdaFooter{position:fixed;left:0;bottom:0;width:100%;background:#272727}.pdaFooterButton{width:33%;padding:.5em 0;font-size:200%;border:none;background:none;color:#fff}.pdaFooterButton.hover{background:#507aac}.pdaFooterButton.disabled{background:none!important;color:#555!important}.pdaFooterButton .uiLinkPendingIcon{position:absolute;width:33%;background-repeat:no-repeat;background-position:50%}.dnaBlock{float:left;width:90px;padding:0 0 5px}.dnaBlockNumber{color:#fff;background:#363636;min-width:20px}.dnaBlockNumber,.dnaSubBlock{font-family:Fixed,monospace;float:left;height:20px;padding:0;text-align:center}.dnaSubBlock{min-width:16px}.mask{position:fixed;left:0;top:0;width:100%;height:100%;background:url(uiMaskBackground.png)}.maskContent{width:100%;height:200px;margin:200px 0;text-align:center}body{background:#272727;color:#fff;font-family:Verdana,Geneva,sans-serif;font-size:12px;line-height:170%;margin:0;padding:0}hr{background-color:#40628a;height:1px;border:none}a img,img{border-style:none}h1,h2,h3,h4,h5,h6{margin:0;padding:12px 0 6px;color:#fff;clear:both}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1' viewBox='0 0 425 200' opacity='.25'%3E%3Cpath d='M178.004.039H106.8a6.761 6.026 0 0 0-6.761 6.025v187.872a6.761 6.026 0 0 0 6.761 6.025h53.107a6.761 6.026 0 0 0 6.762-6.025V92.392l72.216 104.7a6.761 6.026 0 0 0 5.76 2.87H318.2a6.761 6.026 0 0 0 6.761-6.026V6.064A6.761 6.026 0 0 0 318.2.04h-54.717a6.761 6.026 0 0 0-6.76 6.025v102.62L183.763 2.909a6.761 6.026 0 0 0-5.76-2.87zM4.845 22.109A13.412 12.502 0 0 1 13.478.039h66.118A5.365 5 0 0 1 84.96 5.04v79.88zM420.155 177.891a13.412 12.502 0 0 1-8.633 22.07h-66.118a5.365 5 0 0 1-5.365-5.001v-79.88z'/%3E%3C/svg%3E") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020) no-repeat fixed 50%/100% 100%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2a2a2a',endColorstr='#ff202020',GradientType=0)}#uiWrapper{width:100%;height:100%;-ms-user-select:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}#uiTitleWrapper{position:relative;height:30px}#uiTitleText{position:absolute;top:6px;left:44px;width:66%;overflow:hidden;color:#e9c183;font-size:16px}#uiTitle.icon{padding:6px 8px 6px 42px;background-position:2px 50%;background-repeat:no-repeat}#uiTitleFluff{position:absolute;top:4px;right:12px;width:42px;height:24px;background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1' viewBox='0 0 425 200' opacity='.25'%3E%3Cpath d='M178.004.039H106.8a6.761 6.026 0 0 0-6.761 6.025v187.872a6.761 6.026 0 0 0 6.761 6.025h53.107a6.761 6.026 0 0 0 6.762-6.025V92.392l72.216 104.7a6.761 6.026 0 0 0 5.76 2.87H318.2a6.761 6.026 0 0 0 6.761-6.026V6.064A6.761 6.026 0 0 0 318.2.04h-54.717a6.761 6.026 0 0 0-6.76 6.025v102.62L183.763 2.909a6.761 6.026 0 0 0-5.76-2.87zM4.845 22.109A13.412 12.502 0 0 1 13.478.039h66.118A5.365 5 0 0 1 84.96 5.04v79.88zM420.155 177.891a13.412 12.502 0 0 1-8.633 22.07h-66.118a5.365 5 0 0 1-5.365-5.001v-79.88z'/%3E%3C/svg%3E") 50% 50% no-repeat}.statusicon{position:absolute;top:4px;left:12px}#uiMapWrapper{clear:both;padding:8px}#uiMapHeader{position:relative;clear:both}#uiMapContainer{position:relative;width:100%;height:600px;overflow:hidden;border:1px solid #40628a;background:url(nanomapBackground.png)}#uiMap{top:50%;left:50%;margin:-512px 0 0 -512px;overflow:hidden;zoom:4}#uiMap,#uiMapImage{position:absolute;width:256px;height:256px}#uiMapImage{bottom:1px;left:1px}#uiMapContent{position:absolute;bottom:-13.5px;left:0;width:256px;height:256px}#uiMapFooter{position:relative;clear:both}#uiContent{clear:both;padding:8px}#uiMapTooltip{position:absolute;right:10px;top:10px;border:1px solid #40628a;background-color:#272727;padding:8px;display:none;z-index:1}#uiLoadingNotice{position:relative;background:url(uiNoticeBackground.jpg) 50% 50%;color:#000;font-size:14px;font-style:italic;font-weight:700;padding:3px 4px;margin:4px 0} \ No newline at end of file diff --git a/nano/styles/_bars.less b/nano/styles/_bars.less index f154274f596..90eb3557144 100644 --- a/nano/styles/_bars.less +++ b/nano/styles/_bars.less @@ -31,6 +31,26 @@ float: right; } +.displayBarText.good { + color: white; +} + +.displayBarText.notgood { + color: white; +} + +.displayBarText.average { + color: white; +} + +.displayBarText.bad { + color: white; +} + +.displayBarText.highlight { + color: black; +} + .displayBarFill.good { color: #ffffff; background: @good-color; @@ -54,4 +74,4 @@ .displayBarFill.highlight { color: #ffffff; background: @highlight-color; -} \ No newline at end of file +} diff --git a/nano/templates/comm_console.tmpl b/nano/templates/comm_console.tmpl index 6d566aa85fb..c4e1799afcf 100644 --- a/nano/templates/comm_console.tmpl +++ b/nano/templates/comm_console.tmpl @@ -68,6 +68,9 @@ Used In File(s): /code/game/machinery/computers/communications.dm
    {{:helper.link('Message List','comment',{'operation':'messagelist'})}}
    +
    + {{:helper.link('Restart Nano-Mob Hunter GO! Server','power-off',{'operation':'RestartNanoMob'})}} +
    {{if data.dock_request}}
    {{:helper.link('Accept Docking Request','signal',{'operation':'AcceptDocking'})}} diff --git a/nano/templates/pda_mob_hunt.tmpl b/nano/templates/pda_mob_hunt.tmpl new file mode 100644 index 00000000000..dde4ab82a5c --- /dev/null +++ b/nano/templates/pda_mob_hunt.tmpl @@ -0,0 +1,91 @@ +
    +
    + + + + {{if data.connected}} + + + {{else}} + + + {{/if}} + +
    + Connection Status: + + Connected + + {{:helper.link('Disconnect', 'sign-out', {'choice': 'Disconnect'})}} + + No Connection + + {{:helper.link('Connect', 'sign-in', {'choice': 'Reconnect'})}} +
    +
    +
    +
    +
    My Collection:
    +{{if data.no_collection}} +
    +
    + Your collection is empty! Go capture some Nano-Mobs! +
    +
    +
    + Wild mobs captured: {{:data.wild_captures}} +{{else}} +
    +
    +
    + {{if data.entry}} + {{if data.entry.nickname}} + Name: {{:data.entry.nickname}}
    + {{/if}} + Species: {{:data.entry.real_name}}
    + Level: {{:data.entry.level}}
    + Primary Type: {{:data.entry.type1}}
    + {{if data.entry.type2}} + Secondary Type: {{:data.entry.type2}}
    + {{/if}} + {{if data.entry.sprite}} + + {{else}} + Mob Image Missing! + {{/if}} + {{else}} + + Mob Data Missing!

    +
    + {{/if}} +
    +
    +
    +
    + Wild mobs captured: {{:data.wild_captures}} +
    + + + + + + + + +
    + {{:helper.link('Previous Mob', 'arrow-left', {'choice': 'Prev'})}} + + {{:helper.link('Transfer Mob', 'exchange', {'choice': 'Transfer'})}} + + {{:helper.link('Rename Mob', 'pencil', {'choice': 'Rename'})}} + + {{:helper.link('Release Mob', 'tree', {'choice': 'Release'})}} + + {{:helper.link('Next Mob', 'arrow-right', {'choice': 'Next'})}} +
    + {{if data.entry.is_hacked}} +
    + {{:helper.link('Set Trap', 'bolt', {'choice': 'Set_Trap'})}} + {{/if}} +
    +{{/if}} \ No newline at end of file diff --git a/paradise.dme b/paradise.dme index 45730ee2d01..e7698d5eeed 100644 --- a/paradise.dme +++ b/paradise.dme @@ -107,6 +107,7 @@ #include "code\_onclick\hud\alien.dm" #include "code\_onclick\hud\alien_larva.dm" #include "code\_onclick\hud\bot.dm" +#include "code\_onclick\hud\constructs.dm" #include "code\_onclick\hud\fullscreen.dm" #include "code\_onclick\hud\guardian.dm" #include "code\_onclick\hud\hud.dm" @@ -176,6 +177,7 @@ #include "code\controllers\Processes\lighting.dm" #include "code\controllers\Processes\machinery.dm" #include "code\controllers\Processes\mob.dm" +#include "code\controllers\Processes\nano_mob_hunter.dm" #include "code\controllers\Processes\nanoui.dm" #include "code\controllers\Processes\npcai.dm" #include "code\controllers\Processes\npcpool.dm" @@ -407,7 +409,10 @@ #include "code\game\gamemodes\changeling\powers\tiny_prick.dm" #include "code\game\gamemodes\changeling\powers\transform.dm" #include "code\game\gamemodes\cult\cult.dm" +#include "code\game\gamemodes\cult\cult_comms.dm" +#include "code\game\gamemodes\cult\cult_datums.dm" #include "code\game\gamemodes\cult\cult_items.dm" +#include "code\game\gamemodes\cult\cult_objectives.dm" #include "code\game\gamemodes\cult\cult_structures.dm" #include "code\game\gamemodes\cult\ritual.dm" #include "code\game\gamemodes\cult\runes.dm" @@ -464,6 +469,7 @@ #include "code\game\gamemodes\wizard\wizard.dm" #include "code\game\jobs\access.dm" #include "code\game\jobs\job_controller.dm" +#include "code\game\jobs\job_exp.dm" #include "code\game\jobs\job_objective.dm" #include "code\game\jobs\jobs.dm" #include "code\game\jobs\whitelist.dm" @@ -1056,6 +1062,11 @@ #include "code\modules\arcade\claw_game.dm" #include "code\modules\arcade\prize_counter.dm" #include "code\modules\arcade\prize_datums.dm" +#include "code\modules\arcade\mob_hunt\battle_computer.dm" +#include "code\modules\arcade\mob_hunt\mob_avatar.dm" +#include "code\modules\arcade\mob_hunt\mob_cards.dm" +#include "code\modules\arcade\mob_hunt\mob_datums.dm" +#include "code\modules\arcade\mob_hunt\mob_type_datums.dm" #include "code\modules\assembly\assembly.dm" #include "code\modules\assembly\bomb.dm" #include "code\modules\assembly\health.dm" @@ -1438,6 +1449,7 @@ #include "code\modules\mob\mob_helpers.dm" #include "code\modules\mob\mob_movement.dm" #include "code\modules\mob\mob_transformation_simple.dm" +#include "code\modules\mob\pulling.dm" #include "code\modules\mob\say.dm" #include "code\modules\mob\status_procs.dm" #include "code\modules\mob\transform_procs.dm" @@ -1684,18 +1696,21 @@ #include "code\modules\mob\living\simple_animal\hostile\retaliate\pet.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\undead.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\__defines.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\actions.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\black.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\chem.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\ghost.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\gray.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\prince.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\red.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\terror_spiders.dm" #include "code\modules\mob\new_player\login.dm" #include "code\modules\mob\new_player\logout.dm" #include "code\modules\mob\new_player\new_player.dm" #include "code\modules\mob\new_player\poll.dm" #include "code\modules\mob\new_player\preferences_setup.dm" #include "code\modules\mob\new_player\sprite_accessories.dm" -#include "code\modules\mob\spirit\cultnet.dm" -#include "code\modules\mob\spirit\movement.dm" -#include "code\modules\mob\spirit\spirit.dm" -#include "code\modules\mob\spirit\viewpoint.dm" -#include "code\modules\mob\spirit\mask\mask.dm" -#include "code\modules\mob\spirit\mask\respawn.dm" #include "code\modules\nano\nanoexternal.dm" #include "code\modules\nano\nanomanager.dm" #include "code\modules\nano\nanomapgen.dm" @@ -1748,6 +1763,7 @@ #include "code\modules\pda\core_apps.dm" #include "code\modules\pda\messenger.dm" #include "code\modules\pda\messenger_plugins.dm" +#include "code\modules\pda\mob_hunt_game_app.dm" #include "code\modules\pda\PDA.dm" #include "code\modules\pda\pdas.dm" #include "code\modules\pda\radio.dm" diff --git a/sound/effects/altar_break.ogg b/sound/effects/altar_break.ogg new file mode 100644 index 00000000000..72625df1000 Binary files /dev/null and b/sound/effects/altar_break.ogg differ diff --git a/sound/effects/dimensional_rend.ogg b/sound/effects/dimensional_rend.ogg new file mode 100644 index 00000000000..98bd3ef193f Binary files /dev/null and b/sound/effects/dimensional_rend.ogg differ diff --git a/sound/effects/forge_destroy.ogg b/sound/effects/forge_destroy.ogg new file mode 100644 index 00000000000..2b198e83af4 Binary files /dev/null and b/sound/effects/forge_destroy.ogg differ diff --git a/sound/effects/pylon_shatter.ogg b/sound/effects/pylon_shatter.ogg new file mode 100644 index 00000000000..7c5ccb37a15 Binary files /dev/null and b/sound/effects/pylon_shatter.ogg differ diff --git a/sound/effects/wood_break.ogg b/sound/effects/wood_break.ogg new file mode 100644 index 00000000000..e720e3327bc Binary files /dev/null and b/sound/effects/wood_break.ogg differ