diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 750e15488b5..badefaf8999 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -248,6 +248,7 @@ CREATE TABLE `player` ( `volume` smallint(4) DEFAULT '100', `nanoui_fancy` smallint(4) DEFAULT '1', `show_ghostitem_attack` smallint(4) DEFAULT '1', + `lastchangelog` varchar(32) NOT NULL, 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 8af09a45737..4f184355e5e 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -248,6 +248,7 @@ CREATE TABLE `SS13_player` ( `volume` smallint(4) DEFAULT '100', `nanoui_fancy` smallint(4) DEFAULT '1', `show_ghostitem_attack` smallint(4) DEFAULT '1', + `lastchangelog` varchar(32) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index edd52324c14..6eef766fd9b 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -464,7 +464,7 @@ "aiV" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel,/area/security/armoury) "aiW" = (/obj/structure/rack,/obj/item/weapon/storage/box/seccarts{pixel_x = 3; pixel_y = 2},/obj/item/weapon/storage/box/handcuffs,/obj/item/weapon/storage/box/flashbangs{pixel_x = -2; pixel_y = -2},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/storage/box/handcuffs,/obj/effect/decal/warning_stripes/red/hollow,/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/security/armoury) "aiX" = (/obj/structure/rack,/obj/item/clothing/mask/gas{pixel_x = 3; pixel_y = 3},/obj/item/clothing/mask/gas{pixel_x = 3; pixel_y = 3},/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas{pixel_x = -3; pixel_y = -3},/obj/item/clothing/mask/gas{pixel_x = -3; pixel_y = -3},/obj/effect/decal/warning_stripes/red/hollow,/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/security/armoury) -"aiY" = (/obj/structure/table,/obj/effect/decal/warning_stripes/red/hollow,/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/security/armoury) +"aiY" = (/obj/structure/table,/obj/effect/decal/warning_stripes/red/hollow,/obj/item/weapon/storage/toolbox/mechanical,/obj/item/device/lock_buster,/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/security/armoury) "aiZ" = (/obj/machinery/recharger/wallcharger{pixel_x = -25; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/obj/machinery/light{dir = 8},/turf/simulated/floor/plasteel{icon_state = "red"; dir = 8},/area/security/main) "aja" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor/plasteel,/area/security/main) "ajb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plasteel,/area/security/main) @@ -2488,7 +2488,7 @@ "aVR" = (/obj/effect/spawner/window/reinforced,/obj/machinery/door/firedoor{dir = 2},/obj/structure/cable{d2 = 4; icon_state = "0-4"},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable,/turf/simulated/floor/plating,/area/hallway/primary/port) "aVS" = (/obj/machinery/door/firedoor,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 5},/area/hallway/primary/port) "aVT" = (/obj/effect/spawner/window/reinforced,/obj/machinery/door/firedoor{dir = 2},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/hallway/primary/port) -"aVU" = (/turf/simulated/wall/r_wall,/area/hallway/primary/port) +"aVU" = (/obj/effect/spawner/window/reinforced,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "aVV" = (/obj/structure/disposalpipe/segment,/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aVW" = (/obj/machinery/door/firedoor{dir = 4; name = "Firelock East"},/obj/machinery/door/airlock/command{name = "Gateway Access"; req_access_txt = "62"},/turf/simulated/floor/plasteel,/area/gateway) "aVX" = (/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,/obj/machinery/door/firedoor{dir = 4; name = "Firelock East"},/obj/machinery/door/poddoor/shutters{dir = 2; id_tag = "stationawaygate"; name = "Gateway Access Shutters"},/turf/simulated/floor/plasteel,/area/gateway) @@ -2505,7 +2505,7 @@ "aWi" = (/obj/structure/grille,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/hallway/primary/central/ne) "aWj" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/hallway/primary/central/ne) "aWk" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/hallway/primary/central/ne) -"aWl" = (/obj/machinery/vending/snack,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/hallway/primary/central) +"aWl" = (/obj/structure/table,/obj/item/device/radio/beacon/syndicate/bomb{pixel_y = 5},/obj/item/device/radio/beacon/syndicate/bomb,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "aWm" = (/turf/simulated/floor/plasteel{icon_state = "neutral"; dir = 4},/area/hallway/primary/central/ne) "aWn" = (/obj/machinery/light{dir = 1},/obj/machinery/vending/boozeomat,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/crew_quarters/bar) "aWo" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/crew_quarters/bar) @@ -3935,7 +3935,7 @@ "bxI" = (/obj/structure/stool/bed/chair/office/light{dir = 1},/obj/effect/landmark/start{name = "Roboticist"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/assembly/robotics) "bxJ" = (/turf/simulated/floor/plasteel{icon_state = "white"},/area/assembly/robotics) "bxK" = (/obj/machinery/camera{c_tag = "Research Robotics Lab"; dir = 2; network = list("Research","SS13")},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whiteredcorner"},/area/assembly/robotics) -"bxL" = (/obj/machinery/computer/guestpass,/obj/structure/table,/obj/machinery/door_control{id = "robotics"; name = "Robotics Lab Shutters Control"; pixel_x = -24; pixel_y = 24; req_access_txt = "29"},/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitered"},/area/assembly/robotics) +"bxL" = (/obj/structure/table,/obj/machinery/door_control{id = "robotics"; name = "Robotics Lab Shutters Control"; pixel_x = -24; pixel_y = 24; req_access_txt = "29"},/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitered"},/area/assembly/robotics) "bxM" = (/obj/structure/stool,/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitered"},/area/assembly/robotics) "bxN" = (/obj/structure/filingcabinet/chestdrawer,/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitered"},/area/assembly/robotics) "bxO" = (/turf/simulated/wall,/area/medical/research{name = "Research Division"}) @@ -4580,7 +4580,7 @@ "bKd" = (/obj/machinery/light/small{dir = 1},/obj/machinery/camera{c_tag = "Research Shuttle Maintenance"; dir = 2; network = list("Research","SS13")},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitepurplecorner"},/area/medical/research{name = "Research Division"}) "bKe" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Biohazard"; name = "Biohazard Shutter"; opacity = 0},/obj/machinery/door/airlock/glass_research{name = "Research Shuttle Dock"; req_access_txt = "65"},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitepurplecorner"},/area/medical/research_shuttle_dock) "bKf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitebluecorner"},/area/medical/research_shuttle_dock) -"bKg" = (/obj/effect/spawner/window/reinforced,/obj/machinery/door/firedoor{dir = 2},/turf/simulated/shuttle/plating,/area/medical/research_shuttle_dock) +"bKg" = (/obj/machinery/vending/snack,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/hallway/primary/central/ne) "bKh" = (/obj/machinery/power/apc{dir = 1; name = "Genetics Maintenance APC"; pixel_y = 24},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/plating,/area/maintenance/genetics) "bKi" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/turf/simulated/floor/plating,/area/maintenance/genetics) "bKj" = (/obj/machinery/light/small{dir = 1},/obj/structure/disposalpipe/sortjunction{dir = 2; icon_state = "pipe-j2s"; sortType = 14},/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/genetics) @@ -4670,7 +4670,7 @@ "bLP" = (/obj/structure/stool/bed/chair/office/dark{dir = 4},/obj/effect/landmark/start{name = "Head of Personnel"},/turf/simulated/floor/plasteel,/area/crew_quarters/heads) "bLQ" = (/obj/structure/table,/obj/machinery/firealarm{dir = 8; pixel_x = -24},/obj/item/weapon/folder/yellow,/obj/item/device/eftpos,/obj/item/weapon/book/manual/sop_supply,/turf/simulated/floor/plasteel,/area/quartermaster/office) "bLR" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/floor/plasteel,/area/crew_quarters/heads) -"bLS" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel,/area/crew_quarters/heads) +"bLS" = (/obj/machinery/computer/guestpass,/obj/structure/table,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/lab) "bLT" = (/obj/machinery/computer/message_monitor,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/server) "bLU" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/supply{req_access_txt = "0"},/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/server) "bLV" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/server) @@ -4821,7 +4821,7 @@ "bOK" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/plasteel{icon_state = "white"},/area/crew_quarters/hor) "bOL" = (/obj/machinery/ai_status_display{pixel_y = 32},/turf/simulated/floor/plasteel{dir = 4; icon_state = "warnwhite"; tag = "icon-warnwhite (NORTH)"},/area/crew_quarters/hor) "bOM" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/asmaint2) -"bON" = (/obj/effect/spawner/window/reinforced,/turf/simulated/shuttle/plating,/area/maintenance/asmaint2) +"bON" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable,/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "representative"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area/ntrep) "bOO" = (/turf/simulated/floor/plasteel{dir = 10; icon_state = "warning"},/area/medical/research_shuttle_dock) "bOP" = (/obj/machinery/power/apc{dir = 2; name = "Research Shuttle Dock APC"; pixel_y = -24},/obj/structure/cable,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/research_shuttle_dock) "bOQ" = (/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/research_shuttle_dock) @@ -5148,7 +5148,7 @@ "bUZ" = (/turf/simulated/wall,/area/ntrep) "bVa" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable,/obj/structure/disposalpipe/segment,/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "representative"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area/ntrep) "bVb" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock/command{name = "NT Representative's Office"; req_access_txt = "73"},/turf/simulated/floor/wood,/area/ntrep) -"bVc" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable,/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "representative"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area/blueshield) +"bVc" = (/obj/effect/landmark{name = "blobstart"},/turf/simulated/floor/plating,/area/maintenance/apmaint) "bVd" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/firedoor,/turf/simulated/floor/plasteel,/area/hallway/primary/central/south) "bVe" = (/obj/structure/sign/directions/engineering,/obj/structure/sign/directions/science{dir = 4; pixel_x = 0; pixel_y = -7},/obj/structure/sign/directions/medical{dir = 4; pixel_y = 7},/turf/simulated/wall,/area/janitor) "bVf" = (/turf/simulated/wall,/area/janitor) @@ -5414,7 +5414,7 @@ "caf" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{dir = 2; icon_state = "whitebluecorner"; tag = "icon-whitebluecorner"},/area/medical/medbay2) "cag" = (/obj/machinery/vending/medical,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (SOUTHEAST)"; icon_state = "whiteblue"; dir = 6},/area/medical/medbay2) "cah" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/structure/disposalpipe/segment,/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "cmooffice"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area/medical/cmo) -"cai" = (/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/cmo) +"cai" = (/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/cmo) "caj" = (/obj/structure/stool/bed/chair/office/dark{dir = 1},/obj/effect/landmark/start{name = "Chief Medical Officer"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/cmo) "cak" = (/obj/machinery/prize_counter,/turf/simulated/floor/wood,/area/crew_quarters/bar) "cal" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "cmooffice"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area/medical/cmo) @@ -5707,8 +5707,8 @@ "cfM" = (/obj/structure/grille,/obj/structure/window/plasmareinforced{dir = 4},/obj/structure/window/plasmareinforced{dir = 8},/obj/structure/window/plasmareinforced,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Biohazard"; name = "Biohazard Shutter"; opacity = 0},/turf/simulated/floor/plating,/area/toxins/mixing) "cfN" = (/turf/simulated/floor/plasteel/airless{dir = 4; icon_state = "warning"},/area/toxins/test_area) "cfO" = (/turf/simulated/floor/plasteel/airless{tag = "icon-warningcorner (NORTH)"; icon_state = "warningcorner"; dir = 1},/area/toxins/test_area) -"cfP" = (/obj/machinery/light/small{dir = 1},/obj/structure/stool,/turf/simulated/floor/plating,/area/maintenance/aft) -"cfQ" = (/obj/effect/landmark{name = "blobstart"},/turf/simulated/floor/plating,/area/maintenance/aft) +"cfP" = (/obj/machinery/light/small{dir = 1},/obj/structure/stool,/turf/simulated/floor/plating,/area/maintenance/apmaint) +"cfQ" = (/obj/structure/closet,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/apmaint) "cfR" = (/turf/simulated/floor/plating,/area/maintenance/aft) "cfS" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/maintenance/apmaint) "cfT" = (/obj/structure/closet/secure_closet/blueshield,/obj/machinery/firealarm{dir = 8; pixel_x = -24},/turf/simulated/floor/wood,/area/blueshield) @@ -5784,9 +5784,9 @@ "chl" = (/turf/simulated/floor/plasteel/airless{icon_state = "warning"},/area/toxins/test_area) "chm" = (/turf/simulated/floor/plasteel/airless{dir = 6; icon_state = "warning"},/area/toxins/test_area) "chn" = (/turf/simulated/floor/plasteel/airless{dir = 10; icon_state = "warning"},/area/toxins/test_area) -"cho" = (/obj/structure/table,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/aft) -"chp" = (/obj/structure/closet,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/aft) -"chq" = (/obj/structure/rack{dir = 1},/obj/effect/spawner/lootdrop/maintenance{lootcount = 2; name = "2maintenance loot spawner"},/turf/simulated/floor/plating,/area/maintenance/aft) +"cho" = (/obj/structure/table,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/apmaint) +"chp" = (/obj/structure/rack{dir = 1},/obj/effect/spawner/lootdrop/maintenance{lootcount = 2; name = "2maintenance loot spawner"},/turf/simulated/floor/plating,/area/maintenance/apmaint) +"chq" = (/obj/structure/closet/emcloset,/turf/simulated/floor/plasteel{icon_state = "caution"; dir = 4},/area/hallway/primary/aft) "chr" = (/turf/simulated/wall/r_wall,/area/blueshield) "chs" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = -32; pixel_y = 0},/obj/structure/disposalpipe/junction{tag = "icon-pipe-j2"; icon_state = "pipe-j2"; dir = 2},/turf/simulated/floor/plasteel{dir = 8; icon_state = "cautioncorner"},/area/hallway/primary/aft) "cht" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/unary/vent_scrubber{on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel,/area/hallway/primary/aft) @@ -6135,7 +6135,7 @@ "cnY" = (/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/weapon/circuitboard/powermonitor{pixel_x = -2; pixel_y = 2},/obj/item/weapon/circuitboard/stationalert_all{pixel_x = 1; pixel_y = -1},/obj/item/weapon/circuitboard/atmos_alert{pixel_x = 3; pixel_y = -3},/obj/item/weapon/circuitboard/thermomachine,/obj/item/weapon/circuitboard/smes{pixel_x = 4},/turf/simulated/floor/plating,/area/storage/tech) "cnZ" = (/obj/machinery/light_switch{pixel_x = 27},/turf/simulated/floor/plating,/area/storage/tech) "coa" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{dir = 2; icon_state = "yellowcorner"},/area/hallway/primary/aft) -"cob" = (/obj/structure/closet/emcloset,/turf/simulated/floor/plasteel{icon_state = "caution"; dir = 4},/area/hallway/secondary/construction{name = "\improper Engineering Training"}) +"cob" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/obj/machinery/computer/guestpass/hop{pixel_x = 28},/turf/simulated/floor/plasteel,/area/crew_quarters/heads) "coc" = (/obj/machinery/door/firedoor{dir = 1; name = "Firelock North"},/obj/machinery/door/airlock/glass_engineering{name = "Engineering"; req_access_txt = "0"; req_one_access_txt = "11;24"},/turf/simulated/floor/plasteel,/area/engine/controlroom) "cod" = (/turf/simulated/wall,/area/engine/controlroom) "coe" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11; level = 1},/turf/simulated/wall/r_wall,/area/construction) @@ -7063,7 +7063,7 @@ "cFQ" = (/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/clothing/shoes/magboots,/obj/item/clothing/suit/space/rig/engineering,/obj/item/clothing/mask/breath,/obj/item/clothing/head/helmet/space/rig/engineering,/obj/machinery/firealarm{dir = 2; pixel_y = 24},/turf/simulated/floor/plasteel,/area/engine/hardsuitstorage) "cFR" = (/obj/machinery/power/apc{dir = 4; name = "CE Office APC"; pixel_x = 24; pixel_y = 0; shock_proof = 1},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) "cFS" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/plating,/area/engine/chiefs_office) -"cFT" = (/obj/machinery/keycard_auth{pixel_x = 0; pixel_y = 24},/obj/structure/table/reinforced,/obj/item/weapon/rcd,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/stock_parts/cell/high{charge = 100; maxcharge = 15000},/obj/item/weapon/stock_parts/cell/high{charge = 100; maxcharge = 15000},/obj/item/clothing/glasses/meson{pixel_y = 4},/obj/item/device/megaphone,/mob/living/simple_animal/parrot/Poly,/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) +"cFT" = (/obj/machinery/keycard_auth{pixel_x = 0; pixel_y = 24},/obj/structure/table/reinforced,/obj/item/weapon/rcd,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/stock_parts/cell/high{charge = 100; maxcharge = 15000},/obj/item/weapon/stock_parts/cell/high{charge = 100; maxcharge = 15000},/obj/item/clothing/glasses/meson{pixel_y = 4},/obj/item/device/megaphone,/obj/item/device/lock_buster,/mob/living/simple_animal/parrot/Poly,/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) "cFU" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/structure/closet/firecloset,/obj/machinery/requests_console{department = "Atmospherics"; departmentType = 3; name = "Atmospherics Requests Console"; pixel_x = -30},/turf/simulated/floor/plasteel,/area/atmos) "cFV" = (/obj/machinery/door_control{id = "atmos"; name = "Atmospherics Lockdown"; pixel_x = 10; pixel_y = 24; req_access_txt = "24"},/obj/machinery/door_control{desc = "A remote control-switch for the engineering security doors."; id = "Engineering"; name = "Engineering Lockdown"; pixel_x = -10; pixel_y = 24; req_access_txt = "10"},/obj/machinery/door_control{desc = "A remote control-switch for secure storage."; id = "Secure Storage"; name = "Engineering Secure Storage"; pixel_x = 0; pixel_y = 24; req_access_txt = "11"},/obj/machinery/light_switch{pixel_y = 38},/obj/machinery/atmospherics/unary/vent_pump{dir = 1; external_pressure_bound = 101; on = 1; pressure_checks = 1},/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) "cFW" = (/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) @@ -8536,7 +8536,6 @@ "dii" = (/obj/docking_port/stationary{dir = 2; dwidth = 2; height = 18; id = "skipjack_nw"; name = "northwest of SS13"; width = 19},/turf/space,/area/space) "dij" = (/obj/machinery/door/window{base_state = "right"; dir = 4; icon_state = "right"; name = "Equipment Room"; req_access_txt = "150"},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "dik" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1331; id_tag = "synd_pump"},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) -"dil" = (/obj/effect/spawner/window/reinforced,/turf/unsimulated/floor{icon_state = "floor4"},/area/shuttle/syndicate) "dim" = (/obj/structure/rack,/obj/item/clothing/suit/space/syndicate/black/red,/obj/item/clothing/head/helmet/space/syndicate/black/red,/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1331; id_tag = "synd_pump"},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "din" = (/obj/item/device/radio/intercom/syndicate{pixel_x = -28},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "dio" = (/obj/docking_port/stationary{dheight = 9; dir = 2; dwidth = 5; height = 22; id = "syndicate_ne"; name = "northeast of station"; width = 18},/turf/space,/area/space) @@ -8564,7 +8563,6 @@ "diK" = (/obj/structure/table,/obj/item/weapon/gun/syringe,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "diL" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "diM" = (/obj/machinery/door/window{dir = 1; name = "Secure Storage"; req_access_txt = "150"},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) -"diN" = (/obj/structure/table,/obj/item/device/radio/beacon/syndicate/bomb{pixel_y = 5},/obj/item/device/radio/beacon/syndicate/bomb,/turf/unsimulated/floor{icon_state = "floor4"},/area/shuttle/syndicate) "diO" = (/obj/structure/table,/obj/item/weapon/grenade/syndieminibomb{pixel_x = 4; pixel_y = 2; pixel_z = 0},/obj/item/weapon/grenade/syndieminibomb{pixel_x = -1},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "diP" = (/obj/structure/mirror{pixel_x = 28},/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "diQ" = (/obj/machinery/telecomms/allinone{intercept = 1},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) @@ -8793,12 +8791,12 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhRcaVdhUdhTbFldhNcaVdhObFlaafdhWdhVdhXbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaaCaaDaaEaaFaayaayaawaaGaaHaayaazaazaaIaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhYcaVcaVdhZbFldiacaVcczdicdibdibdibbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaaqaayaaKaaLaaMaayaaNaaOaavaaPaataataalaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhRcaVcaVcaVdidcaVcaVdiedigdifdifdihbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdiibikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaataataataaQaaRaaSaawaaGaaHaaxaaTaaUaaVaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhRcaVcaVcaVdijcaVcaVcaVdildikdikdimbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaaWaaXaaYaaZabaabbabcabdabeabfabgabhabhaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhRcaVcaVcaVdijcaVcaVcaVaVUdikdikdimbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaaWaaXaaYaaZabaabbabcabdabeabfabgabhabhaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdhPaafaafaafaafaafaafdincaVcaVaafaafaafaafaafaafdhXbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabiabjabkablabmabnaboabpabqabraatabsabtaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdiobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldipdipdiqdisdirbFlditcaVcaVbFldiudiwdivdiydixbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikaalabuaalabvabwabxabxaalaalabyaaoaalaalabzaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFlcaVcaVcaVdhUcaVdizcaVcaVcaVdiAcaVdhUcaVdhUdiBbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabBaatabCabDabEabFbikbikbikbikbikaalabGaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikabAcQScJadgjbikbikbikabAbikbikbikdgjbikbikbikabAdiCdgldgjbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldiDdiEcaVcaVcaVdiFcaVcaVcaVdiGcaVcaVcaVcaVdiHbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabBaatabCabHaalbikbikbikbikbikbikaalaalaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgmdgodgndgmbikbikabAdgmdgpdgrdgqdgmdgjbikbikdgmdgsdgtdgmbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldiIdiEcaVdiKdiJbFldiLdiMdiLbFldiNdiOcaVcaVcaVbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikaalaalaalaalabuaatabIabJaalaalaalaalbikbikbikabKabLabLabKbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgmdgvdgudgmbikabAdgwdgydgxdgAdgzdgydgwdgjbikdgmdgBdgCdgmbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldiIdiEcaVdiKdiJbFldiLdiMdiLbFlaWldiOcaVcaVcaVbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikaalaalaalaalabuaatabIabJaalaalaalaalbikbikbikabKabLabLabKbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgmdgvdgudgmbikabAdgwdgydgxdgAdgzdgydgwdgjbikdgmdgBdgCdgmbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFlcaVcaVdiPbFlaafbFlcaVdiRdiQbFlaafbFlcaVcaVcaVbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabMabNabOabPabQabRabSabTabUabVaalbikbikbikbikabKabLabWabKbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgmdgEdgDdgFbikdgHdgGdgydgydgIdgydgydgGdgJbikdgLdgKdgMdgmbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldiSdiUdiTbFlbikbFldiVdiVdiVbFlbikbFldiWdiYdiXbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabXabYabZacaacbaccacdaceacfacfaalbikbikbikbikbikabKabLabLabKbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgwdgNdgwbikbikdgOdgGdgydgPdgQdgydgydgGdgRbikbikdgwdgNdgwbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldiVdiVdiVbFlbikcVGdiZdjbdjadelbikbFldiVdiVdiVbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacgacgacgacgacgacgachaciacjackaclaalacmbikbikbikbikbikabKabLabLabKbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgwdgNdgwdgwdgwdgwdgwdgwdgwdgSdgwdgwdgwdgwdgwdgwdgwdgNdgwbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik @@ -8854,8 +8852,8 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaNhaNmaNiaODaOEaOFaOGaOHaOIaOJaOKaOLaOMaONaOOaKzaKBaOPaMoaOQaORaOSaOTaOSaOUaKHaOVaMqaOWaOXaOYaOXaOZaPaaPbaPcaPdaPdaPdaPdaPdaPdaPeaPfaMvbikaLRaPgaNHaPhaNJaPiaLRbikaJGaJLaJMaPjaPkaPlaPmaPnaJMaGvaIKaPoaPoaKPaPpaMHaKSaPqaKSaMHaPraKWaPsaPsaIKaPtazUaPuazIaKbaEeaPvaPvaPvaPvaPwaPxaPyaPzaPAaPBaPBaPBaPCaPBaPDaPEaPFaPGaPHaPEaPIaPJazxayGayGayGayGayGayGayGayGayGayGayGayGaBMayGayGayGayGayHaDxaOiazvaabazvayHaPLaPMaPNaPOaPPaPQaPRaPRaPRaPRaPSaPTaPUaPVaPWaPXaPWaPYaPWaPWaPZaQaaQbaQbaQcaQdaQeaQeaQeaQeaQeaQeaQeaQeaQeabLadbbikbikbikbikbikbikbikaaabdBaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaONaQgaQhaQiaOMaQjaOFaQjaOFaQjaOFaQjaOMaQkaQlaKzaKBaQmaMoaQnaQoaQpaQqaQraQsaKHaQtaMqaQuaQvaQwaQxaQyaKHaQzaPdaPdaPdaPdaPdaPdaPdaPeaQAaMvaabaLRaQBaQCaQDaQEaQFaLRaabaJGaJLaJMaQGaQHaQIaQJaQKaJMaGvaIKaIKaIKaIKaQLaLXaJOaLYaJOaLXaQMaIKaIKaIKaIKaQNaQOaQPazIaMKaQQaQRaQRaQRaQSaQTaQUaQVaQWaQXaQVaQYaQZaRaaQVaRbaRcaRdaReaRfaMeaRgaRhaRiaRjaRjaRhaRkaRlaRlaRlaRlaRlaRmaRnaRlaRoaRpaRqaRraRsaRvaRuaTkaRwaRxaRwaRyaRzayHayGaRAaRBaRCaRDaREaRFaRGaRHaRIaRJaRIaRKaRLaRMaRNaROaRPaRQaRRaRSaRTaRUaQdaRVaRWaRXaRYaRZaSaaSbaScaSdaprbikbikbikbikbikbikbikaaabfmbifbieaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaSfaOFaOFaNjaOMaQjaOFaQjaSgaQjaOFaQjaOMaQkaQlaKzaKBaShaMoaMoaSiaSjaSkaSjaMoaKHaKHaKHaKHaSlaSmaSnaSoaKHaSpaSqaSraPdaPdaSsaPdaStaSuaSvaMvbikaLRaLRaSwaSxaSwaLRaLRbikaJGaJLaJMaSyaSzaSAaQJaSBaJMaGvaIKaJNaJOaSCaNRaLXaJOaLYaJOaLXaNTaSDaIKaIKaIKaSEaSFaSGaSHaSIaSJamKamKaSKaSLaSMaSNaMcaSOaMQaMcaSPaMcaSQaMcaSRaSSaSTaSUaSVaTeaSXaSYaSZaTaaTbaTcaTdaTbaTbaUjaTbaSYaTfaSYaOvaTgaSYaThaTiaTjaTmaTlaToaTnaTqaTpaWIaTraOuaTsaTtaTuaTvaTwaTxaTyaTzaRHaTAaTBaRIaTCaTDaTEaTFaROaTGaRQaRRaRSaTHaTIaQdaTJaTKaTKaTLaScaScaScaScaSdaprbikbikbikbikbikbikaaabfmbigbijbihbieaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaONaTMaTNaQiaOMaQjaOFaQjaOFaQjaOFaQjaOMaQkaQlaKzaKBaTOaTPaTQaTRaTSaTSaJraTTaTUaTVaTWaTXaTYaTZaMqcoCaKHaUbaUcaUdaUeaUfaUgaUhaUiaUZaUkaMvbikaabbikaUlaUmaUlbikaabbikaCuaJLaJMaUnaUoaUpaUqaUraJMaGvaIKaUsaUtaKPaUuaUvaKSaUwaKSaUxaUyaUzaIKaUAaUBaUCaUDaUEaUFaUGaUHbikbikaSKaUIaUJaUKaMcaULaUMaMQaMQaUNaMQaMQaMQaUOaMeaUPaMeaUQaURaMeaUSaMeaUTaUUaUVaUWaUXaUYaUTbwNaVaaVbaVcaVbaVbaVbaVbaVdaWLaVbaVeaVfaWFaWBaVbaVhayHaRDaViaTvaVjaVkaVlaVmaVnaVoaVpaVqaRIaVraVsaVtaVuaVvaTGaRQaRRaRSaRTaVwaQdaVxaTKaTKaTLaScaScaScaScaSdaprbikbikbikbikbikbikbdBblqbjMbmKbjMbqQbdBbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaVyaVzaNiaODaOMaOFaVAaVBaOFaOFaVCaVAaOMaONaVDaKzaKBaVEaVFaVGaVHaVGaVGaVGaVGaVGaVIaJraKHaVJaVKaVJaKHaKHaVLaVMaVLaMuaMuaMuaMuaVLaVNaVOaMvaVPaVQaVQaVRaVSaVRaVQaVQaVTaVUaVVaJMaVWaJMaVXaVYaVZaJMaWaaIKaIKaIKaIKaWbaWcaWdaWeaWdaWcaWbaIKaIKaWfaUDaUDaUDaUDaWgaWhaWiaWjaWkaSKaWlaUJaWmaMcaMcaMcaMcaMcaMcaMcaMeaMeaUOaWnaWoaWpaWqaWraWsaWuaWtaUTaWvaWwaWxaWyaWzaUTaWAaWGaWCaWDaWCaWEaWHaYDaWNaYFaWJaWKaYGaWMaYEaVbaWOaRtaWPaWQaWRaVjbtTcvIaVmaWTaRIaWUaWVaWWaWXaWYaTFaTFaRIaRIaRQaRRaRSaTHaWZaQdaXaaXbaXcaXdaXeaXfaScaScaXgaprbikbikbikbikbikaaabfmbqRbmKbmKbmKbqSbieaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaONaTMaTNaQiaOMaQjaOFaQjaOFaQjaOFaQjaOMaQkaQlaKzaKBaTOaTPaTQaTRaTSaTSaJraTTaTUaTVaTWaTXaTYaTZaMqcoCaKHaUbaUcaUdaUeaUfaUgaUhaUiaUZaUkaMvbikaabbikaUlaUmaUlbikaabbikaJGaJLaJMaUnaUoaUpaUqaUraJMaGvaIKaUsaUtaKPaUuaUvaKSaUwaKSaUxaUyaUzaIKaUAaUBaUCaUDaUEaUFaUGaUHbikbikaSKaUIaUJaUKaMcaULaUMaMQaMQaUNaMQaMQaMQaUOaMeaUPaMeaUQaURaMeaUSaMeaUTaUUaUVaUWaUXaUYaUTbwNaVaaVbaVcaVbaVbaVbaVbaVdaWLaVbaVeaVfaWFaWBaVbaVhayHaRDaViaTvaVjaVkaVlaVmaVnaVoaVpaVqaRIaVraVsaVtaVuaVvaTGaRQaRRaRSaRTaVwaQdaVxaTKaTKaTLaScaScaScaScaSdaprbikbikbikbikbikbikbdBblqbjMbmKbjMbqQbdBbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaVyaVzaNiaODaOMaOFaVAaVBaOFaOFaVCaVAaOMaONaVDaKzaKBaVEaVFaVGaVHaVGaVGaVGaVGaVGaVIaJraKHaVJaVKaVJaKHaKHaVLaVMaVLaMuaMuaMuaMuaVLaVNaVOaMvaVPaVQaVQaVRaVSaVRaVQaVQaVTaJGaVVaJMaVWaJMaVXaVYaVZaJMaWaaIKaIKaIKaIKaWbaWcaWdaWeaWdaWcaWbaIKaIKaWfaUDaUDaUDaUDaWgaWhaWiaWjaWkaSKbKgaUJaWmaMcaMcaMcaMcaMcaMcaMcaMeaMeaUOaWnaWoaWpaWqaWraWsaWuaWtaUTaWvaWwaWxaWyaWzaUTaWAaWGaWCaWDaWCaWEaWHaYDaWNaYFaWJaWKaYGaWMaYEaVbaWOaRtaWPaWQaWRaVjbtTcvIaVmaWTaRIaWUaWVaWWaWXaWYaTFaTFaRIaRIaRQaRRaRSaTHaWZaQdaXaaXbaXcaXdaXeaXfaScaScaXgaprbikbikbikbikbikaaabfmbqRbmKbmKbmKbqSbieaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaVyaNiaNjaNiaNiaNkaNlaNiaNiaNjaVzaXhaCuaXiaVEaInaXjaXjaXkaXjaXlaDEaXmaXnaJraXoaXpaXqaXqaXraXsaXqaXtaXqaXqaXqaXuaXqaXqaXvaXwaXxaXyaXzaXAaXyaXBaXyaXyaXyaXyaXCaXDaXEaXqaXqaXFaXGaXHaXIaXJaXKaXLaXMaXRaXPaXPaXPaXPaXPaXPaXPaXQaXWaXXaXSaXTaXUaXVaXYaZHaXZaUDaUDaYaaYbaYcaYbaYcaYdaYeaYfaYgaYhaYiaMeaYkbBvaYmaYlaYnaYnaYoaYpaYqaYraUTaYsaYtaYuaYuaYvaUTaYwaYxaYyaYzaYAaYAaYBaYCaYHbbFbalbbHbbGbbJaVgaVbaVhaKsaRDaYIaYJaYJaYKaYLaYJaYMaRIaYNaYOaRIaYPaYQaTFaYRaRIaYSaYTaYUaRSaQbaQbaQdaYVaQeaYWaYXaQeaQeaQeaQeaQeabLadbbikbikbikbikbqUbqTbqVbmKbmKbrUbthbmKbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaInaYYaKzaKzaKzaKzaKzaKzaYYaInaMlaCuaYZaZaaInaZbaZcaZdaZdaZeaDEaZfaXnaZgaZhaXpaZiaZjaZkaZlaZlaZmaZnaZnaZnaZoaZpaZpaZqaZraZsaZlaZlaZtaZpaZvaZwaZxaZxaZyaZzaZAaZuaZuaZuaZBaXGaXHaXIaXJaXJaXJaXJaZCaXJaXJaXJaXJaXJaXJaZDaZEaZNaZFaZGaZJaZIaZLaZKaZMaZNaZNaZNaZOaZPaZPaZPaZQaYiaYiaYiaZRaZSaYiaMebbsaZUaYnaYnaZVaYnaZWaZXaYqaZYaUTaZZbaababbacbadaUTbaebafbagbahbaibajaVbaVbbbKbbLaVbaVbbakbbMbakaVbaVhayHaRDbamaTvaTvaTvbanaTvbaoaRIaRIaRIaRIaRIaRIaRIbapaRIaRSaRSaRRaRSbaqbaraQbbasbatbaubavbawbaxbaybazbaAbikbikbikbikaaabtibtjbtibtibtibtkbtibtlbtibtjbtiaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabaabaLyaCuaInaGdaKzbaBbaCbaDbaEaKzaGdaInaInaCubaFaVEaInbaGbaHaZdaZdaZeaDEbaIaXnaJraZhaXpaXqbaJbaKbaLbaLbaMbaNbaObaLbaPbaLbaQbaLbaRbaSbaLbaLbaWbaLbaLbaUbaVbaLbaWbaXbaYbaZaXqaXqbbabbbbbcbbdbbebbfbbebbgbbhbbgbbgbbgbbgbbgbbgbbibbjbbkbbkbbkbbkbblbbkbbmbbnbbkbbkbbobbpbbqbbqbbqbbqbbqbbqbbqbbraYiaYiaMebcTbbtbbubbvbbvbbwbbxaZXaYqbbyaUTaUTaUTaUTaUTbbzaUTbbAbbBbbCbbDaWCbbEaVbbdfbdcbdgbbIbkZbjrcSNcIgaVbaVhaHYaRDbbNbbOaTvbbPbbQaTvbbRbbRaRDbbSbbTbbUaQbbbVbbWbbXaRSaRSbbYbbZaQbbcaaQbbcbbatbccbcdbcebatbatbcfbaAbikbikbikbikbqUbtmbwlbutbwmbtmbmKbutbwmbtmbwlbutbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik @@ -8873,36 +8871,36 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbBGbDCbBHdjhbDDdjidjidjkdjjbtqbxZbjNaInaInaKBbrWbrXbrYbrXbrXbrXbrXbrZbsabsbbcsbcsbscbsdblCbmUbsebsfbpAblCbsgbshbsgbcobcobcobcobsibcobsjbskbngbslbsmbpFbsnbsobngboCbnmbspbpIbpIbpIbsqbnmbsrbpNboIbpOdmbbrwbrxbstbsubrAbpTbsvbmgbswbsxbnvbsybszbsAboSbsBbsCbsDbsEbsFbsGbsHbsIbsJbqbbsKbnAbsLbsMbqibqjbqkbqlbqnbsNbqnbqnbqnbqnbsObsPbsPbsPbsPbsQbqnbqnbqnbqnbsRbqnbsNbsSbqnbsTbsUbsVbqnbsWbsXbsXbsYbsZbtabtbbmFbmFbmFbmFbmFbmFbmFbtcbtdbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbtebtfbtfbtgddSddRddUddTddTddTddTddVddWbaAaabbikbikaabbqUddXddZddYdeabqUbikbqUdecdebdecdecbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbBGbDCdjldjidjidjidjidjidjidjideHdjnaGddjnaJrbtrbrXbtsbttbtubtvbtwbrZbtxbtybtzbtzbtAbtBblCblCblCbosbtCborbcsbcsbcsbcsbtDbejbejbskbejbsjbskbngbtEbtFbtGbtHboAbngbtIbnmbtJbpIbpIbpIbtKbtLbtMbpNbtNbnqbtObtPbpRbpRbpRbpRbpTbtQbmgbtRbtSbmgbmgbmgbmgbmgbmgbmgbnzbnAbqrbtUbtVbtWbtXbtYbtZbnAbvubuabuabucbucbucbucbucbucbucbudbudbuebufbugbugbufbuebudbudbuhbuhbuhbuhbuhbuhbuibuibujbuibuibuibuibuibukafkbumbunbmFbmFbuobuobupbupbupbupbupbuqbtfbtfbtebtfbmFbtfbtfbtfbtfburbusbusbusbusdedbuubuubuubuubuubuubuubuubuubikbikbikbikbdBddYddYddYdeebqUbikbqUdefdebdebdegbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbBGbDCdjodjpdjpdjidjpdjpdjpbtqdjqaInaInaInaKBbuvbrXbuwbuxbuxbuxbuybrZbejbuzbuAbuBbuCbuDblCbmUbuEbosbuFborbuGbuHbuIbuJbuKbuLbuLbuMbuLbuNbuObngbuPbuQbuRbuSbuTbuUbuVbnmbuWbpIbpIbuXbuYbuZbtMbpNbvabnqbvbbvcbvdbvebvfbvgbvhbnqbnqbvibvjbvkbvlbvmbvlbvnbvjbikbvobnAbvpbvqbvrdmcbtXbqbbvtbnAbxebvwbxfbucbzcbvybvzbvAbvBbvCbvDbvEbvFbvGbvHbvHbvGbvIbvJbvKbuhbvLbvMbvNbvObuhbvPbvQbvRbvSbvTbvUbvUbvVbukafNbvXbvYbvZbvYbwabwabupbwbbwcbwdbupbwebwfbwebupbwgbtfburbusbwhbwibwhbusbwjbwkbusdeicngbxXbwobikbikbikbikbikbikbikbikbikbikbqUddXddZddYdejbqUbikbqUdekdekdekdekbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjrbtqbtqbtqbtqbtqbtqbtqbtqdjqbikbikaInbwqbdFbwrbrXbwsbrXbwtbuxbwubwvbrZbwwbwxbwybwzbuDblCblCblCblCblCblCbwAbwBbwCbwDbwEbngbngbngbngbngbngbngbwFbngbngbngbwGbngbwHbwIbwJbpIbpIbpIbwKbtLbwLbpNbwMbnqbIDbvcbnrbnrbnrbnqbwObnqbwPbwQbwRbwSbwTbwUbwVbwWbwXbwYbwZbnAbxabqbbxbbxcbtXbxdbqbbnAbzbbxgbANbucbxhbxibxjbxkbxlbxmbxnbvHbvHbvHbvHbvHbvHbvHbvHbxobxpbxqbxrbxsbxtbuhbxubxvbxwbxxbxybxzbxvbxAbukbDdbvXbxCbxDbxEbxFbxFbxGbxHbxIbxJbxKbxLbxMbxNbupbxObxPbxQbusbxRbxSbxTbxUbxUbxVbusbxWbxXbxYbwobikbikbikbikbikbikbikbikbikbikbDybtldemdemdemdenbikdeodepdepdepbtlbDzbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjrbtqbtqbtqbtqbtqbtqbtqbtqdjqbikbikaInbwqbdFbwrbrXbwsbrXbwtbuxbwubwvbrZbwwbwxbwybwzbuDblCblCblCblCblCblCbwAbwBbwCbwDbwEbngbngbngbngbngbngbngbwFbngbngbngbwGbngbwHbwIbwJbpIbpIbpIbwKbtLbwLbpNbwMbnqbIDbvcbnrbnrbnrbnqbwObnqbwPbwQbwRbwSbwTbwUbwVbwWbwXbwYbwZbnAbxabqbbxbbxcbtXbxdbqbbnAbzbbxgbANbucbxhbxibxjbxkbxlbxmbxnbvHbvHbvHbvHbvHbvHbvHbvHbxobxpbxqbxrbxsbxtbuhbxubxvbxwbxxbxybxzbxvbxAbukbDdbvXbxCbxDbxEbxFbxFbxGbxHbxIbxJbxKbxLbxMbxNbupbxObxPbxQbusbxRbxSbxTbLSbxUbxVbusbxWbxXbxYbwobikbikbikbikbikbikbikbikbikbikbDybtldemdemdemdenbikdeodepdepdepbtlbDzbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaLyaCuaKzaKzaInaInaInaInaInaInaInaKBaJrbyabrXbybbycbydbyebyebyfbygbyhbyibyibyjbykbtzbtzbtzbtzbtzbtzbylbymbymbynbyobngbypbyqbyrbysbytbyubyvbywbngbyxbyybyzbuVbtLbwJbpIbpIbyAbnmbnmbyBbyCbyDbyEbyFbyGbyHbyIbyJbyKbyLbyMbyNbyObwXbyPbyQbyPbyQbyRbwXbwYbySbyTbyUbyVbyWbyXbyYbyZbzabyTbAObvwbvwbucbzebzdcSCbzfbzgbucbxnbvHbvHbvHbvHbvHbvHbvHbzhbzibzjbzkbzlbxqbzmbuhbznbzobzpbxxbxAbxzbzqbzrbukbIbbztbzubzvbzvbzwbzxbzybzzbzAbzAbzAbzBbzAbzCbzDbzEbzFbzGbzHbzIbzJbzKbzKbzKbzLbusbzMbxXbzNbwobikbikbikbikbikbikbikbikbikbikbikbDyderderderbDzbikbDyderderderbDzbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaIndjtdjsdjuaIoaIoaIobdFaJraJrbrXbzVbrXbzWbzXbzYbzZbrXbcsbAabAabAbbAcbAbbAbbAbbAcbAbbcsbcsbngbngbngbAdbngbAebAebAebAebAebAebyvbAfbAgbAhbAibAjbAkbAlbAmbAnbAobApbAqbArbAsbAtbAubAvbAwbAwbAxbAybAzbAAbABbACbADbAEbvjbAFbwVbAGbwTbAHbvjbikbAIbAJbAKbALbAJbAJbAJbAJbAMbnAbCBbvwbCCbAPbAQbARbASbATbAUbucbAVbAWbAXbAYbAZbBabBbbBcbvHbBdbuhbBebzlbBfbBgbuhbBhbBibxwbxxbxAbxzbxvbxAbukbDdbvXbBjbBkbBlbBmbBnbBobBpbBqbBrbBsbBtbBubKpbupbBwbBxbBybusbBzbBAbBBbxUbBCbKwbusbzMbxXbBEbwobikbikbikbikaabaabaabaabaabaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaIndjwdjvdjuaJqaJqbBIbBJaJqbBKbrXbBLbycbBMbBNbBObBPbrXbikaabaabdetdesdesdesdesdesdeubikbikbBRbBSbBTbBUbBVbAebAebAebAebAebAebBWbBXbBYbBZbCabCbbCcbCdbnmbnmbCebCfbnmbnmbCgbChbCibCjbCkbClbClbCmbClbCnbCobCpbCqbAEbvjbCrbvlbvlbvlbCsbvjbikbAIbAJbCtbCubCvbCwbCxbCybCzbCAbEsbvwbEtbucbvxbCDbCEbCFbCGbCHbCIbCJbCKbCLbCMbCNbCObCPbCQbCRbCSbCTbzlbCUbCVbuhbCWbCXbCYbCZbDabDbbDcbvVbukbIcbDebDfbDgbDgbDhbDibDjbDkbDlbDmbDnbDobDpbDqbupbDrbBxbDsbusbDtbDubDvbxUbxUbDwbusbxWbxXbDxbwobikbikbikbikaabbDAbFfbDBbFfbDBbFfbFgaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaIndjudjubDEaInaInaLyaCubDFbDGbrXbDHbycbycbycbrXbrXbrXbikbikbikdewdevdevdexdevdevdewbikbikbBRbDIbAebDJbDKbDKbDKbDKbDKbDLbDMbDKbDNbDObDPbDQbDRbDSbDTbnmbDUbpIbDVbDWbtLbDXbDYbDZbCjbCjbCpbEabEbbEcbEdbEebCpbvibAEbvjbEfbEgbEhbqtbEjbvjbikbEkbAJbElbEmbEnbEobEpbEobEqbErbFWbvwbHBbucbEubEubEvbEwbExbEybEzbEAbEBbECbEDbEDbEEbEFbEGbEHbuhbCTbEIaJSbuhbuhbuibEKbELbEMbuibukbukbukbENbIdbvXbEPbBkbBlbEQbDgbDjbERbESbESbETbxJbEUbEVbEWbEXbxPbEYbusbEZbFabxUbFbbFcbFdbusbzMbFebwobwobikbikbikbikaabbFhbFjbFibGSbFkbGTbFhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjydjydjydjydjAdjzdjydjydjydjydjBbikbikbikbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevdewbFnbBRbBRbFobFpbFqbFrbFrbFrbFpbAebyvbAfbAebAebAgbFsbFtbFubFvbFwbFxbFybpIbpIbFzbtLbDXbDYbFAbFBbFCbFDbFEbFFbFGbFHbFIbCpbFJbFKbwRbFLbFMbFNbFObFPbwXbwYbFQbAJbFRbFSbFTbEobFUbEobFVbErbJebvwbKObucbFYbFZbGabGbbGcbGdbGebGfbGgbGgbGhbGibGgbGgbGjbGkbGlbGmbGnbGobGpbGqbGrbGsbGtbGubGvbGwbKhbIebKjbKibvXbGBbGCbGDbGEbGFbxGbGGbESbESbGHbGIbEUbGJbupbGKbGKbGLbusbGMbGNbGObGPbxUbGQbusbzMbGRbwobikbikbikbikbikaabbGUbIybFibFkbFibKkbDBaabbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjCdjEdjDdjGdjFdjIdjHdjFdjJdjLdjKdjydjydjBbikbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevbGWbmrbNkbmrbGXbGYbGZbGYbGYbGYbGYbHabyvbAfbHbbngbngbHcbpIbAibFvbHdbtLbHebHfbHfbHgbHhbHibHjbHkbHlbHmbHnbHobHpbHqbHrbHsbCpbCqbAEbvjbEibHubHvbHwbHxbvjbikbEkbHybHzbHybHybHybHybHybHAbHybKPbvwbKObucbHCbHDbHDbHEbHFbEybHGbHHbHIbHJbHKbHLbHMbHIbHNbHObHPbHQbHRbHSbHTbHTbHUbHVbHWbHXbHYbLibLCbLBbNdbNcbNebIfbIfbIgbIhbIibxGbIjbxJbxJbIkbIlbEUbImbInbIobIpbIqbIrbIsbItbIubIvbIubusbusbIwbEXbGxbLDbLDbLDbLDbLDbGxbFhbFkbFibFkbFkbGTbFhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjydjHdjHdjHdjMdjFdjNdjNdjFdjOdjHdjHdjQdjPdjydjBbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevbLFbKmbIAbKmbIBbAebFqbFrbFrbFrbAebAebyvbAfbICbKobngbIEbpIbAibFvbIFbtLbIGbpIbrsbpIbIHbDXbvvbIIbHlbHmbIJbIKbILbIMbINbIObIPbIQbIRbISbISbITbIUbIVbvjbvjbikbEkbHybIWbIXbIYbIZbJabJbbJcbJdbMhbvwbKObCHbJfbJgbJhbJibJjbEybJkbJlbJmbJnbJobJpbJqbJrbJsbJtbJubJvbJwbJxbJybJzbJAbJBbJCbJDbJEbGwchEbIecnfcjubvYbJIbJJbJKbJLbJLbxGbJMbJNbJObxGbJPbEUbJQbxGbJRbJSbJTbJUbJVbJWbJXbJYbJZbKabKbbKcbKdbKebKfbKfbIxbJFbJHbKgbKlbFfbDBbNhbDBbFfbLEaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjydjHdjHdjHdjMdjFdjNdjNdjFdjOdjHdjHdjQdjPdjydjBbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevbLFbKmbIAbKmbIBbAebFqbFrbFrbFrbAebAebyvbAfbICbKobngbIEbpIbAibFvbIFbtLbIGbpIbrsbpIbIHbDXbvvbIIbHlbHmbIJbIKbILbIMbINbIObIPbIQbIRbISbISbITbIUbIVbvjbvjbikbEkbHybIWbIXbIYbIZbJabJbbJcbJdbMhbvwbKObCHbJfbJgbJhbJibJjbEybJkbJlbJmbJnbJobJpbJqbJrbJsbJtbJubJvbJwbJxbJybJzbJAbJBbJCbJDbJEbGwchEbIecnfcjubvYbJIbJJbJKbJLbJLbxGbJMbJNbJObxGbJPbEUbJQbxGbJRbJSbJTbJUbJVbJWbJXbJYbJZbKabKbbKcbKdbKebKfbKfbIxbJFbJHbGzbKlbFfbDBbNhbDBbFfbLEaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjydjSdjRdjUdjTdjVdjFdjWdjHdjXdjHdjHdjHdjHdjHdjMdjFbikbikbikbikbikbikbikbikbikbikdewdeCdevdevdevcOfdewbFnbBRbBRdezbAebFqbAebAebAebAebAebyvbAfbICbLwbngbLQbpIbKqbKrbpIbKsbpHbpIbpIbKtbtLbDXbvvbIIbHlbHmbCpbKubKvbqzbKxbKybKzbKAbKBbKCbKDbwXbKEbKFbwXbwYbwYbKGbHybKHbKIbKJbKKbKLbKLbKMbKNbMibvwbMjbucbEybKQbEubKRbKSbEybJkbKTbKUbKVbKWbKXbKYbKUbJkbKZbLabLbcchbLbbLcbLbbLdbLdbLebLfbLgbLhbLhcpLbLgbLgbLhbLhbLjbLkbLjbLjbxGbxGbxGbxGbxGbLlbLmbBobxGbLnbLobLpbLqbLqbLrbLsbLtbLubLvbLIbLxbLybLzbLAbLAbEObGAbHZbGxbGzbGzbGzbIabGxbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjZdjYdjHdjHdkadkadkadjFdjHdjHdjFdkbdkddkcdkfdkedkgdjFbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevbWobKmbIAbKmbFobLGbLHbAebAebAebLGbAebyvbAfbICbNrbngbLJbpIbAibFvbpIbnmbLKbpIbpIbLLbtLbDXbvvbLMbHlbLNbCpbLObLPbWDbLRbLSbKzbLTbLUbLVbLWbLXbLYbLZbMabikbikbikbHybMbbMcbMdbMdbMebMfbMgbHybNSbNRbKObNTbMkbMlbMmbMnbMobMpbMqbJlbMrbMsbMtbMubMvbMrbJkbKZbMwbMxbMybMzbMAbMBbLdbMCbMDbMEbLgbMFbMGbMHbMIbMJbMKbMLbKabMMbLqbLqbMNbMObLqbMPbMQbMRbMSbMTbLqbMUbiTbMWbMXbMYbMZbNabNbbNabNabNabIwbEXbGxbLDbLDbGxcnccndcnebOQbOSbUHbYdbGzbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkhdjYdjHdjHdjHdjHdjHdkidjHdjHdjFdjydjydjydjydjydjydkjbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevdeEdeDdeGdeDbNlbNmbNnbNnbNnbNnbNnbNobNpbNqbICbWSbngbNsbNtbNubNvbNwbNxbNybNybNybNzbNzbNAbvvbNBbNCbHmbCpbNDbNEbNFbKvbNGbKzbNHbNIbNJbNKbNLbFNbNMbMabikbikbikbHybNNbNObNPbNQbMebMfbMgbHybPibNUbQObPjbNVbNWbNXbNYbNZbOabObbOcbKUbKUbOdbOebKUbKUbJkbKZbOfbOgbOhbOibOjbOkbLdbOlbOmbOnbOobOpbOqbOrbOrbOsbOtbOubOvbOwbJVbJVbOxbJVbOybJVbOzbJVbOAbOBbOBbOCbODbOEbOFbOGbOHcsjbOJbOKbOLbNabOMbONbikbikbikbGxbORbJFbOPbOQbKgbOObNibGxbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkmdkldkodkndjHdjFdjHdjHdjFdjHdkqdkpdkrbikbikbikbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevdewbFnbBRbBRbngbngbBRbBRbBRbBRbBRbngbngbBRbBRbBRbngbOVbOVbOVbOWbOVbNzbOXbOYbOZbPabNzbDXbvvbPbbPcbPcbCpbCpbCpbCpbCpbPdbKzbISbIRbPebNKbPgbPhbMabMabvjbvjbvjbHybHzbHybHybHybHybHybHybHybQPbvwbQQbPkbPlbPmbPnbPlbPlbPobPpbPqbPrbPsbPtbPubPvbPwbMqbPxbPybPzbPAbPBbPCbPDbPEbPFbPGbPHbPIbPJbPKbPLbMHbPMbLhbLhbPNbPObPNbPPbPQbPPbPPbPPbPRbPSbPTbPTbPUbPVbPWbPXbOFbPYbPZbQabQbbQcbQdbNabOMbONbikbikbikbGxbNfbNgbGxbKgbGxbGxbKgbGxbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjZdjYdjHdjHdkadkadkadjFdjHdjHdjFdkbdkddkcdkfdkedkgdjFbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevbWobKmbIAbKmbFobLGbLHbAebAebAebLGbAebyvbAfbICbNrbngbLJbpIbAibFvbpIbnmbLKbpIbpIbLLbtLbDXbvvbLMbHlbLNbCpbLObLPbWDbLRcobbKzbLTbLUbLVbLWbLXbLYbLZbMabikbikbikbHybMbbMcbMdbMdbMebMfbMgbHybNSbNRbKObNTbMkbMlbMmbMnbMobMpbMqbJlbMrbMsbMtbMubMvbMrbJkbKZbMwbMxbMybMzbMAbMBbLdbMCbMDbMEbLgbMFbMGbMHbMIbMJbMKbMLbKabMMbLqbLqbMNbMObLqbMPbMQbMRbMSbMTbLqbMUbiTbMWbMXbMYbMZbNabNbbNabNabNabIwbEXbGxbLDbLDbGxcnccndcnebOQbOSbUHbYdbGzbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkhdjYdjHdjHdjHdjHdjHdkidjHdjHdjFdjydjydjydjydjydjydkjbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevdeEdeDdeGdeDbNlbNmbNnbNnbNnbNnbNnbNobNpbNqbICbWSbngbNsbNtbNubNvbNwbNxbNybNybNybNzbNzbNAbvvbNBbNCbHmbCpbNDbNEbNFbKvbNGbKzbNHbNIbNJbNKbNLbFNbNMbMabikbikbikbHybNNbNObNPbNQbMebMfbMgbHybPibNUbQObPjbNVbNWbNXbNYbNZbOabObbOcbKUbKUbOdbOebKUbKUbJkbKZbOfbOgbOhbOibOjbOkbLdbOlbOmbOnbOobOpbOqbOrbOrbOsbOtbOubOvbOwbJVbJVbOxbJVbOybJVbOzbJVbOAbOBbOBbOCbODbOEbOFbOGbOHcsjbOJbOKbOLbNabOMcxHbikbikbikbGxbORbJFbOPbOQbGzbOObNibGxbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkmdkldkodkndjHdjFdjHdjHdjFdjHdkqdkpdkrbikbikbikbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevdewbFnbBRbBRbngbngbBRbBRbBRbBRbBRbngbngbBRbBRbBRbngbOVbOVbOVbOWbOVbNzbOXbOYbOZbPabNzbDXbvvbPbbPcbPcbCpbCpbCpbCpbCpbPdbKzbISbIRbPebNKbPgbPhbMabMabvjbvjbvjbHybHzbHybHybHybHybHybHybHybQPbvwbQQbPkbPlbPmbPnbPlbPlbPobPpbPqbPrbPsbPtbPubPvbPwbMqbPxbPybPzbPAbPBbPCbPDbPEbPFbPGbPHbPIbPJbPKbPLbMHbPMbLhbLhbPNbPObPNbPPbPQbPPbPPbPPbPRbPSbPTbPTbPUbPVbPWbPXbOFbPYbPZbQabQbbQcbQdbNabOMcxHbikbikbikbGxbNfbNgbGxbGzbGxbGxbGzbGxbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjydjydjydjydjydjydjFdjOdjHdksdjHdkudktdkvbikbikbikbikbikbikbikbikbikbikbikbikbikdeJdeIdevdeKdevdeLdeMbikbikbikbikbikbikbikbikbikbikbQgaabbikbikbikbikbOVbQhbQibQjbQkbNzbQlbQmbQnbQobNzbDXbvvbQpbQqbQrbQsbQtbQubQvbQwbQxbQybQzbQAbQBbQCbQDbQEbQFbQGbQHbQIbQJbQKbQLbQMbQRbuabQSbvwbShbSgbSibvwbSjbPlbQTbQUbQVbQWbQXbJkbQYbQZbRabRbbRcbRdbRebRfbRgbRhbRibLbbRjbOibRkbRlbRmbRnbRobRpbLgbRqbMHbMHbMHbRrbLhbPNbRsbRtbRubRvbRwbRxbRybPPbRzbRAbRBbPTbPTbRCbPWbRDbREbWHbRGbRHbRIbRJbRKbNabRLbwobikbikbikbGxbGxbGxbGxbikbikaabbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjydkxdkwdkydkxdkzdjFdjHdjHdjFdjHdkBdkAdkCbikbikbikbikbikbikbikbikbikbikbikbikbikdeOdeNdePdePdePdeNdeQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbOVbRMbRNbRObRPbNybRQbRRbRSbRTbNzbDXbRUbRVbvvbvvbFXbRWbubbQNbQMbRXbRYbRXbRZbSabSabSbbScbSdbSabSabSebSabSfbSabQMbQRbuabSlbSkbTJbTIbTLbTKbvwbPlbSmbQUbSnbSobSpbJkbSqbSrbSsbStbSubSvbSwbSxbJkbSybSzbLbbSAbSBbSBbSCbSDbSEbSFbSGbLgbSHbSIbMHbSJbSKbLhbPNbSLbSMbSNbSObSPbSQbSRbPPbSSbRAbSTbSTbPTbSUbSVbSWbSXbSYbSZbTabTbbTcbTdbNabOMbwobTebikbikbikbikbikbikbikbikaabbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjZdjYdkDdkDdkDdkDdkDdkEdjHdjHdjFdjydjydjydjydjydjydjBbikbikbikbikbikbikbikbikbikbikbikdeRdeSdeSdeSdeTbikbikbikbikbikbikbikbikbOUbOTbQebOTbQfbikbikbikbOVbOVbTjbTkbRObTlbNybTmbQnbTnbTobNzbDXbTpbTqbTrbTsbTtbTubTvbTwbTxbTybTzbTAbTBbTCbTCbTDbTEbTEbTEbTEbTEbTEbTFbTGbTHbTNbTMbTPbTOdlidjmdlkdljdllbPlbTQbQUbQVbTRbSpbJkbSqbSrbTSbTTbTUbTVbTWbTXbJsbTYbTZbLbbLbbUabUabLbbSDbLdbUbbUcbLgbUdbUebUfbUgbUhbLhbPNbUibUjbUkbUlbUmbUnbUobPPbUpbRAbSTbSTbPTbUqbUrbUsbUtbUubUvbUwbUxbUybUzbNabOMbUAbUBbUAbUCbUDbUCbUCbUCbikbikbikbikaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikaabaabaabaabaabbikbikbikbikaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkhdjYdkDdkDdkDdkFdkGdjFdjHdjHdjFdjHdjHdjHdkHdjHdkIdjFbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbTgbTfbTibThbTgbUIbUIbUIbOVbUJbUKbULbUMbUNbUObUPbUQbUQbURbNzbUSbUTbUUbUVbUVbUWbUXbUYbUVbUZbUZbVabVbbVcbUZbUZbVdbQMbQMbVebVfbVfbVfbVgbVhbVfbVfbVibVjbVkbVkbVlbVkbVmbVnbVkbVobVpbVqbPlbVrbVsbSqbVtbVubVvbVwbVxbVybVubJkbSybVzbVAbVBbVCbVDbVEbVFbVGbVHbVIbVJbVKbVLbVMbVNbVObLhbPNbPNbVPbVQbVRbVSbVRbVTbPPbVUbVVbVWbVWbPTbVXbVYbVZbNabNabNabNabNabNabNabNabOMbUAbWabWbbWcbWdbWdbWebUCbikbikbikbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikaabbWfbWfbWfbWfbWgbWgbWhbWhbWhbWhbWiaabaabbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkhdjYdkDdkDdkDdkFdkGdjFdjHdjHdjFdjHdjHdjHdkHdjHdkIdjFbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbTgbTfbTibThbTgbUIbUIbUIbOVbUJbUKbULbUMbUNbUObUPbUQbUQbURbNzbUSbUTbUUbUVbUVbUWbUXbUYbUVbUZbUZbVabVbbONbUZbUZbVdbQMbQMbVebVfbVfbVfbVgbVhbVfbVfbVibVjbVkbVkbVlbVkbVmbVnbVkbVobVpbVqbPlbVrbVsbSqbVtbVubVvbVwbVxbVybVubJkbSybVzbVAbVBbVCbVDbVEbVFbVGbVHbVIbVJbVKbVLbVMbVNbVObLhbPNbPNbVPbVQbVRbVSbVRbVTbPPbVUbVVbVWbVWbPTbVXbVYbVZbNabNabNabNabNabNabNabNabOMbUAbWabWbbWcbWdbWdbWebUCbikbikbikbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikaabbWfbWfbWfbWfbWgbWgbWhbWhbWhbWhbWiaabaabbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkKdkJdkDdkLdkMdjFdjHdjHdkNdjHdjHdjHdkOdjHdkPdjFbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbQebUEbUFbUEbQebUIbWmbWlbOVbWnbWpbWqbWrbWsbNzbWtbWubWvbWwbNzbUTbUTbWxbUVbWybWzbWAbWBbWCbUZdmdbWEbWFbWGcAzbUZbWIbWJbWKbVfbWLbWMbWObWNbWPbWQbWRceLbWTbWUbWVbWWbWXbWYbWZbXabXbbXcbXdbXebXfbXgbXhbSrbXibXjbXkbXlbXmbXnbJsbXobXpbXqbXrbVDbXsbXsbXtbXubLgbXvbXwbXxbXybXzbXAbXBbLhbXCbXDbXEbXFbXEbXEbXGbXHbXIbXJbXKbXLbXMbPTbXNbXObPXbEXbxXbXPbXQbXRbXRbXQbXRbXSbUAbXTbXUbWcbWdbXWbXVbUCbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWfbXXbXYbXXbWgbWhbWhbXZbYabXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkQdkDdkDdkRdjFdjHdjHdjFdkSdjHdjHdkUdkTdjydkjbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbTgbUGbUEbUEdeycOWbTkbTkdeAbZAbTkbWqbYhbYibNzbNzbNzbNzbNzbNzbYjbUTbYkbYlbYmbYnbYnbYnbYobUZbYpbYqbYqbYqbYrbYsbYtbYubYvbYwbYxbYybYzbYAbYBbYCbVfbVibYDbVkbYEbYFbYGbYHbYIbVkbSmbQVbSnbSobYJbYKbYLbYMbYNbYObYPbYQbYRbVubYSbYTbYUbYVbYWbYXbYYbYZbZabZbbLgbLgbLgbLgbLgbZcbZdbZebLhbZfbXEbXEbZgbZhbXEbZibZjbZkbZlbRAbZmbZmbPTbPVbZnbPXbEXbUAbZobUAbUAbUAbUAbUAbUAbUAbZpbZqbUCbZrbZtbZsbUCaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacbZubXXbXXbZvbWhbWhbXZbXZbZwbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkWdkVdkXdjFdjHdkYdjFdkZdladjHdjydjydkjbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbQebUFbUFbUFbQebUIbYfbYebZzbZAbTkbZBbZCbZDbZEbZFbZFbZFbZGbUTbUTbUTbWxbUVbZHbYnbZIbYnbZJbUZbYpbYqbZKbYqbZLbUZbZMbZNbZObVfbZPbZQbZRbZSbZTbZUbZVbZWbZXbZYbZZcaacabcaccadbVkbTQbQVbQVcaebYJbYKcafcagcahbXjcaicajcElcalcamcancaocapcaqcarcIfcasbXscatbVAcaucavcawcaxcaycazcaAbZjbZfcaBbXEbXEbXEcaCcaDbZjbZkcaEbRAbZmbZmbPTcaFcaGbPXbEXcaHcaIcaJbUAcaKcaLcaMcaNcaOcaPcaQbUCcaRcaScaTbUCbUAbUAbUAbUAbUAbUAbUAbUAbikbikbikbikbikaabbikbikbikbikbikbikbikcaUbWhbZubWhbWhbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydjydjydjydjydjydjydjydjydjydkjbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbTgbWjbYbbWkbTgbUIbUIbUIbOVcaYcaZcaZcaZbOVbOVbUTcbacbacbbcbcbUTcbdcbebUVbZHbYnbYnbYncbfbUZbYpbYqbYqcbgcbhcbicbjcbkcblbVfbVfbVfbVfbVfcbmbVfbVfcbncbobVkbVkcbpbVkbVnbVkbVkbPlcbqcbqbPlccicbrcbscbtcbucbvcbwcbxcbycbzcbAcbBcaocapcbCcbDcbEcbFcbGcbHbVAcbIcbJcbKcbLcbMcbNcbOcbPcbQcbPcbRcbRcbRcbPcbScbPcbPcbTcbUbZmbZmbPTcbVbZnbPXcbWcbXcbYcbZccaccbccccccccdcceccfccgcckccjcdqcclcfeccmccnccoccpccqccrccscctaabaabaabaabaabaabaabaabbikbikbikbikbikbWgbWhccuccvccvbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbYcbOTbYgbOTbZxbikaabbikbOVbOVbUIbUIbUIbOVbikbUTccAccBccCccDbZFccEccFbUVccGccHccIbYnccJccKccLccMccNccOccPbUZccQccRccSccTccUccUccUccUccVccWccXccYccYccZccZcdacdbcdcbVibPlcddcdecdfcdgcdhbYKcdicbtcdjcdkcdlcdmbSwcdncdocdpcffcdrcdrcdscdrcdrcdrcdtbVAcducdvcdwcdxcdycdzcdAcbPcdBcdCcdDcdEcdFcdCcdGcdHcdCcdIcdJbRBbPTbPTcdKcdLcdMcdNcdOcdPcdQcdRcdScdTcdUcdVcdWcdXcdYcdZceacebceaceccebcebcebcedceecefcegcehaabbikbikbikbikaabbikbikbikbikbikbikbikbWhbWhceibXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabaabaabaabaabaabaabaabaabaabaabaabaabaabaabaabcejbUTbUTbUTcekbUTbUTcelbUVcemcenceocepceqcercescetceucevcewccKcexceycezceAceBceBceBceBceCceDceEceFceGceFceHceIceJceKchvceMceNceOcePceQceRceSceTceUceVceWceXceYceZcfacfbcfccfgbMmbMmcfichOcgHceYchVcfjcfjcfkcfjcflcfmcfncfocbPcfpcfqcfrcfscfrcftcfucfvcdCbPTcfwbPTbPTcfxcfybZnbBxbEXbUAcfzbUAbUAcfAcfBcfCcfDcfEcebcfFcfGcfHcdUcfHcdUcfIcdUcdUbUAcfJcfKcfLcfMaabaabaabaabaabaabaabaabbikbikbikbikbikbWhbXZbXZbXZbXZbXZbXZcfNbXZcfObXZbXZbXZbXZbXZbWhbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcejcfPcfQcfRbUTcfSbUVcfTcfUcfVbZHcfWcfXcfYbYpcfZcgacgbcfXcgccgdcgecgfcgfcggcghcgicgjcgkcglcgmbGycgnbVicgobGybGycgpcgqcgrcgscgtceQcgucgvcgwcgxcgycgzbMVcgBcgCcgzcgzcgDcgEcgEcgEcgEcgEcgGcgFciOcgJcgJcgKcgLcgMcgNcgOcgPcbPcgQcgRcgScgTcgScgUcgVcfrcgWcgXcgYbBxcgZbBxcfybZnbBxbEXchachbchcbUAbUAbUAbUAbUAchdcdUchechfcfIcdUchgcdUbZpcdUchhbUAchichjchkbUAaabbikbikbikbikaabbikbikbikbikbikbikbikbWhchlchlchlchlchlchlchmbXZchnchlcfObXZbXZbXZbXZbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcejchochpchqbUTcfSchrchrchrchrchrchrbUZbUZbUZbUZbUZbUZbUZchschtchucWpchwchxchychychzchAcglbGybGychBchCchDbGybGybGycqOchFchGceOchHchIchJcgEchKchLchMbSqchLchNcfdcfdcfdcjncjlcjlcjlcjlckacgIbSqclPchPchQchRchSchTchUclQcbPchWchXcfrchYcfrchZciacibciccidciecifbBxcigcfybZncihbEXbFeciicijcikbwobxXbxXbUAcilcimcinciocipciqcirciscitciucivbUAciwciycixcizbikbikbikbikaahbikbikbikbikbikbikbikbikciAbXXbXXbXXbXXbXXbXXbXXciBciCbXZbXZbXZbXZciDbYabWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcejcfPbVccqsbUTcfSbUVcfTcfUcfVbZHcfWcfXcfYbYpcfZcgacgbcfXcgccgdcgecgfcgfcggcghcgicgjcgkcglcgmbGycgnbVicgobGybGycgpcgqcgrcgscgtceQcgucgvcgwcgxcgycgzbMVcgBcgCcgzcgzcgDcgEcgEcgEcgEcgEcgGcgFciOcgJcgJcgKcgLcgMcgNcgOcgPcbPcgQcgRcgScgTcgScgUcgVcfrcgWcgXcgYbBxcgZbBxcfybZnbBxbEXchachbchcbUAbUAbUAbUAbUAchdcdUchechfcfIcdUchgcdUbZpcdUchhbUAchichjchkbUAaabbikbikbikbikaabbikbikbikbikbikbikbikbWhchlchlchlchlchlchlchmbXZchnchlcfObXZbXZbXZbXZbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcejchocfQchpbUTcfSchrchrchrchrchrchrbUZbUZbUZbUZbUZbUZbUZchschtchucWpchwchxchychychzchAcglbGybGychBchCchDbGybGybGycqOchFchGceOchHchIchJcgEchKchLchMbSqchLchNcfdcfdcfdcjncjlcjlcjlcjlckacgIbSqclPchPchQchRchSchTchUclQcbPchWchXcfrchYcfrchZciacibciccidciecifbBxcigcfybZncihbEXbFeciicijcikbwobxXbxXbUAcilcimcinciocipciqcirciscitciucivbUAciwciycixcizbikbikbikbikaahbikbikbikbikbikbikbikbikciAbXXbXXbXXbXXbXXbXXbXXciBciCbXZbXZbXZbXZciDbYabWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcejcejcejcejbUTcfScejbikbikbikbikciEbaTciGciHciIciJciKciLciMciNcmPciPciQciRciSciSciTciUciVciWciWciWciWciXciWbGybGybPlciYciZcjacjbcjccjdchScjecjfcjgcjhcjicjjcjkcjlcfdcnicjpcjpcjpcjpckNclSckUcnjcjqcjrcjscjtcbAcwncjvcbPcjwcjxcjycjzcjAcfrcjBcbPcbPbEXcjCbEXbEXbEXcjDcjEcjFbEXbxXciicjGcjHbwobwobwobUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbikbikbikbikbikaabbikbikbikbikbikbikbikbWhccvccvccvccvccvccvcjIbXZccuccvcjJbXZbXZbXZbXZbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcAjbikaabaabcjKcjKcjKcjKcjKcjKcjLcjKbUTcelcjMbikcjNcjOcjPcjQcjRcjScjTcjUcjVcjWcjXcjYcjZcosckbckcckdckeckfckgckhciVckickjckjckjckkciWbGybGycklcklcklcklckmcklckncknckocklcklckpcklckqckrckscktcksclZaPKcmacmmcmlcmocmnckzckAckBckCckDckEckFcdccbPcbPckGcbPckHcbPckIckJckKcgnckLckMckvckOckPckQckRckSckPbxXciickTbxXbxXckVckWckXchabxXbxXbxXbxXbxXbxXbxXckYckZbONbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhbXZbXZbXZbXZbXZbXZcfNbXZcjJbXZbXZbXZbXZbXZbWhbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikclaclbclbclbclccldcleclfclgclhclicjLcljcelcjMbikclkcllclmclnclocjSclpclqclrclsciLcltcgdcoaciPcluchyclvchyclwclxclyclzclAclAclAclBciWbGybGycklclCclDclEclFclGclHclHclIclJclKclLclMclNclOcotcfhcpwcmpcmrcmqctbcsZcuoctcckDclVclWclXckzclYcmtcmscmbcmbcmccmdcmecmfcmgcmhcmfcmfcmfcmicmfcmfcmjcmucnpcnlcqRcoXcrGcqScrHcrHcrIcrHcrHcrHcrHcrJcrKcrHcrHcrHcrMcmvbxXbONbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhbWhceibXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcmwcmxcmxcmxcmxcmycmzcmAcmBcmCcmCcmDcjKcmEcfScjMbikclkcmFcmGcmHcmIcmJcmKcmLcmIcmIcmMcmNcmOcpxcmQcmQcmRbHtchycmTcmUclyclAclAclAclAcmVciWbGybGycklcmWcmXcmYcmZcnacnbcnbbzsbvWbulbxBclHcnhcklcqQcfdcrLcjpcwscvxcwEcwCcxNcxIckDcnmcnncnockDbJGcumctecnqcnqcnqcnqcnqcnrcnscntcnucnvcnvcnwcnwcnvcnxcnycnzcnAcnBcnCcnDcnEcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcuncnFcnGbONbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcaUbWhbWhchlchlbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcnHcnIcnJcnKcnJcnLcnMcnNcnOcnPcnQcjKcnRcelcjMbikclkcnScnTcnUcnVcjScnWcnXcnYcnZciLcltcgdcbkcobcgfcoccodciPciPciPcoecofclAclAcogcohciWbGycoicklcojcokcolcomcomcomconcoocomcomcopclHcoqcorcrNcfdcupcjpcxVcxUcxVcxVcxNcEickDcowcoxcoyckDcozcuscoicoAcoAcoAcoAcoAcoDcoDcoDcoAcoAbikbikbikbikckPcoEcoFcoGcnCcoHcoIcoJcoKcoLcoMcoNcoOcoPcoQcoRcoScoTcoUcnCcuncoWcvtcoYcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcpacpbbWhbZubWhbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikcnHcpccpdcpecpfcmBcpgcphcpicmBcpjcpkcplcpmcjMbikcpncjOcpocjQcppcjScjScpqcprcpscptcpucpvcwqcobcgfcpycpzcpAcpBcpCciVcpDclAclAclAcpEciWbGybGycpFcpFcpGcpHcpIcpIcpIcyFcpJcpJcpJcpKcpFcpGcpMcqQcfdcrLcEjbjVcEYdbndbmcxNclRckDcoucpNcovckDbGycuscoAcoAaabaabbikbikbikbikbikbikbikbikbikbikbikcpRcpScpTcpUcpVcpWcpXcpXcpYcpXcpXcpXcpXcpXcpZcqacqbcqccqdbwocvvbXSbwobwoaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhcqhcqicqjbWhbWhbXZbXZcqkbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcAjbikaabaabcjKcjKcjKcjKcjKcjKcjLcjKbUTcelcjMbikcjNcjOcjPcjQcjRcjScjTcjUcjVcjWcjXcjYcjZcosckbckcckdckeckfckgckhciVckickjckjckjckkciWbGybGycklcklcklcklckmcklckncknckocklcklckpcklckqckrckscktcksclZaPKcmacmmcmlcmocmnckzckAckBckCckDckEckFcdccbPcbPckGcbPckHcbPckIckJckKcgnckLckMckvckOckPckQckRckSckPbxXciickTbxXbxXckVckWckXchabxXbxXbxXbxXbxXbxXbxXckYckZcxHbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhbXZbXZbXZbXZbXZbXZcfNbXZcjJbXZbXZbXZbXZbXZbWhbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikclaclbclbclbclccldcleclfclgclhclicjLcljcelcjMbikclkcllclmclnclocjSclpclqclrclsciLcltcgdcoaciPcluchyclvchyclwclxclyclzclAclAclAclBciWbGybGycklclCclDclEclFclGclHclHclIclJclKclLclMclNclOcotcfhcpwcmpcmrcmqctbcsZcuoctcckDclVclWclXckzclYcmtcmscmbcmbcmccmdcmecmfcmgcmhcmfcmfcmfcmicmfcmfcmjcmucnpcnlcqRcoXcrGcqScrHcrHcrIcrHcrHcrHcrHcrJcrKcrHcrHcrHcrMcmvbxXcxHbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhbWhceibXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcmwcmxcmxcmxcmxcmycmzcmAcmBcmCcmCcmDcjKcmEcfScjMbikclkcmFcmGcmHcmIcmJcmKcmLcmIcmIcmMcmNcmOcpxcmQcmQcmRbHtchycmTcmUclyclAclAclAclAcmVciWbGybGycklcmWcmXcmYcmZcnacnbcnbbzsbvWbulbxBclHcnhcklcqQcfdcrLcjpcwscvxcwEcwCcxNcxIckDcnmcnncnockDbJGcumctecnqcnqcnqcnqcnqcnrcnscntcnucnvcnvcnwcnwcnvcnxcnycnzcnAcnBcnCcnDcnEcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcuncnFcnGcxHbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcaUbWhbWhchlchlbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcnHcnIcnJcnKcnJcnLcnMcnNcnOcnPcnQcjKcnRcelcjMbikclkcnScnTcnUcnVcjScnWcnXcnYcnZciLcltcgdcbkchqcgfcoccodciPciPciPcoecofclAclAcogcohciWbGycoicklcojcokcolcomcomcomconcoocomcomcopclHcoqcorcrNcfdcupcjpcxVcxUcxVcxVcxNcEickDcowcoxcoyckDcozcuscoicoAcoAcoAcoAcoAcoDcoDcoDcoAcoAbikbikbikbikckPcoEcoFcoGcnCcoHcoIcoJcoKcoLcoMcoNcoOcoPcoQcoRcoScoTcoUcnCcuncoWcvtcoYcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcpacpbbWhbZubWhbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikcnHcpccpdcpecpfcmBcpgcphcpicmBcpjcpkcplcpmcjMbikcpncjOcpocjQcppcjScjScpqcprcpscptcpucpvcwqchqcgfcpycpzcpAcpBcpCciVcpDclAclAclAcpEciWbGybGycpFcpFcpGcpHcpIcpIcpIcyFcpJcpJcpJcpKcpFcpGcpMcqQcfdcrLcEjbjVcEYdbndbmcxNclRckDcoucpNcovckDbGycuscoAcoAaabaabbikbikbikbikbikbikbikbikbikbikbikcpRcpScpTcpUcpVcpWcpXcpXcpYcpXcpXcpXcpXcpXcpZcqacqbcqccqdbwocvvbXSbwobwoaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhcqhcqicqjbWhbWhbXZbXZcqkbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcnHcqlcnJcqmcnJcqncqocqpcqqcnNcqrcjKcqscelcejbikbikbikbikciEcqtcqucqvcqvciLcqwciLcqxcgdcbkcqycqzcqAcqBcqCcqCcqCcqDcqEclAcqFclAcqGciWbGybGycpFcqHcqIcqJcqKcqLcqMcpFcqLcqMcqKcqNdehcqPcpMczecyWczgcEjdbpdbodbrdbqdbsctcckDcpOcpPcpQckDbGycuscoAcvyaabaabaabbikbikbikbikbikbikbikbikbikbikcpRcqUcqVcqWcqXcqYcqZcracrbcpXcpXcrccpXcpXcpZcqbcqbcqbcrdbwocvzbxXbwoaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWfcrhcribZvbWgbWhbWhbXZbYabXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikadbabLcrjcrjcrjcrjcrjcrjcrjcrjcrkcrkcrkcrkcrkcjKcjKcjKcjKcjKcjKcjKcekcrlcrmcrmcrmcrmcrmciEciLciLciLciLciLciLciLcrncgdcbkcrocrpcrqcrrcrscrtcrucrvcrwcrxcrycrzcrAciWbGybGycpFcrBcrCcqJcqKcqKcrDcpFcrEcqKcqKcqNcqKcrFcpMbGwbGwbGwcEjdbudbtdbvdbmdbxctcdbydbydbycoAcoAbGycuscoDcwpbikaabaabaabbikbikbikbikbikbikbikbikbikcpRczNczPcoBcrOcrPcrQcrRcrScpXcpXcpXcpXcrTcrUcrVcrWcrXcrYbwocvzbxXbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWfbWfbWfbWfbWgbWgbWhbWhbWhbWhbWiaabaabbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikaSecsdcsecsfcsgcsgcshcsicspcskcslcsmcsncsocsrcsqcsqcsscsucstctzctzctAcsvcswcsxcsycsxcsxcsxcswcsxcsxcszcsAcsBcsCcgdcbkcsDcsEcsFcsGcgfcsHcmQcsIcsJcsKcsLcsMcsNcsObGybGycpFcsPcsQcsRcsScsTcsUcpFcsVcsTcsWcsXdlFcsYcwrbikbikbikcEjdbAdbzdbAdbAdbCdbBdbEdbDdbycwFbVibGycuscoDcwpbikbikaabaabaabbikbikbikbikbikbikbikbikctdckPcxGckSctdctfctgcthctictjctkctlcpXcpXctmctnctoctpctqbwocvzbxXcxHbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikaabaabaabaabbikbikbikbikaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 212a19f79e8..f57e096e0ec 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -2,8 +2,8 @@ #define STOPSPRESSUREDMAGE 1 //This flag is used on the flags variable for SUIT and HEAD items which stop pressure damage. Note that the flag 1 was previous used as ONBACK, so it is possible for some code to use (flags & 1) when checking if something can be put on your back. Replace this code with (inv_flags & SLOT_BACK) if you see it anywhere To successfully stop you taking all pressure damage you must have both a suit and head item with this flag. #define NODROP 2 // This flag makes it so that an item literally cannot be removed at all, or at least that's how it should be. Only deleted. #define NOBLUDGEON 4 // when an item has this it produces no "X has been hit by Y with Z" message with the default handler -#define AIRTIGHT 8 // mask allows internals -//#define USEDELAY 16 // 1 second extra delay on use (Can be used once every 2s) +#define AIRTIGHT 8 // mask allows internals +#define HANDSLOW 16 // If an item has this flag, it will slow you to carry it #define NOSHIELD 32 // weapon not affected by shield #define CONDUCT 64 // conducts electricity (metal etc.) #define ABSTRACT 128 // for all things that are technically items but used for various different stuff, made it 128 because it could conflict with other flags other way diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 5e31e40a7a6..d375f63dd39 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -238,4 +238,16 @@ #define REGION_RESEARCH 4 #define REGION_ENGINEERING 5 #define REGION_SUPPLY 6 -#define REGION_COMMAND 7 \ No newline at end of file +#define REGION_COMMAND 7 +#define REGION_CENTCOMM 8 + +//Matricies +#define MATRIX_DEFAULT list(1, 0, 0, 0,\ + 0, 1, 0, 0,\ + 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) diff --git a/code/__HELPERS/AnimationLibrary.dm b/code/__HELPERS/AnimationLibrary.dm new file mode 100644 index 00000000000..65225d37363 --- /dev/null +++ b/code/__HELPERS/AnimationLibrary.dm @@ -0,0 +1,190 @@ +/* + * A file intended to store various animation procs for re-use. + * A fair majority of these are copy-pasted from Goon and may not function as expected without tweaking. + * The spin from being thrown will interrupt most of these animations as will grabs, account for that accordingly. + */ + +/proc/animate_fade_grayscale(var/atom/A, var/time = 5) + if(!istype(A) && !istype(A, /client)) + return + A.color = MATRIX_DEFAULT + animate(A, color = MATRIX_GREYSCALE, time = time, easing = SINE_EASING) + +/proc/animate_melt_pixel(var/atom/A) + if(!istype(A)) + return + animate(A, pixel_y = 0, time = 50 - A.pixel_y, alpha = 175, easing = BOUNCE_EASING) + animate(alpha = 0, easing = LINEAR_EASING) + +/proc/animate_explode_pixel(var/atom/A) + if(!istype(A)) + return + var/floatdegrees = rand(5, 20) + var/side = pick(-1, 1) + animate(A, pixel_x = rand(-64, 64), pixel_y = rand(-64, 64), transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = 10, alpha = 0, easing = SINE_EASING) + +/proc/animate_float(var/atom/A, var/loopnum = -1, floatspeed = 20, random_side = 1) + if(!istype(A)) + return + var/floatdegrees = rand(5, 20) + var/side = 1 + if(random_side) + side = pick(-1, 1) + + spawn(rand(1,10)) + animate(A, pixel_y = 32, transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING) + animate(pixel_y = 0, transform = matrix(floatdegrees * (side == 1 ? -1:1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING) + +/proc/animate_levitate(var/atom/A, var/loopnum = -1, floatspeed = 20, random_side = 1) + if(!istype(A)) + return + var/floatdegrees = rand(5, 20) + var/side = 1 + if(random_side) + side = pick(-1, 1) + + spawn(rand(1,10)) + animate(A, pixel_y = 8, transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING) + animate(pixel_y = 0, transform = null, time = floatspeed, loop = loopnum, easing = SINE_EASING) + +/proc/animate_ghostly_presence(var/atom/A, var/loopnum = -1, floatspeed = 20, random_side = 1) + if(!istype(A)) + return + var/floatdegrees = rand(5, 20) + var/side = 1 + if(random_side) + side = pick(-1, 1) + + spawn(rand(1,10)) + animate(A, pixel_y = 8, transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING) + animate(pixel_y = 0, transform = matrix(floatdegrees * (side == 1 ? -1:1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING) + +/proc/animate_fading_leap_up(var/atom/A) + if(!istype(A)) + return + var/matrix/M = matrix() + var/do_loops = 15 + while (do_loops > 0) + do_loops-- + animate(A, transform = M, pixel_z = A.pixel_z + 12, alpha = A.alpha - 17, time = 1, loop = 1, easing = LINEAR_EASING) + M.Scale(1.2,1.2) + sleep(1) + A.alpha = 0 + +/proc/animate_fading_leap_down(var/atom/A) + if(!istype(A)) + return + var/matrix/M = matrix() + var/do_loops = 15 + M.Scale(18,18) + while(do_loops > 0) + do_loops-- + animate(A, transform = M, pixel_z = A.pixel_z - 12, alpha = A.alpha + 17, time = 1, loop = 1, easing = LINEAR_EASING) + M.Scale(0.8,0.8) + sleep(1) + animate(A, transform = M, pixel_z = 0, alpha = 255, time = 1, loop = 1, easing = LINEAR_EASING) + +/proc/animate_shake(var/atom/A, var/amount = 5, var/x_severity = 2, var/y_severity = 2) + // Wiggles the sprite around on its tile then returns it to normal + if(!istype(A)) + return + if(!isnum(amount) || !isnum(x_severity) || !isnum(y_severity)) + return + amount = max(1,min(amount,50)) + x_severity = max(-32,min(x_severity,32)) + y_severity = max(-32,min(y_severity,32)) + + var/x_severity_inverse = 0 - x_severity + var/y_severity_inverse = 0 - y_severity + + animate(A, transform = null, pixel_y = rand(y_severity_inverse,y_severity), pixel_x = rand(x_severity_inverse,x_severity),time = 1,loop = amount, easing = ELASTIC_EASING) + spawn(amount) + animate(A, transform = null, pixel_y = 0, pixel_x = 0,time = 1,loop = 1, easing = LINEAR_EASING) + +/proc/animate_teleport(var/atom/A) + if(!istype(A)) + return + var/matrix/M = matrix(1, 3, MATRIX_SCALE) + animate(A, transform = M, pixel_y = 32, time = 10, alpha = 50, easing = CIRCULAR_EASING) + M.Scale(0,4) + animate(transform = M, time = 5, color = "#1111ff", alpha = 0, easing = CIRCULAR_EASING) + animate(transform = null, time = 5, color = "#ffffff", alpha = 255, pixel_y = 0, easing = ELASTIC_EASING) + +/proc/animate_teleport_wiz(var/atom/A) + if(!istype(A)) + return + var/matrix/M = matrix(0, 4, MATRIX_SCALE) + animate(A, color = "#ddddff", time = 20, alpha = 70, easing = LINEAR_EASING) + animate(transform = M, pixel_y = 32, time = 20, color = "#2222ff", alpha = 0, easing = CIRCULAR_EASING) + animate(time = 8, transform = M, alpha = 5) //Do nothing, essentially + animate(transform = null, time = 5, color = "#ffffff", alpha = 255, pixel_y = 0, easing = ELASTIC_EASING) + +/proc/animate_rainbow_glow_old(var/atom/A) + if(!istype(A)) + return + animate(A, color = "#FF0000", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#00FF00", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#0000FF", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + +/proc/animate_rainbow_glow(var/atom/A) + if(!istype(A)) + return + animate(A, color = "#FF0000", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#FFFF00", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#00FF00", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#00FFFF", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#0000FF", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#FF00FF", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + +/proc/animate_fade_to_color_fill(var/atom/A, var/the_color, var/time) + if(!istype(A) || !the_color || !time) + return + animate(A, color = the_color, time = time, easing = LINEAR_EASING) + +/proc/animate_flash_color_fill(var/atom/A, var/the_color, var/loops, var/time) + if(!istype(A) || !the_color || !time || !loops) + return + animate(A, color = the_color, time = time, easing = LINEAR_EASING) + animate(color = "#FFFFFF", time = 5, loop = loops, easing = LINEAR_EASING) + +/proc/animate_flash_color_fill_inherit(var/atom/A, var/the_color, var/loops, var/time) + if(!istype(A) || !the_color || !time || !loops) + return + var/color_old = A.color + animate(A, color = the_color, time = time, loop = loops, easing = LINEAR_EASING) + animate(A, color = color_old, time = time, loop = loops, easing = LINEAR_EASING) + +/proc/animate_clownspell(var/atom/A) + if(!istype(A)) + return + animate(A, transform = matrix(1.3, MATRIX_SCALE), time = 5, color = "#00ff00", easing = BACK_EASING) + animate(transform = null, time = 5, color = "#ffffff", easing = ELASTIC_EASING) + +/proc/animate_wiggle_then_reset(var/atom/A, var/loops = 5, var/speed = 5, var/x_var = 3, var/y_var = 3) + if(!istype(A) || !loops || !speed) + return + animate(A, pixel_x = rand(-x_var, x_var), pixel_y = rand(-y_var, y_var), time = speed * 2,loop = loops, easing = rand(2,7)) + animate(pixel_x = 0, pixel_y = 0, time = speed, easing = rand(2,7)) + +/proc/animate_spin(var/atom/A, var/dir = "L", var/T = 1, var/looping = -1) + if(!istype(A)) + return + + var/matrix/M = A.transform + var/turn = -90 + if(dir == "R") + turn = 90 + + animate(A, transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping) + animate(transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping) + animate(transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping) + animate(transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping) + +/proc/animate_shockwave(var/atom/A) + if(!istype(A)) + return + var/punchstr = rand(10, 20) + var/original_y = A.pixel_y + animate(A, transform = matrix(punchstr, MATRIX_ROTATE), pixel_y = 16, time = 2, color = "#eeeeee", easing = BOUNCE_EASING) + animate(transform = matrix(-punchstr, MATRIX_ROTATE), pixel_y = original_y, time = 2, color = "#ffffff", easing = BOUNCE_EASING) + animate(transform = null, time = 3, easing = BOUNCE_EASING) \ No newline at end of file diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 5f4be64c9db..948602def06 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -64,12 +64,6 @@ return 1 return 0 -//Empties the list by setting the length to 0. Hopefully the elements get garbage collected -/proc/clearlist(list/list) - if(istype(list)) - list.len = 0 - return - //Removes any null entries from the list /proc/listclearnulls(list/list) if(istype(list)) diff --git a/code/_globalvars/configuration.dm b/code/_globalvars/configuration.dm index 4cfa038cd1e..5b41171d557 100644 --- a/code/_globalvars/configuration.dm +++ b/code/_globalvars/configuration.dm @@ -4,7 +4,7 @@ var/host = null var/join_motd = null var/station_name = "NSS Cyberiad" var/game_version = "Custom ParaCode" -var/changelog_hash = "" +var/changelog_hash = md5('html/changelog.html') //used to check if the CL changed var/game_year = (text2num(time2text(world.realtime, "YYYY")) + 544) var/aliens_allowed = 1 @@ -35,4 +35,4 @@ var/MAX_EX_FLAME_RANGE = 14 var/eventchance = 10 //% per 5 mins var/event = 0 var/hadevent = 0 -var/blobevent = 0 \ No newline at end of file +var/blobevent = 0 diff --git a/code/_globalvars/lists/reagents.dm b/code/_globalvars/lists/reagents.dm index f6639796b97..8417275d780 100644 --- a/code/_globalvars/lists/reagents.dm +++ b/code/_globalvars/lists/reagents.dm @@ -55,7 +55,7 @@ var/global/list/blocked_chems = list("polonium", "initropidril", "concentrated_i "syndicate_nanites", "ripping_tendrils", "boiling_oil", "envenomed_filaments", "lexorin_jelly", "kinetic", "cryogenic_liquid", "dark_matter", "b_sorium", - "reagent", "life") + "reagent", "life","dragonsbreath") //List of chems/mixtures that can't grow in plants (in addition to the global random chem blacklist) var/global/list/plant_blocked_chems = list() //filled in /datum/reagents/New() with chems that have can_grow_in_plants = 0 \ No newline at end of file diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 327ac67c801..08c418778a3 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -308,7 +308,7 @@ var/list/uplink_items = list() reference = "AIRJ" item = /obj/item/clothing/under/contortionist cost = 6 - job = list("Atmospheric Technician") + job = list("Life Support Specialist") //Stimulants diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index caead8e0a61..4c6a0881d36 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -14,9 +14,6 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" required_enemies = 1 recommended_enemies = 4 - uplink_welcome = "Syndicate Uplink Console:" - uplink_uses = 20 - var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target var/const/prob_right_murder_target_h = 50 // upper bound on probability of naimg the right assassination target diff --git a/code/game/gamemodes/changeling/changeling_power.dm b/code/game/gamemodes/changeling/changeling_power.dm index 6d03a864692..8e8e824d85e 100644 --- a/code/game/gamemodes/changeling/changeling_power.dm +++ b/code/game/gamemodes/changeling/changeling_power.dm @@ -73,6 +73,12 @@ return 0 return 1 +/obj/effect/proc_holder/changeling/proc/transfer_changeling_powers(var/mob/living/carbon/user, var/mob/living/carbon/target) + if(istype(target, /mob/living/carbon)) // so we don't runtime, I don't even know why it's necessary as it needs a grab + var/datum/changeling/c = user.mind.changeling + var/datum/changeling/t = target.mind.changeling + c.purchasedpowers = t.purchasedpowers + //used in /mob/Stat() /obj/effect/proc_holder/changeling/proc/can_be_used_by(var/mob/user) if(!ishuman(user)) diff --git a/code/game/gamemodes/changeling/powers/swap_form.dm b/code/game/gamemodes/changeling/powers/swap_form.dm index ad8b9381dff..188c5fb437b 100644 --- a/code/game/gamemodes/changeling/powers/swap_form.dm +++ b/code/game/gamemodes/changeling/powers/swap_form.dm @@ -50,6 +50,8 @@ user.key = ghost.key user.Paralyse(2) - user.remove_language("Changeling") target.add_language("Changeling") + user.remove_language("Changeling") + transfer_changeling_powers(user, target) + to_chat(target, "Our genes cry out as we swap our [user] form for [target].") diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 2c50365aec4..392aee68d6b 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -45,9 +45,6 @@ var/global/list/all_cults = list() required_enemies = 3 recommended_enemies = 4 - uplink_welcome = "Nar-Sie Uplink Console:" - uplink_uses = 20 - var/datum/mind/sacrifice_target = null var/finished = 0 diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm index e3e16efc4e6..a5dcef8d4e7 100644 --- a/code/game/gamemodes/extended/extended.dm +++ b/code/game/gamemodes/extended/extended.dm @@ -3,9 +3,6 @@ config_tag = "extended" required_players = 0 - uplink_welcome = "Syndicate Uplink Console:" - uplink_uses = 20 - /datum/game_mode/announce() to_chat(world, "The current game mode is - Extended Role-Playing!") to_chat(world, "Just have fun and role-play!") diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index d5d3c3e87e1..214c5210c14 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -8,9 +8,6 @@ required_enemies = 1 recommended_enemies = 1 - uplink_welcome = "Crazy AI Uplink Console:" - uplink_uses = 10 - var/AI_win_timeleft = 1500 //started at 1500, in case I change this for testing round end. var/malf_mode_declared = 0 var/station_captured = 0 diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm index a8c8fec6f51..6df3df1dd19 100644 --- a/code/game/gamemodes/meteor/meteor.dm +++ b/code/game/gamemodes/meteor/meteor.dm @@ -5,9 +5,6 @@ var/wave = 1 required_players = 35 - uplink_welcome = "EVIL METEOR Uplink Console:" - uplink_uses = 10 - /datum/game_mode/meteor/announce() to_chat(world, "The current game mode is - Meteor!") diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm index 8c4a2685e04..5cfe1324849 100644 --- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm +++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm @@ -68,6 +68,7 @@ projectilesound = 'sound/weapons/taser2.ogg' AIStatus = AI_OFF var/resources = 0 //Resource points, generated by consuming metal/glass + loot = list(/obj/effect/decal/cleanable/blood/gibs/robot, /obj/item/weapon/ore/bluespace_crystal/artificial) /mob/living/simple_animal/hostile/swarmer/Login() ..() @@ -91,7 +92,6 @@ /mob/living/simple_animal/hostile/swarmer/death() ..() - new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) ghostize() qdel(src) diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm index dbb56523e4e..c50b4b04700 100644 --- a/code/game/gamemodes/miniantags/guardian/guardian.dm +++ b/code/game/gamemodes/miniantags/guardian/guardian.dm @@ -785,7 +785,7 @@ /obj/item/weapon/guardiancreator/tech name = "holoparasite injector" desc = "It contains alien nanoswarm of unknown origin. Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, it requires an organic host as a home base and source of fuel." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/obj/hypo.dmi' icon_state = "combat_hypo" theme = "tech" mob_name = "Holoparasite" diff --git a/code/game/gamemodes/miniantags/slaughter/slaughter.dm b/code/game/gamemodes/miniantags/slaughter/slaughter.dm index f410b9bfb6d..acff759f277 100644 --- a/code/game/gamemodes/miniantags/slaughter/slaughter.dm +++ b/code/game/gamemodes/miniantags/slaughter/slaughter.dm @@ -42,6 +42,7 @@ var/cooldown = 0 var/gorecooldown = 0 var/vialspawned = FALSE + loot = list(/obj/effect/decal/cleanable/blood/innards, /obj/effect/decal/cleanable/blood, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic, /obj/item/organ/internal/heart/demon) var/playstyle_string = "You are the Slaughter Demon, a terrible creature from another existence. You have a single desire: To kill. \ You may Ctrl+Click on blood pools to travel through them, appearing and dissaapearing from the station at will. \ Pulling a dead or critical mob while you enter a pool will pull them in with you, allowing you to feast. \ @@ -79,17 +80,14 @@ else speed = 0 +/obj/effect/decal/cleanable/blood/innards + icon = 'icons/obj/surgery.dmi' + icon_state = "innards" + name = "pile of viscera" + desc = "A repulsive pile of guts and gore." + /mob/living/simple_animal/slaughter/death() ..() - var/obj/effect/decal/cleanable/blood/innards = new (get_turf(src)) - innards.icon = 'icons/obj/surgery.dmi' - innards.icon_state = "innards" - innards.name = "pile of viscera" - innards.desc = "A repulsive pile of guts and gore." - new /obj/effect/decal/cleanable/blood(loc) - new /obj/effect/gibspawner/generic(get_turf(src)) - new /obj/effect/gibspawner/generic(get_turf(src)) - new /obj/item/organ/internal/heart/demon(loc) playsound(get_turf(src),'sound/misc/demon_dies.ogg', 200, 1) visible_message("[src] screams in anger as it collapses into a puddle of viscera, its most recent meals spilling out of it.") for(var/mob/living/M in consumed_mobs) diff --git a/code/game/gamemodes/mutiny/mutiny.dm b/code/game/gamemodes/mutiny/mutiny.dm index 92b45e223a5..73876652e23 100644 --- a/code/game/gamemodes/mutiny/mutiny.dm +++ b/code/game/gamemodes/mutiny/mutiny.dm @@ -19,9 +19,6 @@ datum/game_mode/mutiny required_players = 20 ert_disabled = 1 - uplink_welcome = "Mutineers Uplink Console:" - uplink_uses = 0 - New() fluff = new(src) diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 0268133a5d1..9ebd3a28ab7 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -11,9 +11,6 @@ proc/issyndicate(mob/living/M as mob) required_enemies = 5 recommended_enemies = 5 - uplink_welcome = "Corporate Backed Uplink Console:" - uplink_uses = 120 - var/const/agents_possible = 5 //If we ever need more syndicate agents. var/nukes_left = 1 // Call 3714-PRAY right now and order more nukes! Limited offer! diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index c7fcd59dfe4..97f2d301472 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -16,10 +16,6 @@ required_enemies = 1 recommended_enemies = 4 - - uplink_welcome = "Syndicate Uplink Console:" - uplink_uses = 20 - var/traitors_possible = 4 //hard limit on traitors if scaling is turned off var/const/traitor_scaling_coeff = 5.0 //how much does the amount of players get divided by to determine traitors diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm index 92f08ecc586..79d644b2132 100644 --- a/code/game/gamemodes/vampire/vampire.dm +++ b/code/game/gamemodes/vampire/vampire.dm @@ -4,6 +4,7 @@ var/list/datum/mind/vampires = list() var/list/datum/mind/vampire_enthralled = list() //those controlled by a vampire var/list/vampire_thralls = list() //vammpires controlling somebody + /datum/game_mode/vampire name = "vampire" config_tag = "vampire" @@ -14,9 +15,6 @@ required_enemies = 1 recommended_enemies = 4 - uplink_welcome = "Syndicate Uplink Console:" - uplink_uses = 20 - var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target var/const/prob_right_murder_target_h = 50 // upper bound on probability of naimg the right assassination target diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index 32d73ff33f7..9caa009f2e6 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -8,9 +8,6 @@ required_enemies = 1 recommended_enemies = 1 - uplink_welcome = "Wizardly Uplink Console:" - uplink_uses = 20 - var/use_huds = 0 var/finished = 0 var/but_wait_theres_more = 0 diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index e3649f5e445..c7435a29df9 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -267,6 +267,8 @@ return list(access_mailsorting, access_mining, access_mining_station, access_mineral_storeroom, access_cargo, access_qm) if(REGION_COMMAND) //command return list(access_heads, access_RC_announce, access_keycard_auth, access_change_ids, access_ai_upload, access_teleporter, access_eva, access_tcomsat, access_gateway, access_all_personal_lockers, access_heads_vault, access_blueshield, access_ntrep, access_hop, access_captain) + if(REGION_CENTCOMM) //because why the heck not + return get_all_centcom_access() + get_all_accesses() /proc/get_region_accesses_name(code) switch(code) @@ -286,6 +288,8 @@ return "Supply" if(REGION_COMMAND) //command return "Command" + if(REGION_CENTCOMM) //CC + return "CentComm" /proc/get_access_desc(A) @@ -600,4 +604,3 @@ proc/get_all_job_icons() //For all existing HUD icons return return "Unknown" //Return unknown if none of the above apply - diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 238e071ebe9..31ad9f145ee 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -73,6 +73,7 @@ if(M.environment_smash) M.do_attack_animation(src) visible_message("[M.name] smashes [src] apart!") + go_out() qdel(src) return @@ -183,7 +184,10 @@ data["dialysis"] = connected.filtering if (connected.beaker) data["isBeakerLoaded"] = 1 - data["beakerFreeSpace"] = round(connected.beaker.reagents.maximum_volume - connected.beaker.reagents.total_volume) + if(connected.beaker.reagents) + data["beakerFreeSpace"] = round(connected.beaker.reagents.maximum_volume - connected.beaker.reagents.total_volume) + else + data["beakerFreeSpace"] = 0 var/chemicals[0] for (var/re in connected.injection_chems) @@ -354,15 +358,21 @@ to_chat(occupant, "You no longer feel reliant on [R.name]!") occupant.reagents.addiction_list.Remove(R) + for(var/mob/M as mob in src) // makes sure that simple mobs don't get stuck inside a sleeper when they resist out of occupant's grasp + if(M == occupant) + continue + else + M.forceMove(src.loc) + updateDialog() return /obj/machinery/sleeper/blob_act() if(prob(75)) - for(var/atom/movable/A as mob|obj in src) - A.forceMove(src.loc) - A.blob_act() + var/atom/movable/A = occupant + go_out() + A.blob_act() qdel(src) return @@ -404,11 +414,14 @@ orient = "RIGHT" dir = 4 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + return if(exchange_parts(user, G)) return - default_deconstruction_crowbar(G) + if(istype(G, /obj/item/weapon/crowbar)) + default_deconstruction_crowbar(G) + return if(istype(G, /obj/item/weapon/grab)) if(panel_open) @@ -453,24 +466,23 @@ if(1.0) for(var/atom/movable/A as mob|obj in src) A.forceMove(src.loc) - ex_act(severity) + A.ex_act(severity) qdel(src) return if(2.0) if(prob(50)) for(var/atom/movable/A as mob|obj in src) A.forceMove(src.loc) - ex_act(severity) + A.ex_act(severity) qdel(src) return if(3.0) if(prob(25)) for(var/atom/movable/A as mob|obj in src) A.forceMove(src.loc) - ex_act(severity) + A.ex_act(severity) qdel(src) return - return /obj/machinery/sleeper/emp_act(severity) if(filtering) diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 45ee6e0f4c9..897e3ee51c8 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -19,6 +19,13 @@ else set_light(0) +/obj/machinery/bodyscanner/process() + for(var/mob/M as mob in src) // makes sure that simple mobs don't get stuck inside a sleeper when they resist out of occupant's grasp + if(M == occupant) + continue + else + M.forceMove(src.loc) + /obj/machinery/bodyscanner/New() ..() component_parts = list() @@ -59,11 +66,14 @@ else dir = 4 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + return if(exchange_parts(user, G)) return - default_deconstruction_crowbar(G) + if(istype(G, /obj/item/weapon/crowbar)) + default_deconstruction_crowbar(G) + return if(istype(G, /obj/item/weapon/grab)) var/obj/item/weapon/grab/TYPECAST_YOUR_SHIT = G @@ -161,39 +171,40 @@ switch(severity) if(1.0) for(var/atom/movable/A as mob|obj in src) - A.loc = src.loc - ex_act(severity) - //Foreach goto(35) - //SN src = null + A.forceMove(src.loc) + A.ex_act(severity) qdel(src) return if(2.0) if (prob(50)) for(var/atom/movable/A as mob|obj in src) - A.loc = src.loc - ex_act(severity) - //Foreach goto(108) - //SN src = null + A.forceMove(src.loc) + A.ex_act(severity) qdel(src) return if(3.0) if (prob(25)) for(var/atom/movable/A as mob|obj in src) - A.loc = src.loc - ex_act(severity) - //Foreach goto(181) - //SN src = null + A.forceMove(src.loc) + A.ex_act(severity) qdel(src) return - else - return /obj/machinery/bodyscanner/blob_act() if(prob(50)) - for(var/atom/movable/A as mob|obj in src) - A.loc = src.loc + var/atom/movable/A = occupant + go_out() + A.blob_act() qdel(src) +/obj/machinery/bodyscanner/attack_animal(var/mob/living/simple_animal/M)//Stop putting hostile mobs in things guise + if(M.environment_smash) + M.do_attack_animation(src) + visible_message("[M.name] smashes [src] apart!") + go_out() + qdel(src) + return + /obj/machinery/body_scanconsole var/obj/machinery/bodyscanner/connected var/delete @@ -249,6 +260,13 @@ if(prob(50)) qdel(src) +/obj/machinery/body_scanconsole/attack_animal(var/mob/living/simple_animal/M)//Stop putting hostile mobs in things guise + if(M.environment_smash) + M.do_attack_animation(src) + visible_message("[M.name] smashes [src] apart!") + qdel(src) + return + /obj/machinery/body_scanconsole/proc/findscanner() var/obj/machinery/bodyscanner/bodyscannernew = null // Loop through every direction diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 0948c8ae3a1..d3cc5f089a0 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -967,7 +967,9 @@ name = "Spaceport Security" desc = "The Premier security forces for all spaceports found along the Orion Trail." faction = list("orion") - corpse = /obj/effect/landmark/mobcorpse/orionsecurity + loot = list(/obj/effect/landmark/mobcorpse/orionsecurity, + /obj/item/weapon/gun/projectile/automatic/c20r, + /obj/item/weapon/shield/energy) /obj/effect/landmark/mobcorpse/orionsecurity name = "Spaceport Security" diff --git a/code/game/machinery/computer/pod_tracking_console.dm b/code/game/machinery/computer/pod_tracking_console.dm index 5ac31a0f567..6817d265a0f 100644 --- a/code/game/machinery/computer/pod_tracking_console.dm +++ b/code/game/machinery/computer/pod_tracking_console.dm @@ -17,17 +17,20 @@ var/data[0] var/list/pods[0] for(var/obj/item/device/spacepod_equipment/misc/tracker/TR in world) - var/obj/spacepod/myPod = TR.my_atom + var/obj/spacepod/my_pod = TR.my_atom var/enabled = TR.enabled - if(myPod && enabled) - var/podname = capitalize(sanitize(myPod.name)) - var/occupant = "None" - var/occupant2 = "None" - if(myPod.occupant) - occupant = myPod.occupant.name - if(myPod.occupant2) - occupant2 = myPod.occupant2.name - pods.Add(list(list("pod" = "\ref[myPod]", "name" = podname, "occupant" = occupant, "occupant2" = occupant2, "x" = myPod.x, "y" = myPod.y, "z" = myPod.z))) + if(my_pod && enabled) + var/podname = capitalize(sanitize(my_pod.name)) + var/list/chairs = list() + if(my_pod.pilot || my_pod.passengers) + if(my_pod.pilot) + chairs += list("pilot" = my_pod.pilot.name) + var/i = 1 + for(var/mob/M in my_pod.passengers) + chairs += list("passenger [i]" = M.name) + i++ + + pods.Add(list(list("pod" = "\ref[my_pod]", "name" = podname) + chairs + list("x" = my_pod.x, "y" = my_pod.y, "z" = my_pod.z))) data["pods"] = pods diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index ccdd9b3f276..42875f58019 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -71,7 +71,7 @@ to_chat(user, "Access Denied. This robot is not linked to you.") return // Cyborgs may blow up themselves via the console - if(isrobot(user) && user != target) + if((isrobot(user) && user != target) || !is_authenticated(user)) to_chat(user, "Access Denied.") return var/choice = input("Really detonate [target.name]?") in list ("Yes", "No") diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 095cd23498a..8fd840fd0e3 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -58,6 +58,7 @@ 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 @@ -127,6 +128,7 @@ hackProof = 1 aiControlDisabled = 1 unacidable = 1 + is_special = 1 /obj/machinery/door/airlock/maintenance_hatch name = "Maintenance Hatch" @@ -305,6 +307,7 @@ 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)) @@ -800,7 +803,6 @@ About the new airlock wires panel: else return else if(istype(C, /obj/item/weapon/screwdriver)) - playsound(src.loc, 'sound/items/Screwdriver.ogg', 25, 1) src.p_open = !( src.p_open ) src.update_icon() else if(istype(C, /obj/item/weapon/wirecutters)) diff --git a/code/game/machinery/gameboard.dm b/code/game/machinery/gameboard.dm index b331930b325..5657d62f65f 100644 --- a/code/game/machinery/gameboard.dm +++ b/code/game/machinery/gameboard.dm @@ -2,59 +2,60 @@ name = "Virtual Gameboard" icon = 'icons/obj/stationobjs.dmi' icon_state = "gboard_on" - desc = "A holographic table allowing the crew to have fun™ on boring shifts! One player per board." + desc = "A holographic table allowing the crew to have funâ„¢ on boring shifts! One player per board." density = 1 anchored = 1 use_power = 1 + var/cooling_down = 0 /obj/machinery/gameboard/New() - ..() - component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/gameboard(null) - component_parts += new /obj/item/weapon/stock_parts/micro_laser(null) - component_parts += new /obj/item/stack/cable_coil(null, 3) - component_parts += new /obj/item/stack/sheet/glass(null, 1) - RefreshParts() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/gameboard(null) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(null) + component_parts += new /obj/item/stack/cable_coil(null, 3) + component_parts += new /obj/item/stack/sheet/glass(null, 1) + RefreshParts() /obj/machinery/gameboard/power_change() - . = ..() - update_icon() + . = ..() + update_icon() /obj/machinery/gameboard/update_icon() - if(stat & NOPOWER) - icon_state = "gboard_off" - else - icon_state = "gboard_on" + if(stat & NOPOWER) + icon_state = "gboard_off" + else + icon_state = "gboard_on" /obj/machinery/gameboard/attack_hand(mob/user) - . = ..() - if(.) - return - if(src.in_use) - to_chat(user, "This gameboard is already in use!") - return - interact(user) + . = ..() + if(.) + return + if(src.in_use) + to_chat(user, "This gameboard is already in use!") + return + interact(user) /obj/machinery/gameboard/interact(mob/user) - . = ..() - if(.) - return + . = ..() + if(.) + return - var/dat - dat = replacetext(file2text('html/chess.html'), "\[hsrc]", "\ref[src]") - var/datum/asset/simple/chess/assets = get_asset_datum(/datum/asset/simple/chess) - assets.send(user) + var/dat + dat = replacetext(file2text('html/chess.html'), "\[hsrc]", "\ref[src]") + var/datum/asset/simple/chess/assets = get_asset_datum(/datum/asset/simple/chess) + assets.send(user) - var/datum/browser/popup = new(user, "SpessChess", name, 500, 800, src) - popup.set_content(dat) - popup.add_stylesheet("chess.css", 'html/browser/chess.css') - popup.add_script("garbochess.js", 'html/browser/garbochess.js') - //popup.add_script("boardui.js", 'html/browser/boardui.js') - popup.add_script("jquery-1.8.2.min.js", 'html/browser/jquery-1.8.2.min.js') - popup.add_script("jquery-ui-1.8.24.custom.min.js", 'html/browser/jquery-ui-1.8.24.custom.min.js') - popup.set_window_options("titlebar=0") - popup.open() - user.set_machine(src) + var/datum/browser/popup = new(user, "SpessChess", name, 500, 800, src) + popup.set_content(dat) + popup.add_stylesheet("chess.css", 'html/browser/chess.css') + popup.add_script("garbochess.js", 'html/browser/garbochess.js') + //popup.add_script("boardui.js", 'html/browser/boardui.js') + popup.add_script("jquery-1.8.2.min.js", 'html/browser/jquery-1.8.2.min.js') + popup.add_script("jquery-ui-1.8.24.custom.min.js", 'html/browser/jquery-ui-1.8.24.custom.min.js') + popup.set_window_options("titlebar=0") + popup.open() + user.set_machine(src) /obj/machinery/gameboard/proc/close_game() //yes, shamelessly copied over from arcade_base in_use = 0 @@ -65,15 +66,21 @@ return /obj/machinery/gameboard/Topic(var/href, var/list/href_list) - . = ..() - var/prize = /obj/item/stack/tickets - if (.) - return + . = ..() + var/prize = /obj/item/stack/tickets + if (.) + return - if (href_list["checkmate"]) - visible_message("[src.name] beeps, \"WINNER!\"") - new prize(get_turf(src), 80) - close_game() + if (href_list["checkmate"]) + if(cooling_down) + message_admins("Too many checkmates on chessboard, possible HREF exploits: [key_name_admin(usr)] on [src] (JMP)") + return + visible_message("[src.name] beeps, \"WINNER!\"") + new prize(get_turf(src), 80) + close_game() + cooling_down = 1 + spawn(600) + cooling_down = 0 - if (href_list["close"]) - close_game() \ No newline at end of file + if (href_list["close"]) + close_game() diff --git a/code/game/machinery/guestpass.dm b/code/game/machinery/guestpass.dm index b63307c3db8..bf1d69e7437 100644 --- a/code/game/machinery/guestpass.dm +++ b/code/game/machinery/guestpass.dm @@ -58,6 +58,9 @@ else to_chat(user, "There is already ID card inside.") +/obj/machinery/computer/guestpass/proc/get_changeable_accesses() + return giver.access + /obj/machinery/computer/guestpass/attack_ai(var/mob/user as mob) return attack_hand(user) @@ -84,7 +87,7 @@ dat += "Duration (minutes): [duration] m
" dat += "Access to areas:
" if (giver && giver.access) - for (var/A in giver.access) + for (var/A in get_changeable_accesses()) var/area = get_access_desc(A) if (A in accesses) area = "[area]" @@ -124,7 +127,8 @@ if (A in accesses) accesses.Remove(A) else - accesses.Add(A) + if(giver && giver.access && (A in get_changeable_accesses())) + accesses.Add(A) if (href_list["action"]) switch(href_list["action"]) if ("id") @@ -178,4 +182,12 @@ else to_chat(usr, "\red Cannot issue pass without issuing ID.") updateUsrDialog() - return \ No newline at end of file + return + +/obj/machinery/computer/guestpass/hop + name = "\improper HoP guest pass terminal" + +/obj/machinery/computer/guestpass/hop/get_changeable_accesses() + . = ..() + if(. && access_change_ids in .) + return get_all_accesses() diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index f916998e26b..eab12bb22d5 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -519,7 +519,7 @@ var/list/turret_icons assess_and_assign(ME.occupant, targets, secondarytargets) for(var/obj/spacepod/SP in view(7,src)) - assess_and_assign(SP.occupant, targets, secondarytargets) + assess_and_assign(SP.pilot, targets, secondarytargets) for(var/obj/vehicle/T in view(7,src)) assess_and_assign(T.buckled_mob, targets, secondarytargets) diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 5b5a532efdb..92bca16c5b7 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -54,8 +54,52 @@ if(src.occupant) process_occupant() + + for(var/mob/M as mob in src) // makes sure that simple mobs don't get stuck inside a sleeper when they resist out of occupant's grasp + if(M == occupant) + continue + else + M.forceMove(src.loc) return 1 +/obj/machinery/recharge_station/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + A.ex_act(severity) + qdel(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + A.ex_act(severity) + qdel(src) + return + if(3.0) + if (prob(25)) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + A.ex_act(severity) + qdel(src) + return + +/obj/machinery/recharge_station/blob_act() + if(prob(50)) + var/atom/movable/A = occupant + go_out() + A.blob_act() + qdel(src) + +/obj/machinery/recharge_station/attack_animal(var/mob/living/simple_animal/M)//Stop putting hostile mobs in things guise + if(M.environment_smash) + M.do_attack_animation(src) + visible_message("[M.name] smashes [src] apart!") + go_out() + qdel(src) + return + /obj/machinery/recharge_station/Bumped(var/mob/AM) move_inside(AM) @@ -210,7 +254,7 @@ /obj/machinery/recharge_station/verb/move_inside(var/mob/user = usr) set category = "Object" set src in oview(1) - if(!user) + if(!user || !usr) return if (usr.stat != CONSCIOUS) diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 3052d5a28ce..9c1d90ce67a 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -436,6 +436,15 @@ else icon_state = "tele0" +/obj/machinery/teleport/perma/attackby(obj/item/W, mob/user, params) + if(default_deconstruction_screwdriver(user, "tele-o", "tele0", W)) + return + + if(exchange_parts(user, W)) + return + + default_deconstruction_crowbar(W) + /obj/machinery/teleport/station name = "station" desc = "The power control station for a bluespace teleporter." diff --git a/code/game/machinery/turrets.dm b/code/game/machinery/turrets.dm index b1d92718104..82060d47bc2 100644 --- a/code/game/machinery/turrets.dm +++ b/code/game/machinery/turrets.dm @@ -21,7 +21,7 @@ turretTargets |= Mech else if( istype(O, /obj/spacepod) ) var/obj/spacepod/Pod = O - if( Pod.occupant || Pod.occupant2 ) + if( Pod.pilot ) turretTargets |= Pod else if(istype(O,/mob/living/simple_animal)) turretTargets |= O @@ -139,7 +139,7 @@ return 1 else if( istype(T, /obj/spacepod) ) var/obj/spacepod/SP = T - if( SP.occupant || SP.occupant2 ) + if( SP.pilot ) return 1 else if(istype(T,/mob/living/simple_animal)) var/mob/living/simple_animal/A = T @@ -159,8 +159,8 @@ if(M.occupant) new_targets += M for(var/obj/spacepod/M in protected_area.turretTargets) - if(M.occupant) - new_targets += M + if(M.pilot) + new_targets += M.pilot for(var/mob/living/simple_animal/M in protected_area.turretTargets) if(!M.stat) new_targets += M @@ -488,7 +488,7 @@ return 1 else if(istype(target, /obj/spacepod)) var/obj/spacepod/S = target - if(S.occupant || S.occupant2) + if(S.pilot) return 1 return 0 @@ -522,14 +522,12 @@ continue //Don't shoot at empty mechs. pos_targets += M for(var/obj/spacepod/M in oview(scan_range, src)) - if(M.occupant) - if(faction in M.occupant.faction) + if(M.pilot) + var/mob/P = M.pilot + if(faction in P.faction) continue - if(M.occupant2) - if(faction in M.occupant2.faction) - continue - if(!M.occupant && !M.occupant2) - continue //Don't shoot at empty mechs. + if(!M.pilot) + continue //Don't shoot at empty pods. pos_targets += M if(pos_targets.len) target = pick(pos_targets) diff --git a/code/game/objects/items/control_wand.dm b/code/game/objects/items/control_wand.dm index 86f6fd5a74d..178f56912c1 100644 --- a/code/game/objects/items/control_wand.dm +++ b/code/game/objects/items/control_wand.dm @@ -31,6 +31,9 @@ /obj/item/weapon/door_remote/afterattack(obj/machinery/door/airlock/D, mob/user) if(!istype(D)) return + if(D.is_special) + to_chat(user, "[src] cannot access this kind of door!") + return if(!(D.arePowerSystemsOn())) to_chat(user, "[D] has no power!") return @@ -99,6 +102,12 @@ icon_state = "gangtool-white" region_access = REGION_GENERAL +/obj/item/weapon/door_remote/centcomm + name = "centcomm door remote" + desc = "High-ranking NT officials only." + icon_state = "gangtool-blue" + region_access = REGION_CENTCOMM + #undef WAND_OPEN #undef WAND_BOLT -#undef WAND_EMERGENCY \ No newline at end of file +#undef WAND_EMERGENCY diff --git a/code/game/objects/items/devices/floor_painter.dm b/code/game/objects/items/devices/floor_painter.dm new file mode 100644 index 00000000000..7fa9759e330 --- /dev/null +++ b/code/game/objects/items/devices/floor_painter.dm @@ -0,0 +1,98 @@ +// Floor painter + +/obj/item/device/floor_painter + name = "floor painter" + icon_state = "floor_painter" + + var/floor_icon + var/floor_state = "floor" + var/floor_dir = SOUTH + + w_class = 1 + item_state = "electronic" + flags = CONDUCT + slot_flags = SLOT_BELT + + var/static/list/allowed_states = list("arrival", "arrivalcorner", "bar", "barber", "blackcorner", "blue", "bluecorner", + "bluefull", "bluered", "blueyellow", "blueyellowfull", "bot", "brown", "browncorner", "browncornerold", "brownold", + "cafeteria", "caution", "cautioncorner", "chapel", "cmo", "dark", "delivery", "escape", "escapecorner", "floor", + "freezerfloor", "green", "greenblue", "greenbluefull", "greencorner", "greenfull", "greenyellow", + "greenyellowfull", "grimy", "loadingarea", "neutral", "neutralcorner", "neutralfull", "orange", "orangecorner", + "orangefull", "purple", "purplecorner", "purplefull", "rampbottom", "ramptop", "red", "redblue", "redbluefull", + "redcorner", "redfull", "redgreen", "redgreenfull", "redyellow", "redyellowfull", "warning", "warningcorner", "warnwhite", + "warnwhitecorner", "white", "whiteblue", "whitebluecorner", "whitebluefull", "whitebot", "whitecorner", "whitedelivery", + "whitegreen", "whitegreencorner", "whitegreenfull", "whitehall", "whitepurple", "whitepurplecorner", "whitepurplefull", + "whitered", "whiteredcorner", "whiteredfull", "whiteyellow", "whiteyellowcorner", "whiteyellowfull", "yellow", + "yellowcorner", "yellowcornersiding", "yellowsiding") + +/obj/item/device/floor_painter/afterattack(var/atom/A, var/mob/user, proximity, params) + if(!proximity) + return + + var/turf/simulated/floor/plasteel/F = A + if(!istype(F)) + to_chat(user, "\The [src] can only be used on station flooring.") + return + + F.icon_state = floor_state + F.icon_regular_floor = floor_state + F.dir = floor_dir + +/obj/item/device/floor_painter/attack_self(var/mob/user) + if(!user) + return 0 + user.set_machine(src) + interact(user) + return 1 + +/obj/item/device/floor_painter/interact(mob/user as mob) + if(!floor_icon) + floor_icon = icon('icons/turf/floors.dmi', floor_state, floor_dir) + user << browse_rsc(floor_icon, "floor.png") + var/dat = {" +
+ <- + + -> +
+ Choose Style +
Style: [floor_state]
+ Choose Direction +
Direction: [dir2text(floor_dir)]
+ "} + + var/datum/browser/popup = new(user, "floor_painter", name, 225, 300) + popup.set_content(dat) + popup.open() + +/obj/item/device/floor_painter/Topic(href, href_list) + if(..()) + return + + if(href_list["choose_state"]) + var/state = input("Please select a style", "[src]") as null|anything in allowed_states + if(state) + floor_state = state + floor_dir = SOUTH // Reset dir, because some icon_states might not have that dir. + if(href_list["choose_dir"]) + var/seldir = input("Please select a direction", "[src]") as null|anything in list("north", "south", "east", "west", "northeast", "northwest", "southeast", "southwest") + if(seldir) + floor_dir = text2dir(seldir) + if(href_list["cycleleft"]) + var/index = allowed_states.Find(floor_state) + index-- + if(index < 1) + index = allowed_states.len + floor_state = allowed_states[index] + floor_dir = SOUTH + if(href_list["cycleright"]) + var/index = allowed_states.Find(floor_state) + index++ + if(index > allowed_states.len) + index = 1 + floor_state = allowed_states[index] + floor_dir = SOUTH + + floor_icon = icon('icons/turf/floors.dmi', floor_state, floor_dir) + if(usr) + attack_self(usr) diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index ef79d5c2a35..9ea2f17378a 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -233,7 +233,6 @@ sleep(300) canprint = 1 - //empty tape recorders /obj/item/device/taperecorder/empty/New() return @@ -260,12 +259,29 @@ to_chat(user, "You pull out all the tape!") ruin() +/obj/item/device/tape/verb/wipe() + set name = "Wipe Tape" + set category = "Object" + + if(usr.stat) + return + if(ruined) + return + + to_chat(usr, "You erase the data from the [src]") + clear() + +/obj/item/device/tape/proc/clear() + used_capacity = 0 + storedinfo.Cut() + timestamp.Cut() /obj/item/device/tape/proc/ruin() overlays += "ribbonoverlay" ruined = 1 + /obj/item/device/tape/proc/fix() overlays -= "ribbonoverlay" ruined = 0 @@ -277,6 +293,12 @@ if(do_after(user, 120, target = src)) to_chat(user, "You wound the tape back in!") fix() + else if(istype(I, /obj/item/weapon/pen)) + var/title = stripped_input(usr,"What do you want to name the tape?", "Tape Renaming", name, MAX_NAME_LEN) + if(!title || !length(title)) + name = initial(name) + return + name = "tape - [title]" //Random colour tapes diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index d30cc76b0a7..79c6466235b 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -107,6 +107,8 @@ var/icon/side var/dat var/stamped = 0 + + var/obj/item/weapon/card/id/guest/guest_pass = null // Guest pass attached to the ID /obj/item/weapon/card/id/New() ..() @@ -120,6 +122,16 @@ show(usr) else to_chat(user, "It is too far away.") + if(guest_pass) + to_chat(user, "There is a guest pass attached to this ID card") + if (world.time < guest_pass.expiration_time) + to_chat(user, "It expires at [worldtime2text(guest_pass.expiration_time)].") + else + to_chat(user, "It expired at [worldtime2text(guest_pass.expiration_time)].") + to_chat(user, "It grants access to following areas:") + for (var/A in guest_pass.temp_access) + to_chat(user, "[get_access_desc(A)].") + to_chat(user, "Issuing reason: [guest_pass.reason].") /obj/item/weapon/card/id/proc/show(mob/user as mob) var/datum/asset/assets = get_asset_datum(/datum/asset/simple/paper) @@ -170,7 +182,9 @@ " /obj/item/weapon/card/id/GetAccess() - return access + if(!guest_pass) + return access + return access | guest_pass.GetAccess() /obj/item/weapon/card/id/GetID() return src @@ -204,9 +218,42 @@ if(!stamped) dat+="" stamped = 1 - to_chat(usr, "You stamp the ID card!") + to_chat(user, "You stamp the ID card!") else - to_chat(usr, "This ID has already been stamped!") + to_chat(user, "This ID has already been stamped!") + + else if(istype(W, /obj/item/weapon/card/id/guest)) + if(istype(src, /obj/item/weapon/card/id/guest)) + return + var/obj/item/weapon/card/id/guest/G = W + if(world.time > G.expiration_time) + to_chat(user, "There's no point, the guest pass has expired.") + return + if(guest_pass) + to_chat(user, "There's already a guest pass attached to this ID.") + return + if(G.registered_name != registered_name && G.registered_name != "NOT SPECIFIED") + to_chat(user, "The guest pass cannot be attached to this ID") + return + if(!user.unEquip(G)) + return + G.loc = src + guest_pass = G + +/obj/item/weapon/card/id/verb/remove_guest_pass() + set name = "Remove Guest Pass" + set category = "Object" + set src in range(0) + + if(usr.stat || !usr.canmove || usr.restrained()) + return + + if(guest_pass) + to_chat(usr, "You remove the guest pass from this ID.") + guest_pass.forceMove(get_turf(src)) + guest_pass = null + else + to_chat(usr, "There is no guest pass attached to this ID") /obj/item/weapon/card/id/silver name = "identification card" diff --git a/code/game/objects/items/weapons/dnascrambler.dm b/code/game/objects/items/weapons/dnascrambler.dm index 47bea6ca58d..2765b4a319d 100644 --- a/code/game/objects/items/weapons/dnascrambler.dm +++ b/code/game/objects/items/weapons/dnascrambler.dm @@ -1,16 +1,16 @@ /obj/item/weapon/dnascrambler name = "dna scrambler" desc = "An illegal genetic serum designed to randomize the user's identity." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/obj/hypo.dmi' item_state = "syringe_0" - icon_state = "b10" + icon_state = "lepopen1" var/used = null update_icon() if(used) - icon_state = "b0" + icon_state = "lepopen0" else - icon_state = "b10" + icon_state = "lepopen1" attack(mob/M as mob, mob/user as mob) if(!M || !user) diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm new file mode 100644 index 00000000000..879e82f9ee0 --- /dev/null +++ b/code/game/objects/items/weapons/holy_weapons.dm @@ -0,0 +1,328 @@ +/obj/item/weapon/nullrod + name = "null rod" + desc = "A rod of pure obsidian, its very presence disrupts and dampens the powers of Nar-Sie's followers." + icon_state = "nullrod" + item_state = "nullrod" + force = 18 + throw_speed = 3 + throw_range = 4 + throwforce = 10 + w_class = 1 + var/reskinned = FALSE + var/list/fluff_transformations = list() //does it have any special transformations only accessible to it? Should only be subtypes of /obj/item/weapon/nullrod + +/obj/item/weapon/nullrod/suicide_act(mob/user) + user.visible_message("[user] is killing \himself with \the [src.name]! It looks like \he's trying to get closer to god!") + return (BRUTELOSS|FIRELOSS) + +/obj/item/weapon/nullrod/attack(mob/M, mob/living/carbon/user) + ..() + if(M.mind) + if(M.mind.vampire) + if(ishuman(M)) + if(!M.mind.vampire.get_ability(/datum/vampire_passive/full)) + to_chat(M, "The nullrod's power interferes with your own!") + M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) + +/obj/item/weapon/nullrod/attack_self(mob/user) + if(reskinned) + return + if(user.mind && (user.mind.assigned_role == "Chaplain")) + reskin_holy_weapon(user) + +/obj/item/weapon/nullrod/proc/reskin_holy_weapon(mob/M) + var/list/holy_weapons_list = typesof(/obj/item/weapon/nullrod) - typesof(/obj/item/weapon/nullrod/fluff) + if(fluff_transformations.len) + for(var/thing in fluff_transformations) + holy_weapons_list += thing + var/list/display_names = list() + for(var/V in holy_weapons_list) + var/atom/A = V + display_names += initial(A.name) + + var/choice = input(M,"What theme would you like for your holy weapon?","Holy Weapon Theme") as null|anything in display_names + if(!src || !choice || !in_range(M, src) || M.incapacitated() || reskinned) + return + + var/index = display_names.Find(choice) + var/A = holy_weapons_list[index] + + var/obj/item/weapon/nullrod/holy_weapon = new A + + feedback_set_details("chaplain_weapon","[choice]") + + if(holy_weapon) + holy_weapon.reskinned = TRUE + M.unEquip(src) + M.put_in_active_hand(holy_weapon) + qdel(src) + +/obj/item/weapon/nullrod/godhand + icon_state = "disintegrate" + item_state = "disintegrate" + name = "god hand" + desc = "This hand of yours glows with an awesome power!" + flags = ABSTRACT | NODROP + w_class = 5 + hitsound = 'sound/weapons/sear.ogg' + damtype = BURN + attack_verb = list("punched", "cross countered", "pummeled") + +/obj/item/weapon/nullrod/staff + icon_state = "godstaff-red" + item_state = "godstaff-red" + name = "red holy staff" + desc = "It has a mysterious, protective aura." + w_class = 5 + force = 5 + slot_flags = SLOT_BACK + +/obj/item/weapon/nullrod/staff/IsShield() + return 1 + +/obj/item/weapon/nullrod/staff/blue + name = "blue holy staff" + icon_state = "godstaff-blue" + item_state = "godstaff-blue" + +/obj/item/weapon/nullrod/claymore + icon_state = "claymore" + item_state = "claymore" + name = "holy claymore" + desc = "A weapon fit for a crusade!" + w_class = 5 + slot_flags = SLOT_BACK|SLOT_BELT + sharp = 1 + edge = 1 + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/weapon/nullrod/claymore/IsShield() + if(prob(30)) + return 1 + else + return 0 + +/obj/item/weapon/nullrod/claymore/darkblade + icon_state = "cultblade" + item_state = "cultblade" + name = "dark blade" + desc = "Spread the glory of the dark gods!" + slot_flags = SLOT_BELT + hitsound = 'sound/hallucinations/growl1.ogg' + +/obj/item/weapon/nullrod/claymore/chainsaw_sword + icon_state = "chainswordon" + item_state = "chainswordon" + name = "sacred chainsaw sword" + desc = "Suffer not a heretic to live." + slot_flags = SLOT_BELT + attack_verb = list("sawed", "torn", "cut", "chopped", "diced") + hitsound = 'sound/weapons/chainsaw.ogg' + +/obj/item/weapon/nullrod/claymore/glowing + icon_state = "swordon" + item_state = "swordon" + name = "force weapon" + desc = "The blade glows with the power of faith. Or possibly a battery." + slot_flags = SLOT_BELT + +/obj/item/weapon/nullrod/claymore/katana + name = "hanzo steel" + desc = "Capable of cutting clean through a holy claymore." + icon_state = "katana" + item_state = "katana" + slot_flags = SLOT_BELT | SLOT_BACK + +/obj/item/weapon/nullrod/claymore/saber + name = "light energy sword" + hitsound = 'sound/weapons/blade1.ogg' + icon_state = "swordblue" + item_state = "swordblue" + desc = "If you strike me down, I shall become more robust than you can possibly imagine." + slot_flags = SLOT_BELT + +/obj/item/weapon/nullrod/claymore/saber/red + name = "dark energy sword" + icon_state = "swordred" + item_state = "swordred" + desc = "Woefully ineffective when used on steep terrain." + +/obj/item/weapon/nullrod/sord + name = "\improper UNREAL SORD" + desc = "This thing is so unspeakably HOLY you are having a hard time even holding it." + icon_state = "sord" + item_state = "sord" + slot_flags = SLOT_BELT + force = 4.13 + throwforce = 1 + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/weapon/nullrod/scythe + icon_state = "scythe0" + item_state = "scythe0" + name = "reaper scythe" + desc = "Ask not for whom the bell tolls..." + w_class = 4 + armour_penetration = 35 + slot_flags = SLOT_BACK + sharp = 1 + edge = 1 + attack_verb = list("chopped", "sliced", "cut", "reaped") + hitsound = 'sound/weapons/bladeslice.ogg' + +/obj/item/weapon/nullrod/scythe/vibro + icon_state = "hfrequency0" + item_state = "hfrequency1" + name = "high frequency blade" + desc = "Bad references are the DNA of the soul." + attack_verb = list("chopped", "sliced", "cut", "zandatsu'd") + +/obj/item/weapon/nullrod/hammmer + icon_state = "hammeron" + item_state = "hammeron" + name = "relic war hammer" + desc = "This war hammer cost the chaplain fourty thousand space dollars." + slot_flags = SLOT_BELT + w_class = 5 + attack_verb = list("smashed", "bashed", "hammered", "crunched") + +/obj/item/weapon/nullrod/chainsaw + name = "chainsaw hand" + desc = "Good? Bad? You're the guy with the chainsaw hand." + icon_state = "chainsaw1" + item_state = "mounted_chainsaw" + w_class = 5 + flags = NODROP | ABSTRACT + sharp = 1 + edge = 1 + attack_verb = list("sawed", "torn", "cut", "chopped", "diced") + hitsound = 'sound/weapons/chainsaw.ogg' + +/obj/item/weapon/nullrod/clown + icon = 'icons/obj/wizard.dmi' + icon_state = "clownrender" + item_state = "gold_horn" + name = "clown dagger" + desc = "Used for absolutely hilarious sacrifices." + hitsound = 'sound/items/bikehorn.ogg' + sharp = 1 + edge = 1 + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut", "honked") + +/obj/item/weapon/nullrod/whip + name = "holy whip" + desc = "What a terrible night to be on Space Station 13." + icon_state = "chain" + item_state = "chain" + slot_flags = SLOT_BELT + attack_verb = list("whipped", "lashed") + hitsound = 'sound/weapons/slash.ogg' + +/obj/item/weapon/nullrod/whip/afterattack(atom/movable/AM, mob/user, proximity) + if(!proximity) + return + if(istype(AM, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = AM + if(is_shadow(H)) + var/phrase = pick("Die monster! You don't belong in this world!!!", "You steal men's souls and make them your slaves!!!", "Your words are as empty as your soul!!!", "Mankind ill needs a savior such as you!!!") + user.say("[phrase]") + H.adjustBruteLoss(8) //Bonus damage + +/obj/item/weapon/nullrod/fedora + name = "athiest's fedora" + desc = "The brim of the hat is as sharp as your wit. Throwing it at someone would hurt almost as much as disproving the existence of God." + icon_state = "fedora" + item_state = "fedora" + slot_flags = SLOT_HEAD + icon = 'icons/obj/clothing/hats.dmi' + force = 0 + throw_speed = 4 + throw_range = 7 + throwforce = 20 + +/obj/item/weapon/nullrod/armblade + name = "dark blessing" + desc = "Particularly twisted deities grant gifts of dubious value." + icon_state = "arm_blade" + item_state = "arm_blade" + flags = ABSTRACT | NODROP + w_class = 5 + sharp = 1 + edge = 1 + +/obj/item/weapon/nullrod/carp + name = "carp-sie plushie" + desc = "An adorable stuffed toy that resembles the god of all carp. The teeth look pretty sharp. Activate it to recieve the blessing of Carp-Sie." + icon = 'icons/obj/toy.dmi' + icon_state = "carpplushie" + item_state = "carp_plushie" + force = 15 + attack_verb = list("bitten", "eaten", "fin slapped") + hitsound = 'sound/weapons/bite.ogg' + var/used_blessing = FALSE + +/obj/item/weapon/nullrod/carp/attack_self(mob/living/user) + if(used_blessing) + return + if(user.mind && (user.mind.assigned_role != "Chaplain")) + return + to_chat(user, "You are blessed by Carp-Sie. Wild space carp will no longer attack you.") + user.faction |= "carp" + used_blessing = TRUE + +/obj/item/weapon/nullrod/claymore/bostaff //May as well make it a "claymore" and inherit the blocking + name = "monk's staff" + desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts, now used to harass the clown." + w_class = 4 + force = 15 + slot_flags = SLOT_BACK + sharp = 0 + edge = 0 + hitsound = "swing_hit" + attack_verb = list("smashed", "slammed", "whacked", "thwacked") + icon = 'icons/obj/weapons.dmi' + icon_state = "bostaff0" + item_state = "bostaff0" + +/obj/item/weapon/nullrod/claymore/bostaff/IsShield() + if(prob(40)) + return 1 + else + return 0 + +/obj/item/weapon/nullrod/tribal_knife + icon_state = "crysknife" + item_state = "crysknife" + name = "arrhythmic knife" + w_class = 5 + desc = "They say fear is the true mind killer, but stabbing them in the head works too. Honour compels you to not sheathe it once drawn." + sharp = 1 + edge = 1 + slot_flags = null + flags = HANDSLOW + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/weapon/nullrod/tribal_knife/New() + ..() + processing_objects.Add(src) + +/obj/item/weapon/nullrod/tribal_knife/Destroy() + processing_objects.Remove(src) + return ..() + +/obj/item/weapon/nullrod/tribal_knife/process() + slowdown = rand(-2, 2) + +/obj/item/weapon/nullrod/pitchfork + icon_state = "pitchfork0" + item_state = "pitchfork0" + name = "unholy pitchfork" + w_class = 3 + desc = "Holding this makes you look absolutely devilish." + attack_verb = list("poked", "impaled", "pierced", "jabbed") + hitsound = 'sound/weapons/bladeslice.ogg' + sharp = 1 + edge = 1 diff --git a/code/game/objects/items/weapons/legcuffs.dm b/code/game/objects/items/weapons/legcuffs.dm index e834f45f703..6cc3f45d3bb 100644 --- a/code/game/objects/items/weapons/legcuffs.dm +++ b/code/game/objects/items/weapons/legcuffs.dm @@ -19,11 +19,15 @@ desc = "A trap used to catch bears and other legged creatures." var/armed = 0 var/obj/item/weapon/grenade/iedcasing/IED = null + var/obj/item/device/assembly/signaler/sig = null /obj/item/weapon/restraints/legcuffs/beartrap/Destroy() if(IED) qdel(IED) IED = null + if(sig) + qdel(sig) + sig = null return ..() /obj/item/weapon/restraints/legcuffs/beartrap/suicide_act(mob/user) @@ -43,6 +47,9 @@ if(IED) to_chat(user, "This beartrap already has an IED hooked up to it!") return + if(sig) + to_chat(user, "This beartrap already has a signaler hooked up to it!") + return IED = I switch(IED.assembled) if(0,1) //if it's not fueled/hooked up @@ -50,7 +57,7 @@ IED = null return if(2,3) - user.drop_item(src) + user.drop_item() I.forceMove(src) message_admins("[key_name_admin(user)] has rigged a beartrap with an IED.") log_game("[key_name(user)] has rigged a beartrap with an IED.") @@ -60,12 +67,33 @@ to_chat(user, "You shouldn't be reading this message! Contact a coder or someone, something broke!") IED = null return + if(istype(I, /obj/item/device/assembly/signaler)) + if(IED) + to_chat(user, "This beartrap already has an IED hooked up to it!") + return + if(sig) + to_chat(user, "This beartrap already has a signaler hooked up to it!") + return + sig = I + if(sig.secured) + to_chat(user, "The signaler is secured.") + sig = null + return + user.drop_item() + I.forceMove(src) + to_chat(user, "You sneak the [sig] underneath the pressure plate and connect the trigger wire.") + desc = "A trap used to catch bears and other legged creatures. There is a remote signaler hooked up to it." if(istype(I, /obj/item/weapon/screwdriver)) if(IED) IED.forceMove(get_turf(src)) IED = null to_chat(user, "You remove the IED from the [src].") return + if(sig) + sig.forceMove(get_turf(src)) + sig = null + to_chat(user, "You remove the signaler from the [src].") + return ..() /obj/item/weapon/restraints/legcuffs/beartrap/Crossed(AM as mob|obj) @@ -88,6 +116,9 @@ spawn(IED.det_time) IED.prime() + if(sig && isturf(src.loc)) + sig.signal() + if(ishuman(AM)) var/mob/living/carbon/H = AM if(H.lying) @@ -192,4 +223,4 @@ /obj/item/weapon/legcuffs/bolas/Bump() ..() - throw_failed() //allows a mech bolas to be destroyed \ No newline at end of file + throw_failed() //allows a mech bolas to be destroyed diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index e20a3af837b..8ff2f931159 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -15,75 +15,6 @@ to_chat(viewers(user), "[user] is hitting \himself with the [src.name]! It looks like \he's trying to ban \himself from life.") return (BRUTELOSS|FIRELOSS|TOXLOSS|OXYLOSS) -/obj/item/weapon/nullrod - name = "null rod" - desc = "A rod of pure obsidian, its very presence disrupts and dampens the powers of paranormal phenomenae." - icon_state = "nullrod" - item_state = "nullrod" - slot_flags = SLOT_BELT - force = 15 - throw_speed = 1 - throw_range = 4 - throwforce = 10 - w_class = 1 - var/transformed = 0 - var/transform_into = /obj/item/weapon/nullrod/sword - var/transform_via = list(/obj/item/clothing/suit/armor/riot/knight/templar, /obj/item/clothing/suit/chaplain_hoodie/fluff/chronx) - - suicide_act(mob/user) - to_chat(viewers(user), "[user] is impaling \himself with the [src.name]! It looks like \he's trying to commit suicide.") - return (BRUTELOSS|FIRELOSS) - -/obj/item/weapon/nullrod/attack(mob/M as mob, mob/living/user as mob) //Paste from old-code to decult with a null rod. - - M.attack_log += text("\[[time_stamp()]\] Has been attacked with [src.name] by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to attack [M.name] ([M.ckey])") - - if(!iscarbon(user)) - M.LAssailant = null - else - M.LAssailant = user - - msg_admin_attack("[key_name_admin(user)] attacked [key_name_admin(M)] with [src.name] (INTENT: [uppertext(user.a_intent)])") - - if ((CLUMSY in user.mutations) && prob(50)) - to_chat(user, "\red The rod slips out of your hand and hits your head.") - user.take_organ_damage(10) - user.Paralyse(20) - return - - if(M.mind) - if(M.mind.vampire) - if(ishuman(M)) - if(!M.mind.vampire.get_ability(/datum/vampire_passive/full)) - to_chat(M, "The nullrod's power interferes with your own!") - M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) - ..() - -/obj/item/weapon/nullrod/afterattack(var/obj/item/I as obj, mob/user as mob, proximity) - if(!proximity) - return - for(var/T in transform_via) - if(istype(I, T)) //Only the Chaplain's holy armor is capable fo performing this feat. - if(!transformed) // can't turn a sword into a sword. - var/obj/item/S = new transform_into() - to_chat(user, "You sheath the [src] into the [I]'s scabbard, transforming it into \a [S].") - user.unEquip(src) - qdel(src) - user.put_in_hands(S) - break - -/obj/item/weapon/nullrod/sword - name = "holy sword" - desc = "A sword imbued with holy power, its very presence disrupts and dampens the powers of paranormal phenomenae." - icon_state = "claymore" - item_state = "claymore" - hitsound = 'sound/weapons/bladeslice.ogg' - w_class = 3 //transforming it is not without its downsides. - sharp = 1 - edge = 1 - transformed = 1 - /obj/item/weapon/sord name = "\improper SORD" desc = "This thing is so unspeakably shitty you are having a hard time even holding it." diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 455b044dbe8..4062767a765 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -459,8 +459,9 @@ /obj/structure/table/glass/destroy(dirty) if(dirty) new /obj/item/weapon/shard(loc) + new /obj/item/weapon/shard(loc) else - new /obj/item/stack/sheet/glass(loc) + new /obj/item/stack/sheet/glass(loc, 2) ..() /obj/structure/table/glass/tablepush(obj/item/I, mob/user) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 8f1dded0a6e..7f4ac1704d9 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -66,8 +66,9 @@ smooth_icon(src) if(!damage) - overlays -= damage_overlays[damage_overlay] - damage_overlay = 0 + if(damage_overlay) + overlays -= damage_overlays[damage_overlay] + damage_overlay = 0 return var/overlay = round(damage / damage_cap * damage_overlays.len) + 1 @@ -76,12 +77,11 @@ if(damage_overlay && overlay == damage_overlay) //No need to update. return - overlays -= damage_overlays[damage_overlay] + if(damage_overlay) + overlays -= damage_overlays[damage_overlay] overlays += damage_overlays[overlay] damage_overlay = overlay - return - /turf/simulated/wall/proc/generate_overlays() var/alpha_inc = 256 / damage_overlays.len diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm index 5d91c835ea0..857fcadb48a 100644 --- a/code/game/verbs/suicide.dm +++ b/code/game/verbs/suicide.dm @@ -3,7 +3,7 @@ /mob/living/carbon/human/proc/do_suicide(damagetype, byitem) var/threshold = (config.health_threshold_crit + config.health_threshold_dead) / 2 var/dmgamt = maxHealth - threshold - + var/damage_mod = 1 switch(damagetype) //Sorry about the magic numbers. //brute = 1, burn = 2, tox = 4, oxy = 8 @@ -163,7 +163,7 @@ var/turf/T = get_turf_or_move(card.loc) for (var/mob/M in viewers(T)) M.show_message("\blue [src] flashes a message across its screen, \"Wiping core files. Please acquire a new personality to continue using pAI device functions.\"", 3, "\blue [src] bleeps electronically.", 2) - death(0) + death(0, 1) else to_chat(src, "Aborting suicide attempt.") diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index d7e79934389..7e5edf7c8bb 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -950,7 +950,7 @@ var/gamma_ship_location = 1 // 0 = station , 1 = space //returns 1 to let the dragdrop code know we are trapping this event //returns 0 if we don't plan to trap the event -/datum/admins/proc/cmd_ghost_drag(var/mob/dead/observer/frommob, var/mob/living/tomob) +/datum/admins/proc/cmd_ghost_drag(var/mob/dead/observer/frommob, var/tothing) if(!istype(frommob)) return //extra sanity check to make sure only observers are shoved into things @@ -962,26 +962,49 @@ var/gamma_ship_location = 1 // 0 = station , 1 = space if (!frommob.ckey) return 0 - var/question = "" - if (tomob.ckey) - question = "This mob already has a user ([tomob.key]) in control of it! " - question += "Are you sure you want to place [frommob.name]([frommob.key]) in control of [tomob.name]?" + if(istype(tothing, /obj/item)) + var/mob/living/toitem = tothing + + var/ask = alert("Are you sure you want to allow [frommob.name]([frommob.key]) to possess [toitem.name]?", "Place ghost in control of item?", "Yes", "No") + if (ask != "Yes") + return 1 + + if(!frommob || !toitem) //make sure the mobs don't go away while we waited for a response + return 1 + + var/mob/living/simple_animal/possessed_object/tomob = new(toitem) + + message_admins("[key_name_admin(usr)] has put [frommob.ckey] in control of [tomob.name].") + log_admin("[key_name(usr)] stuffed [frommob.ckey] into [tomob.name].") + feedback_add_details("admin_verb","CGD") + + tomob.ckey = frommob.ckey + qdel(frommob) + + + if(isliving(tothing)) + var/mob/living/tomob = tothing + + var/question = "" + if (tomob.ckey) + question = "This mob already has a user ([tomob.key]) in control of it! " + question += "Are you sure you want to place [frommob.name]([frommob.key]) in control of [tomob.name]?" + + var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No") + if (ask != "Yes") + return 1 + + if(!frommob || !tomob) //make sure the mobs don't go away while we waited for a response + return 1 + + if(tomob.client) //no need to ghostize if there is no client + tomob.ghostize(0) + + message_admins("[key_name_admin(usr)] has put [frommob.ckey] in control of [tomob.name].") + log_admin("[key_name(usr)] stuffed [frommob.ckey] into [tomob.name].") + feedback_add_details("admin_verb","CGD") + + tomob.ckey = frommob.ckey + qdel(frommob) - var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No") - if (ask != "Yes") return 1 - - if(!frommob || !tomob) //make sure the mobs don't go away while we waited for a response - return 1 - - if(tomob.client) //no need to ghostize if there is no client - tomob.ghostize(0) - - message_admins("[key_name_admin(usr)] has put [frommob.ckey] in control of [tomob.name].") - log_admin("[key_name(usr)] stuffed [frommob.ckey] into [tomob.name].") - feedback_add_details("admin_verb","CGD") - - tomob.ckey = frommob.ckey - qdel(frommob) - - return 1 diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index c7c5b1ab1b1..47ab4399eac 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -125,6 +125,7 @@ var/list/admin_verbs_server = list( /datum/admins/proc/toggleAI, /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ /client/proc/cmd_debug_del_all, + /client/proc/cmd_debug_del_sing, /datum/admins/proc/toggle_aliens, /client/proc/delbook, /client/proc/view_flagged_books, @@ -141,6 +142,7 @@ var/list/admin_verbs_debug = list( /client/proc/cmd_debug_mob_lists, /client/proc/cmd_admin_delete, /client/proc/cmd_debug_del_all, + /client/proc/cmd_debug_del_sing, /client/proc/reload_admins, /client/proc/restart_controller, /client/proc/enable_debug_verbs, diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 4793edd37c8..6b3c78cf954 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -359,6 +359,27 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that message_admins("[key_name_admin(src)] has deleted all instances of [hsbitem].", 0) feedback_add_details("admin_verb","DELA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/proc/cmd_debug_del_sing() + set category = "Debug" + set name = "Del Singulo / Tesla" + + if(!check_rights(R_DEBUG)) + return + + //This gets a confirmation check because it's way easier to accidentally hit this and delete things than it is with del-all + var/confirm = alert("This will delete ALL Singularities and Tesla orbs except for any that are on away mission z-levels or the centcomm z-level. Are you sure you want to delete them?", "Confirm Panic Button", "Yes", "No") + if(confirm != "Yes") + return + + for(var/I in singularities) + var/obj/singularity/S = I + if(S.z == ZLEVEL_CENTCOMM || S.z >= MAX_Z) + continue + qdel(S) + log_admin("[key_name(src)] has deleted all Singularities and Tesla orbs.") + message_admins("[key_name_admin(src)] has deleted all Singularities and Tesla orbs.", 0) + feedback_add_details("admin_verb","DELS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + /client/proc/cmd_debug_make_powernets() set category = "Debug" set name = "Make Powernets" diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm index 61c7b4f5790..4eeab674a88 100644 --- a/code/modules/admin/verbs/onlyone.dm +++ b/code/modules/admin/verbs/onlyone.dm @@ -3,7 +3,7 @@ alert("The game hasn't started yet!") return - var/list/incompatible_species = list("Plasmaman") + var/list/incompatible_species = list("Plasmaman", "Vox") for(var/mob/living/carbon/human/H in player_list) if(H.stat == DEAD || !(H.client)) continue diff --git a/code/modules/admin/verbs/onlyoneteam.dm b/code/modules/admin/verbs/onlyoneteam.dm index 6d5c11e3a4b..5072b43383e 100644 --- a/code/modules/admin/verbs/onlyoneteam.dm +++ b/code/modules/admin/verbs/onlyoneteam.dm @@ -3,7 +3,8 @@ alert("The game hasn't started yet!") return - var/list/incompatible_species = list("Plasmaman") + var/list/incompatible_species = list("Plasmaman", "Vox") + var/team_toggle = 0 for(var/mob/living/carbon/human/H in player_list) if(H.stat == DEAD || !(H.client)) continue @@ -27,7 +28,7 @@ H.equip_to_slot_or_del(new /obj/item/weapon/beach_ball/dodgeball(H), slot_r_hand) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/white(H), slot_shoes) - if(prob(50)) + if(!team_toggle) team_alpha += H H.equip_to_slot_or_del(new /obj/item/clothing/under/color/red/dodgeball(H), slot_w_uniform) @@ -53,6 +54,7 @@ W.registered_name = H.real_name H.equip_to_slot_or_del(W, slot_wear_id) + team_toggle = !team_toggle H.species.equip(H) H.regenerate_icons() diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 844e66cd68c..6797ba8f340 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -43,7 +43,8 @@ timer_end() if((!secured)||(cooldown > 0)) return 0 pulse(0) - loc.visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") + if(loc) + loc.visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") cooldown = 2 spawn(10) process_cooldown() diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 9575002bc88..768de2a270b 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -315,6 +315,11 @@ send_resources() + if(prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates. -CP + winset(src, "rpane.changelog", "background-color=#f4aa94;font-style=bold") + prefs.SetChangelog(src,changelog_hash) + to_chat(src, "Changelog has changed since your last visit.") + if(!void) void = new() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 8b222116995..6696e6e8ecd 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -80,7 +80,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts var/last_id //game-preferences -// var/lastchangelog = "" //Saved changlog filesize to detect if there was a change + var/lastchangelog = "" //Saved changelog filesize to detect if there was a change var/ooccolor = "#b82e00" var/be_special = list() //Special role selection var/UI_style = "Midnight" diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index cb2e3116526..07db4bf7128 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -12,7 +12,8 @@ randomslot, volume, nanoui_fancy, - show_ghostitem_attack + show_ghostitem_attack, + lastchangelog FROM [format_table_name("player")] WHERE ckey='[C.ckey]'"} ) @@ -38,10 +39,10 @@ volume = text2num(query.item[10]) nanoui_fancy = text2num(query.item[11]) show_ghostitem_attack = text2num(query.item[12]) + lastchangelog = query.item[13] //Sanitize ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) -// lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) UI_style = sanitize_inlist(UI_style, list("White", "Midnight"), initial(UI_style)) default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot)) toggles = sanitize_integer(toggles, 0, 65535, initial(toggles)) @@ -52,6 +53,7 @@ volume = sanitize_integer(volume, 0, 100, initial(volume)) 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)) return 1 /datum/preferences/proc/save_preferences(client/C) @@ -75,7 +77,8 @@ randomslot='[randomslot]', volume='[volume]', nanoui_fancy='[nanoui_fancy]', - show_ghostitem_attack='[show_ghostitem_attack]' + show_ghostitem_attack='[show_ghostitem_attack]', + lastchangelog='[lastchangelog]' WHERE ckey='[C.ckey]'"} ) @@ -449,4 +452,14 @@ load_character(C) return 0 load_character(C,pick(saves)) - return 1*/ \ No newline at end of file + return 1*/ + +/datum/preferences/proc/SetChangelog(client/C,hash) + lastchangelog=hash + var/DBQuery/query = dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastchangelog='[lastchangelog]' WHERE ckey='[C.ckey]'") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during lastchangelog updating. Error : \[[err]\]\n") + message_admins("SQL ERROR during lastchangelog updating. Error : \[[err]\]\n") + return + return 1 diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 04f0f3ed42d..8d6595b73ff 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -25,6 +25,7 @@ var/active_sound = null var/toggle_cooldown = null var/cooldown = 0 + var/species_disguise = null //BS12: Species-restricted clothing check. /obj/item/clothing/mob_can_equip(M as mob, slot) diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 1654198d9c9..6e4623fa9be 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -218,10 +218,7 @@ desc = "Somehow these seem even more out-of-date than normal sunglasses." action_button_name = "Noir Mode" var/noir_mode = 0 - color_view = 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.0, 0.0, 1,) //greyscale + color_view = MATRIX_GREYSCALE /obj/item/clothing/glasses/sunglasses/noir/attack_self() if(is_equipped()) diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 13b7a948119..0fbb39e6f1b 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -219,6 +219,7 @@ item_state = "cardborg_h" flags = HEADCOVERSEYES | HEADCOVERSMOUTH flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE + species_disguise = "High-tech robot" /obj/item/clothing/head/cardborg/equipped(mob/living/user, slot) ..() diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 6f699e3a9ae..7934d49a620 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -265,7 +265,7 @@ desc = "God wills it!" icon_state = "knight_templar" item_state = "knight_templar" - allowed = list(/obj/item/weapon/gun/energy,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/weapon/gun/projectile,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs,/obj/item/device/flashlight/seclite,/obj/item/weapon/melee/classic_baton/telescopic,/obj/item/weapon/nullrod/sword) + allowed = list(/obj/item/weapon/gun/energy,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/weapon/gun/projectile,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs,/obj/item/device/flashlight/seclite,/obj/item/weapon/melee/classic_baton/telescopic,/obj/item/weapon/nullrod/claymore) //Non-hardsuit ERT armor. /obj/item/clothing/suit/armor/vest/ert diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 5abc5e86cbf..7985eb06b57 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -206,6 +206,7 @@ item_state = "cardborg" body_parts_covered = UPPER_TORSO|LOWER_TORSO flags_inv = HIDEJUMPSUIT + species_disguise = "High-tech robot" /obj/item/clothing/suit/cardborg/equipped(mob/living/user, slot) ..() diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index c89d08b8d1b..3cd6566e731 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -340,9 +340,9 @@ flags_inv = HIDEFACE /obj/item/weapon/nullrod/fluff/chronx //chronx100: Hughe O'Splash - transform_into = /obj/item/weapon/nullrod/sword/fluff/chronx + fluff_transformations = list(/obj/item/weapon/nullrod/fluff/chronx/scythe) -/obj/item/weapon/nullrod/sword/fluff/chronx +/obj/item/weapon/nullrod/fluff/chronx/scythe name = "Soul Collector" desc = "An ancient scythe used by the worshipers of Cthulhu. Tales say it is used to prepare souls for Cthulhu's great devouring. Someone carved their name into the handle: Hughe O'Splash" icon = 'icons/obj/custom_items.dmi' diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm index 150528d4c66..553251a2ee8 100644 --- a/code/modules/hydroponics/beekeeping/beebox.dm +++ b/code/modules/hydroponics/beekeeping/beebox.dm @@ -82,7 +82,7 @@ honey_frames += HF for(var/i in 1 to get_max_bees()) - var/mob/living/simple_animal/hostile/poison/bees/B = new(src) + var/mob/living/simple_animal/hostile/poison/bees/worker/B = new(src) bees += B B.beehome = src B.assign_reagent(R) diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 7f7addca012..57ad87ecbbe 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -9,6 +9,7 @@ var/seed_name // Plant name for seed packet. var/seed_noun = "seeds" // Descriptor for packet. var/display_name // Prettier name. + var/base_name // Unchanging name for use with modified versions var/roundstart // If set, seed will not display variety number. var/mysterious // Only used for the random seed packets. var/can_self_harvest = 0 // Mostly used for living mobs. @@ -23,12 +24,13 @@ var/splat_type = /obj/effect/decal/cleanable/fruit_smudge // Graffiti decal. var/preset_product var/final_form = 1 + var/last_diverge_type = -1 // Used to check if we need to change our name prefix when we are mutated/modified/enhanced var/modular_icon = 0 // Dictates if the product uses a modular sprite. 0 = preset, 1 = modular var/preset_icon = "undef" // Name of the iconstate in icon/obj/harvest.dmi to use for preset sprite // Make sure to set this to the correct icon if not using a modular sprite /datum/seed/New() - + base_name = seed_name set_trait(TRAIT_IMMUTABLE, 0) // If set, plant will never mutate. If -1, plant is highly mutable. set_trait(TRAIT_HARVEST_REPEAT, 0) // If 1, this plant will fruit repeatedly. set_trait(TRAIT_PRODUCES_POWER, 0) // Can be used to make a battery. @@ -797,16 +799,8 @@ new_seed.modular_icon = modular_icon new_seed.preset_icon = preset_icon - switch(modified) - if(0) //Mutant (default) - new_seed.seed_name = "mutant [seed_name]" - new_seed.display_name = "mutant [seed_name]" - if(1) //Modified - new_seed.seed_name = "modified [seed_name]" - new_seed.display_name = "modified [seed_name]" - if(2) //Enhanced - new_seed.seed_name = "enhanced [seed_name]" - new_seed.display_name = "enhanced [seed_name]" + new_seed.base_name = base_name + new_seed.update_name_prefixes(modified) new_seed.seed_noun = seed_noun new_seed.traits = traits.Copy() @@ -818,3 +812,20 @@ growth_stages = plant_controller.plant_sprites[get_trait(TRAIT_PLANT_ICON)] else growth_stages = 0 + +/datum/seed/proc/update_name_prefixes(var/modified = 0) + if(last_diverge_type == modified) + //We already match the new prefix, so we're not going to bother + return + //Since we don't match, set the last_diverge type to the modified value, then handle the new prefix + last_diverge_type = modified + switch(modified) + if(0) //Mutant (default) + seed_name = "mutant [base_name]" + display_name = "mutant [base_name]" + if(1) //Modified + seed_name = "modified [base_name]" + display_name = "modified [base_name]" + if(2) //Enhanced + seed_name = "enhanced [base_name]" + display_name = "enhanced [base_name]" \ No newline at end of file diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm index 372e3df9a98..a028fa66727 100644 --- a/code/modules/hydroponics/seed_datums.dm +++ b/code/modules/hydroponics/seed_datums.dm @@ -40,7 +40,7 @@ seed_name = "ghost pepper" display_name = "ghost pepper plants" mutants = null - chems = list("capsaicin" = list(8,2), "condensedcapsaicin" = list(4,4), "ghostchilijuice" = list(4,4), "plantmatter" = list(1,50)) + chems = list("capsaicin" = list(8,2), "condensedcapsaicin" = list(4,4), "plantmatter" = list(1,50)) kitchen_tag = "ghostchili" preset_icon = "ghostchilipepper" diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index 1f48cf69adf..74a8d7824dc 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -260,12 +260,16 @@ if(prob(20+mutation_mod)) //Low chance of stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return if(2) //Tier 2 if(prob(60+mutation_mod)) //Higher chance of stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return if(3) //Tier 3 @@ -275,11 +279,15 @@ else //No mutant species, mutate stats instead if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return else //Failed to shift, mutate stats instead if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return if(4) //Tier 4 @@ -289,19 +297,27 @@ else //No mutant species, mutate stats instead if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) if(prob(20+mutation_mod)) //Low chance for second stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return else //Failed to shift, mutate stats instead if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) if(prob(20+mutation_mod)) //Low chance for second stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return //Floral Somatoray Tiers @@ -309,12 +325,16 @@ if(prob(80+mutation_mod)) //EVEN Higher chance of stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return if("F2") //Yield Tier if(prob(40+mutation_mod)) //Medium chance of Yield stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() if(seed.get_trait(TRAIT_IMMUTABLE) <= 0 && seed.get_trait(TRAIT_YIELD) != -1) //Check if the plant can be mutated and has a yield to mutate seed.set_trait(TRAIT_YIELD, (seed.get_trait(TRAIT_YIELD) + rand(-2, 2))) //Randomly adjust yield if(seed.get_trait(TRAIT_YIELD) < 0) //If yield would drop below 0 after adjustment, set to 0 to allow further attempts diff --git a/code/modules/hydroponics/trays/tray_reagents.dm b/code/modules/hydroponics/trays/tray_reagents.dm index a2f308f9e33..8f7e4f5e836 100644 --- a/code/modules/hydroponics/trays/tray_reagents.dm +++ b/code/modules/hydroponics/trays/tray_reagents.dm @@ -180,12 +180,16 @@ if(production_stat_value && seed.get_trait(TRAIT_PRODUCTION) > 2) if(!isnull(plant_controller.seeds[seed.name])) //This is so we don't affect plants in other trays unintentionally seed = seed.diverge(2) //ENHANCE! + else + seed.update_name_prefixes(2) var/new_production = seed.get_trait(TRAIT_PRODUCTION) + (reagent_total * production_stat_value) seed.set_trait(TRAIT_PRODUCTION, max(2, new_production)) //can't drop below 2 with this method //Potency if(potency_stat_value) if(!isnull(plant_controller.seeds[seed.name])) //This is so we don't affect plants in other trays unintentionally seed = seed.diverge(2) //ENHANCE! + else + seed.update_name_prefixes(2) var/new_potency = seed.get_trait(TRAIT_POTENCY) + (reagent_total * potency_stat_value) seed.set_trait(TRAIT_POTENCY, max(0, min(100, new_potency))) //can't go above 100 or below 0 with this method diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm index 140cdc8b85b..ee84c1a5864 100644 --- a/code/modules/mining/equipment_locker.dm +++ b/code/modules/mining/equipment_locker.dm @@ -897,7 +897,7 @@ /obj/item/weapon/lazarus_injector name = "lazarus injector" desc = "An injector with a cocktail of nanomachines and chemicals, this device can seemingly raise animals from the dead, making them become friendly to the user. Unfortunately, the process is useless on higher forms of life and incredibly costly, so these were hidden in storage until an executive thought they'd be great motivation for some of their employees." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/obj/hypo.dmi' icon_state = "lazarus_hypo" item_state = "hypo" throwforce = 0 @@ -916,6 +916,7 @@ if(M.stat == DEAD) M.faction = list("neutral") M.revive() + M.can_collar = 1 if(istype(target, /mob/living/simple_animal/hostile)) var/mob/living/simple_animal/hostile/H = M if(malfunctioning) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 9b3bcd38a98..ebefadd7b3d 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -506,7 +506,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp //this is called when a ghost is drag clicked to something. /mob/dead/observer/MouseDrop(atom/over) if(!usr || !over) return - if (isobserver(usr) && usr.client && usr.client.holder && isliving(over)) + if (isobserver(usr) && usr.client && usr.client.holder) if (usr.client.holder.cmd_ghost_drag(src,over)) return diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index eca554dcb0c..b1d7e356b39 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -317,8 +317,12 @@ if(lying || weakened) message = "[src] flops and flails around on the floor." else - var/obj/item/weapon/grab/G = get_active_hand() + var/obj/item/weapon/grab/G + if(istype(get_active_hand(), /obj/item/weapon/grab)) + G = get_active_hand() if(G && G.affecting) + if(buckled || G.affecting.buckled) + return var/turf/oldloc = loc var/turf/newloc = G.affecting.loc if(isturf(oldloc) && isturf(newloc)) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 714e9c45146..539d88f11cb 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -56,17 +56,22 @@ var/list/nospecies = list("Abductor", "Shadowling", "Neara", "Monkey", "Stok", "Farwa", "Wolpin") //species that won't show their race no matter what - if (skipjumpsuit && skipface || (species.name in nospecies)) //either obscured or on the nospecies list - msg += "!\n" //omit the species when examining - else if (species.name == "Slime People") //snowflakey because Slime People are defined as a plural + var/displayed_species = get_species() + for(var/obj/item/clothing/C in src) //Disguise checks + if (C == src.head || C == src.wear_suit || C == src.wear_mask || C == src.w_uniform || C == src.belt || C == src.back) + if(C.species_disguise) + displayed_species = C.species_disguise + if (skipjumpsuit && skipface || (displayed_species in nospecies)) //either obscured or on the nospecies list + msg += "!\n" //omit the species when examining + else if (displayed_species == "Slime People") //snowflakey because Slime People are defined as a plural msg += ", a slime person!\n" - else if (species.name == "Unathi") //DAMN YOU, VOWELS + else if (displayed_species == "Unathi") //DAMN YOU, VOWELS msg += ", a unathi!\n" else - msg += ", \a [lowertext(species.name)]!\n" + msg += ", \a [lowertext(displayed_species)]!\n" //uniform - if(w_uniform && !skipjumpsuit) + if(w_uniform && !skipjumpsuit && !(w_uniform.flags & ABSTRACT)) //Ties var/tie_msg if(istype(w_uniform,/obj/item/clothing/under)) @@ -80,14 +85,14 @@ msg += "[t_He] [t_is] wearing \icon[w_uniform] \a [w_uniform][tie_msg].\n" //head - if(head) + if(head && !(head.flags & ABSTRACT)) if(head.blood_DNA) msg += "[t_He] [t_is] wearing \icon[head] [head.gender==PLURAL?"some":"a"] [head.blood_color != "#030303" ? "blood-stained":"oil-stained"] [head.name] on [t_his] head!\n" else msg += "[t_He] [t_is] wearing \icon[head] \a [head] on [t_his] head.\n" //suit/armour - if(wear_suit) + if(wear_suit && !(wear_suit.flags & ABSTRACT)) if(wear_suit.blood_DNA) msg += "[t_He] [t_is] wearing \icon[wear_suit] [wear_suit.gender==PLURAL?"some":"a"] [wear_suit.blood_color != "#030303" ? "blood-stained":"oil-stained"] [wear_suit.name]!\n" else @@ -101,7 +106,7 @@ msg += "[t_He] [t_is] carrying \icon[s_store] \a [s_store] on [t_his] [wear_suit.name].\n" //back - if(back) + if(back && !(back.flags & ABSTRACT)) if(back.blood_DNA) msg += "[t_He] [t_has] \icon[back] [back.gender==PLURAL?"some":"a"] [back.blood_color != "#030303" ? "blood-stained":"oil-stained"] [back] on [t_his] back.\n" else @@ -122,7 +127,7 @@ msg += "[t_He] [t_is] holding \icon[r_hand] \a [r_hand] in [t_his] right hand.\n" //gloves - if(gloves && !skipgloves) + if(gloves && !skipgloves && !(gloves.flags & ABSTRACT)) if(gloves.blood_DNA) msg += "[t_He] [t_has] \icon[gloves] [gloves.gender==PLURAL?"some":"a"] [gloves.blood_color != "#030303" ? "blood-stained":"oil-stained"] [gloves.name] on [t_his] hands!\n" else @@ -147,7 +152,7 @@ msg += "[t_He] [t_has] \icon[belt] \a [belt] about [t_his] waist.\n" //shoes - if(shoes && !skipshoes) + if(shoes && !skipshoes && !(shoes.flags & ABSTRACT)) if(shoes.blood_DNA) msg += "[t_He] [t_is] wearing \icon[shoes] [shoes.gender==PLURAL?"some":"a"] [shoes.blood_color != "#030303" ? "blood-stained":"oil-stained"] [shoes.name] on [t_his] feet!\n" else @@ -157,14 +162,14 @@ //mask - if(wear_mask && !skipmask) + if(wear_mask && !skipmask && !(wear_mask.flags & ABSTRACT)) if(wear_mask.blood_DNA) msg += "[t_He] [t_has] \icon[wear_mask] [wear_mask.gender==PLURAL?"some":"a"] [wear_mask.blood_color != "#030303" ? "blood-stained":"oil-stained"] [wear_mask.name] on [t_his] face!\n" else msg += "[t_He] [t_has] \icon[wear_mask] \a [wear_mask] on [t_his] face.\n" //eyes - if(glasses && !skipeyes) + if(glasses && !skipeyes && !(glasses.flags & ABSTRACT)) if(glasses.blood_DNA) msg += "[t_He] [t_has] \icon[glasses] [glasses.gender==PLURAL?"some":"a"] [glasses.blood_color != "#030303" ? "blood-stained":"oil-stained"] [glasses] covering [t_his] eyes!\n" else diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 1556211cb5b..7775830b4a0 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1255,6 +1255,54 @@ else germ_level += n +/mob/living/carbon/human/proc/check_and_regenerate_organs(var/mob/living/carbon/human/H) //Regenerates missing limbs/organs. + var/list/types_of_int_organs = list() //This will hold all the types of organs in the mob before rejuvenation. + for(var/obj/item/organ/internal/I in H.internal_organs) + types_of_int_organs |= I.type //Compiling the list of organ types. It is possible for organs to be missing from this list if they are absent from the mob. + + //Removing stumps. + for(var/obj/item/organ/organ in H.contents) + if(istype(organ, /obj/item/organ/external/stump)) //Get rid of all stumps. + qdel(organ) + H.contents -= organ //Making sure the list entry is removed. + for(var/obj/item/organ/organ in H.organs) + if(istype(organ, /obj/item/organ/external/stump)) + qdel(organ) + H.organs -= organ //Making sure the list entry is removed. + for(var/organ_name in H.organs_by_name) + var/obj/item/organ/organ = H.organs_by_name[organ_name] + if(istype(organ, /obj/item/organ/external/stump) || !organ) //The !organ check is to account for mechanical limb (prostheses) losses, since those are handled in a way that leaves indexed but null list entries instead of stumps. + qdel(organ) + H.organs_by_name -= organ_name //Making sure the list entry is removed. + + //Replacing lost limbs with the species default. + var/mob/living/carbon/human/temp_holder + for(var/limb_type in H.species.has_limbs) + if(!(limb_type in H.organs_by_name)) + var/list/organ_data = H.species.has_limbs[limb_type] + var/limb_path = organ_data["path"] + var/obj/item/organ/external/O = new limb_path(temp_holder) + if(H.get_limb_by_name(O.name)) //Check to see if the user already has an limb with the same name as the 'missing limb'. If they do, skip regrowth. + continue //In an example, this will prevent duplication of the mob's right arm if the mob is a Human and they have a Diona right arm, since, + //while the limb with the name 'right_arm' the mob has may not be listed in their species' bodyparts definition, it is still viable and has the appropriate limb name. + else + O = new limb_path(H) //Create the limb on the player. + O.owner = H + H.organs |= H.organs_by_name[O.limb_name] + + //Replacing lost organs with the species default. + temp_holder = new /mob/living/carbon/human() + for(var/index in H.species.has_organ) + var/organ = H.species.has_organ[index] + if(!(organ in types_of_int_organs)) //If the mob is missing this particular organ... + var/obj/item/organ/internal/I = new organ(temp_holder) //Create the organ inside our holder so we can check it before implantation. + if(H.get_organ_slot(I.slot)) //Check to see if the user already has an organ in the slot the 'missing organ' belongs to. If they do, skip implantation. + continue //In an example, this will prevent duplication of the mob's eyes if the mob is a Human and they have Nucleation eyes, since, + //while the organ in the eyes slot may not be listed in the mob's species' organs definition, it is still viable and fits in the appropriate organ slot. + else + I = new organ(H) //Create the organ inside the player. + I.insert(H) + /mob/living/carbon/human/revive() if(species && !(species.flags & NO_BLOOD)) @@ -1262,9 +1310,18 @@ vessel.add_reagent(blood_reagent, max_blood-vessel.total_volume) fixblood() - // Fix up all organs. - // This will ignore any prosthetics in the prefs currently. - species.create_organs(src) + //Fix up all organs and replace lost ones. + restore_all_organs() //Rejuvenate and reset all existing organs. + check_and_regenerate_organs(src) //Regenerate limbs and organs only if they're really missing. + surgeries.Cut() //End all surgeries. + update_revive() + + if(species.name != "Skeleton" && (SKELETON in mutations)) + mutations.Remove(SKELETON) + if(NOCLONE in mutations) + mutations.Remove(NOCLONE) + if(HUSK in mutations) + mutations.Remove(HUSK) if(!client || !key) //Don't boot out anyone already in the mob. for (var/obj/item/organ/internal/brain/H in world) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index d44bfbbb27f..5d79e3f6237 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -39,6 +39,10 @@ if(back) tally += back.slowdown + if(l_hand && (l_hand.flags & HANDSLOW)) + tally += l_hand.slowdown + if(r_hand && (r_hand.flags & HANDSLOW)) + tally += r_hand.slowdown if(FAT in src.mutations) tally += 1.5 diff --git a/code/modules/mob/living/carbon/human/species/abductor.dm b/code/modules/mob/living/carbon/human/species/abductor.dm index 1c641b27af0..bb1f3dd2067 100644 --- a/code/modules/mob/living/carbon/human/species/abductor.dm +++ b/code/modules/mob/living/carbon/human/species/abductor.dm @@ -24,4 +24,6 @@ H.gender = NEUTER if(H.mind) H.mind.abductor = new /datum/abductor - return ..() \ No newline at end of file + H.languages.Cut() //Under no condition should you be able to speak any language + H.add_language("Abductor Mindlink") //other than over the abductor's own mindlink + return ..() diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index 00398c0f0fa..65d100dc420 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -280,6 +280,17 @@ male_scream_sound = 'sound/voice/shriek1.ogg' female_scream_sound = 'sound/voice/shriek1.ogg' + has_organ = list( + "heart" = /obj/item/organ/internal/heart, + "lungs" = /obj/item/organ/internal/lungs, + "liver" = /obj/item/organ/internal/liver, + "kidneys" = /obj/item/organ/internal/kidneys, + "brain" = /obj/item/organ/internal/brain, + "appendix" = /obj/item/organ/internal/appendix, + "eyes" = /obj/item/organ/internal/eyes, + "stack" = /obj/item/organ/internal/stack/vox //Not the same as the cortical stack implant Vox Raiders spawn with. The cortical stack implant is used + ) //for determining the success of the heist game-mode's 'leave nobody behind' objective, while this is just an organ. + suicide_messages = list( "is attempting to bite their tongue off!", "is jamming their claws into their eye sockets!", @@ -370,8 +381,8 @@ "kidneys" = /obj/item/organ/internal/kidneys, "brain" = /obj/item/organ/internal/brain, "eyes" = /obj/item/organ/internal/eyes, - "stack" = /obj/item/organ/internal/stack/vox - ) + "stack" = /obj/item/organ/internal/stack/vox //Not the same as the cortical stack implant Vox Raiders spawn with. The cortical stack implant is used + ) //for determining the success of the heist game-mode's 'leave nobody behind' objective, while this is just an organ. suicide_messages = list( "is attempting to bite their tongue off!", diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 1b5f6c25735..45bc15b1d51 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -574,6 +574,8 @@ var/global/list/damage_icon_parts = list() UpdateDamageIcon() update_icons() update_fire() + force_update_limbs() + update_tail_layer(0) /* --------------------------------------- */ //vvvvvv UPDATE_INV PROCS vvvvvv diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index dbdb6ee0a7f..d00ed375c33 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -320,7 +320,6 @@ /mob/living/proc/revive() rejuvenate() - buckled = initial(src.buckled) if(iscarbon(src)) var/mob/living/carbon/C = src @@ -348,6 +347,8 @@ timeofdeath = 0 /mob/living/proc/rejuvenate() + var/mob/living/carbon/human/human_mob = null //Get this declared for use later. + // shut down various types of badness setToxLoss(0) setOxyLoss(0) @@ -366,6 +367,7 @@ drowsyness = 0 radiation = 0 druggy = 0 + hallucination = 0 nutrition = 400 bodytemperature = 310 sdisabilities = 0 @@ -380,7 +382,13 @@ fire_stacks = 0 on_fire = 0 suiciding = 0 - buckled = initial(src.buckled) + if(buckled) //Unbuckle the mob and clear the alerts. + buckled.buckled_mob = null + buckled = null + anchored = initial(src.anchored) + update_canmove() + clear_alert("buckled") + post_buckle_mob(src) if(iscarbon(src)) var/mob/living/carbon/C = src @@ -392,12 +400,13 @@ // restore all of the human's blood and reset their shock stage if(ishuman(src)) - var/mob/living/carbon/human/human_mob = src + human_mob = src human_mob.restore_blood() human_mob.shock_stage = 0 human_mob.decaylevel = 0 restore_all_organs() + surgeries.Cut() //End all surgeries. if(stat == DEAD) dead_mob_list -= src living_mob_list += src @@ -406,6 +415,9 @@ stat = CONSCIOUS update_fire() regenerate_icons() + if(human_mob) + human_mob.update_eyes() + human_mob.update_dna() return /mob/living/proc/UpdateDamageIcon() diff --git a/code/modules/mob/living/silicon/pai/death.dm b/code/modules/mob/living/silicon/pai/death.dm index 6ad793fff88..0f938ab31b0 100644 --- a/code/modules/mob/living/silicon/pai/death.dm +++ b/code/modules/mob/living/silicon/pai/death.dm @@ -1,12 +1,13 @@ -/mob/living/silicon/pai/death(gibbed) +/mob/living/silicon/pai/death(gibbed, cleanWipe) if(stat == DEAD) return - force_fold_out() + if(!cleanWipe) + force_fold_out() var/turf/T = get_turf_or_move(loc) for (var/mob/M in viewers(T)) - M.show_message("\red [src] emits a dull beep before it loses power and collapses.", 3, "\red You hear a dull beep followed by the sound of glass crunching.", 2) + M.show_message("[src] emits a dull beep before it loses power and collapses.", 3, "You hear a dull beep followed by the sound of glass crunching.", 2) name = "pAI debris" desc = "The unfortunate remains of some poor personal AI device." icon_state = "[chassis]_dead" @@ -24,5 +25,5 @@ if(mind) qdel(mind) living_mob_list -= src ghostize() - if(icon_state != "[chassis]_dead") + if(icon_state != "[chassis]_dead" || cleanWipe) qdel(src) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index cba9fb4c1e1..81c781b51ff 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -298,6 +298,7 @@ var/list/robot_verbs_default = list( module_sprites["Bro"] = "Brobot" module_sprites["Rich"] = "maximillion" module_sprites["Default"] = "Service2" + module_sprites["Standard"] = "robotServ" if("Miner") module = new /obj/item/weapon/robot_module/miner(src) @@ -307,6 +308,7 @@ var/list/robot_verbs_default = list( module_sprites["Basic"] = "Miner_old" module_sprites["Advanced Droid"] = "droid-miner" module_sprites["Treadhead"] = "Miner" + module_sprites["Standard"] = "robotMine" if("Medical") module = new /obj/item/weapon/robot_module/medical(src) @@ -317,6 +319,7 @@ var/list/robot_verbs_default = list( module_sprites["Standard"] = "surgeon" module_sprites["Advanced Droid"] = "droid-medical" module_sprites["Needles"] = "medicalrobot" + module_sprites["Standard"] = "robotMedi" status_flags &= ~CANPUSH if("Security") @@ -326,6 +329,7 @@ var/list/robot_verbs_default = list( module_sprites["Red Knight"] = "Security" module_sprites["Black Knight"] = "securityrobot" module_sprites["Bloodhound"] = "bloodhound" + module_sprites["Standard"] = "robotSecy" status_flags &= ~CANPUSH if("Engineering") @@ -336,6 +340,7 @@ var/list/robot_verbs_default = list( module_sprites["Basic"] = "Engineering" module_sprites["Antique"] = "engineerrobot" module_sprites["Landmate"] = "landmate" + module_sprites["Standard"] = "robotEngi" magpulse = 1 if("Janitor") @@ -344,6 +349,7 @@ var/list/robot_verbs_default = list( module_sprites["Basic"] = "JanBot2" module_sprites["Mopbot"] = "janitorrobot" module_sprites["Mop Gear Rex"] = "mopgearrex" + module_sprites["Standard"] = "robotJani" if("Combat") module = new /obj/item/weapon/robot_module/combat(src) diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm index c824351a7c8..4f8b7753caf 100644 --- a/code/modules/mob/living/simple_animal/friendly/corgi.dm +++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm @@ -603,6 +603,7 @@ var/emagged = 0 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 + loot = list(/obj/effect/decal/cleanable/blood/gibs/robot) /mob/living/simple_animal/pet/corgi/Ian/borgi/emag_act(user as mob) if(!emagged) @@ -651,7 +652,6 @@ /mob/living/simple_animal/pet/corgi/Ian/borgi/death() ..() visible_message("[src] blows apart!") - new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread s.set_up(3, 1, src) s.start() diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm index 54b0d10608a..c24b0b6a844 100644 --- a/code/modules/mob/living/simple_animal/hostile/bees.dm +++ b/code/modules/mob/living/simple_animal/hostile/bees.dm @@ -140,13 +140,15 @@ /mob/living/simple_animal/hostile/poison/bees/worker/Destroy() if(beehome) - beehome.bees.Remove(src) + if(beehome.bees) + beehome.bees.Remove(src) beehome = null ..() /mob/living/simple_animal/hostile/poison/bees/worker/death(gibbed) if(beehome) - beehome.bees.Remove(src) + if(beehome.bees) + beehome.bees.Remove(src) beehome = null ..() @@ -159,8 +161,8 @@ /mob/living/simple_animal/hostile/poison/bees/worker/Found(atom/A) if(istype(A, /obj/machinery/portable_atmospherics/hydroponics)) var/obj/machinery/portable_atmospherics/hydroponics/Hydro = A - if(Hydro.seed && !Hydro.dead && !Hydro.recent_bee_visit) - wanted_objects |= /obj/machinery/portable_atmospherics/hydroponics //so we only hunt them while they're alive/seeded/not visisted + if(Hydro.seed && !Hydro.dead && !Hydro.recent_bee_visit && !Hydro.closed_system) + wanted_objects |= /obj/machinery/portable_atmospherics/hydroponics //so we only hunt them while they're alive/seeded/not visisted and uncovered return 1 ..() @@ -186,7 +188,7 @@ ..() /mob/living/simple_animal/hostile/poison/bees/worker/proc/pollinate(obj/machinery/portable_atmospherics/hydroponics/Hydro) - if(!istype(Hydro) || !Hydro.seed || Hydro.dead || Hydro.recent_bee_visit) + if(!istype(Hydro) || !Hydro.seed || Hydro.dead || Hydro.recent_bee_visit || Hydro.closed_system) target = null return @@ -205,11 +207,15 @@ if(prob(BEE_POLLINATE_YIELD_CHANCE)) //Yield mod is HELLA powerful, but quite rare if(!isnull(plant_controller.seeds[Hydro.seed.name])) Hydro.seed = Hydro.seed.diverge() + else + Hydro.seed.update_name_prefixes() var/seed_yield = Hydro.seed.get_trait(TRAIT_YIELD) Hydro.seed.set_trait(TRAIT_YIELD, seed_yield + 1, 10, 0) if(prob(BEE_POLLINATE_POTENTCY_CHANCE)) if(!isnull(plant_controller.seeds[Hydro.seed.name])) Hydro.seed = Hydro.seed.diverge() + else + Hydro.seed.update_name_prefixes() var/seed_potency = Hydro.seed.get_trait(TRAIT_POTENCY) Hydro.seed.set_trait(TRAIT_POTENCY, seed_potency + 1, 200, 0) diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm index 4412dc77829..94cf8dae65c 100644 --- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm +++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm @@ -23,6 +23,7 @@ minbodytemp = 0 speak_emote = list("states") gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE + loot = list(/obj/effect/decal/cleanable/blood/gibs/robot) /mob/living/simple_animal/hostile/hivebot/range name = "Hivebot" @@ -47,7 +48,6 @@ /mob/living/simple_animal/hostile/hivebot/death() ..() visible_message("[src] blows apart!") - new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread s.set_up(3, 1, src) s.start() diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index b1627d17af0..418c30199d0 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -118,8 +118,8 @@ return 1 if(istype(the_target, /obj/spacepod)) var/obj/spacepod/S = the_target - if(S.occupant || S.occupant2)//Just so we don't attack empty mechs - if(CanAttack(S.occupant) || CanAttack(S.occupant2)) + if(S.pilot) //Just so we don't attack empty pods + if(CanAttack(S.pilot)) return 1 if(isliving(the_target)) var/mob/living/L = the_target @@ -299,7 +299,7 @@ return /mob/living/simple_animal/hostile/proc/FindHidden() - if(istype(target.loc, /obj/structure/closet) || istype(target.loc, /obj/machinery/disposal) || istype(target.loc, /obj/machinery/sleeper)) + if(istype(target.loc, /obj/structure/closet) || istype(target.loc, /obj/machinery/disposal) || istype(target.loc, /obj/machinery/sleeper) || istype(target.loc, /obj/machinery/bodyscanner) || istype(target.loc, /obj/machinery/recharge_station)) var/atom/A = target.loc Goto(A,move_to_delay,minimum_distance) if(A.Adjacent(src)) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm index 5a9f4a433af..6d2efd88010 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm @@ -73,6 +73,8 @@ aggro_vision_range = 9 idle_vision_range = 2 turns_per_move = 5 + loot = list(/obj/item/weapon/ore/diamond{layer = 4.1}, + /obj/item/weapon/ore/diamond{layer = 4.1}) /obj/item/projectile/temp/basilisk name = "freezing blast" @@ -100,14 +102,6 @@ if(3.0) adjustBruteLoss(110) -/mob/living/simple_animal/hostile/asteroid/basilisk/death() - if(stat != DEAD) - var/counter - for(counter=0, counter<2, counter++) - var/obj/item/weapon/ore/diamond/D = new /obj/item/weapon/ore/diamond(src.loc) - D.layer = 4.1 - ..() - /mob/living/simple_animal/hostile/asteroid/goldgrub name = "goldgrub" desc = "A worm that grows fat from eating everything in its sight. Seems to enjoy precious metals and other shiny things, hence the name." @@ -239,6 +233,7 @@ retreat_distance = 3 minimum_distance = 3 pass_flags = PASSTABLE + loot = list(/obj/item/organ/internal/hivelord_core) /mob/living/simple_animal/hostile/asteroid/hivelord/OpenFire(var/the_target) var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A = new /mob/living/simple_animal/hostile/asteroid/hivelordbrood(src.loc) @@ -250,11 +245,6 @@ /mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget() OpenFire() -/mob/living/simple_animal/hostile/asteroid/hivelord/death() - if(stat != DEAD) - new /obj/item/organ/internal/hivelord_core(src.loc) - ..() - /obj/item/organ/internal/hivelord_core name = "hivelord remains" desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly. Try not to think about what you're eating." @@ -370,6 +360,7 @@ idle_vision_range = 5 anchored = 1 //Stays anchored until death as to be unpullable var/pre_attack = 0 + loot = list(/obj/item/asteroid/goliath_hide{layer = 4.1}) /mob/living/simple_animal/hostile/asteroid/goliath/process_ai() ..() @@ -386,13 +377,6 @@ anchored = 1 ..() -/mob/living/simple_animal/hostile/asteroid/goliath/death() - anchored = 0 - if(stat != DEAD) - var/obj/item/asteroid/goliath_hide/G = new /obj/item/asteroid/goliath_hide(src.loc) - G.layer = 4.1 - ..() - /mob/living/simple_animal/hostile/asteroid/goliath/OpenFire() var/tturf = get_turf(target) if(get_dist(src, target) <= 7)//Screen range check, so you can't get tentacle'd offscreen diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm index fbbc0d0a5e3..89835092ffd 100644 --- a/code/modules/mob/living/simple_animal/hostile/pirate.dm +++ b/code/modules/mob/living/simple_animal/hostile/pirate.dm @@ -22,9 +22,8 @@ atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) unsuitable_atmos_damage = 15 speak_emote = list("yarrs") - var/corpse = /obj/effect/landmark/mobcorpse/pirate - var/weapon1 = /obj/item/weapon/melee/energy/sword/pirate - + loot = list(/obj/effect/landmark/mobcorpse/pirate, + /obj/item/weapon/melee/energy/sword/pirate) faction = list("pirate") /mob/living/simple_animal/hostile/pirate/ranged @@ -38,16 +37,12 @@ retreat_distance = 5 minimum_distance = 5 projectiletype = /obj/item/projectile/beam - corpse = /obj/effect/landmark/mobcorpse/pirate/ranged - weapon1 = /obj/item/weapon/gun/energy/laser + loot = list(/obj/effect/landmark/mobcorpse/pirate/ranged, + /obj/item/weapon/gun/energy/laser) /mob/living/simple_animal/hostile/pirate/death() ..() - if(corpse) - new corpse (src.loc) - if(weapon1) - new weapon1 (src.loc) ghostize() qdel(src) return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm index 5ee52bec825..71d088a425c 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm @@ -150,8 +150,8 @@ walk(src,0) /mob/living/simple_animal/hostile/retaliate/malf_drone/death() - src.visible_message("\blue \icon[src] [src] suddenly breaks apart.") ..() + visible_message("\blue \icon[src] [src] suddenly breaks apart.") qdel(src) /mob/living/simple_animal/hostile/retaliate/malf_drone/Destroy() //Seriously, what the actual hell. diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm index cd34c8a6491..2e3718cd800 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm @@ -14,7 +14,7 @@ return A else if(istype(A, /obj/spacepod)) var/obj/spacepod/M = A - if(M.occupant || M.occupant2) + if(M.pilot) return A /mob/living/simple_animal/hostile/retaliate/ListTargets() @@ -47,9 +47,9 @@ enemies |= M.occupant else if(istype(A, /obj/spacepod)) var/obj/spacepod/M = A - if(M.occupant || M.occupant2) + if(M.pilot) enemies |= M - enemies |= M.occupant + enemies |= M.pilot for(var/mob/living/simple_animal/hostile/retaliate/H in around) var/retaliate_faction_check = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm index 44de372550f..210ff43ebda 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm @@ -45,6 +45,7 @@ minbodytemp = 0 faction = list("undead") // did I mention ghost + loot = list(/obj/item/weapon/reagent_containers/food/snacks/ectoplasm) /mob/living/simple_animal/hostile/retaliate/ghost/Process_Spacemove(var/check_drift = 0) return 1 @@ -61,7 +62,7 @@ invisibility = pick(0,60,60,invisibility) ..() /mob/living/simple_animal/hostile/retaliate/ghost/death() - new /obj/item/weapon/reagent_containers/food/snacks/ectoplasm(loc) + ..() qdel(src) return @@ -90,9 +91,10 @@ minbodytemp = 0 faction = list("undead") + loot = list(/obj/effect/decal/remains/human) /mob/living/simple_animal/hostile/retaliate/skeleton/death() - new /obj/effect/decal/remains/human(loc) + ..() qdel(src) return @@ -121,8 +123,9 @@ minbodytemp = 0 faction = list("undead") + loot = list(/obj/effect/decal/cleanable/blood/gibs) /mob/living/simple_animal/hostile/retaliate/zombie/death() - new /obj/effect/decal/cleanable/blood/gibs(loc) + ..() qdel(src) return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm index 35cdbb14dfb..148eeeef9a7 100644 --- a/code/modules/mob/living/simple_animal/hostile/russian.dm +++ b/code/modules/mob/living/simple_animal/hostile/russian.dm @@ -19,35 +19,30 @@ attacktext = "punches" attack_sound = 'sound/weapons/punch1.ogg' a_intent = I_HARM - var/corpse = /obj/effect/landmark/mobcorpse/russian - var/weapon1 = /obj/item/weapon/kitchen/knife unsuitable_atmos_damage = 15 faction = list("russian") status_flags = CANPUSH + loot = list(/obj/effect/landmark/mobcorpse/russian, + /obj/item/weapon/kitchen/knife) /mob/living/simple_animal/hostile/russian/ranged icon_state = "russianranged" icon_living = "russianranged" - corpse = /obj/effect/landmark/mobcorpse/russian/ranged - weapon1 = /obj/item/weapon/gun/projectile/revolver/mateba ranged = 1 retreat_distance = 5 minimum_distance = 5 projectiletype = /obj/item/projectile/bullet projectilesound = 'sound/weapons/Gunshot.ogg' casingtype = /obj/item/ammo_casing/a357 + loot = list(/obj/effect/landmark/mobcorpse/russian/ranged, /obj/item/weapon/gun/projectile/revolver/mateba) -/mob/living/simple_animal/hostile/russian/ranged/New() - if(prob(50) && ispath(weapon1,/obj/item/weapon/gun/projectile/revolver/mateba)) //to preserve varedits - weapon1 = /obj/item/weapon/gun/projectile/shotgun/boltaction - casingtype = /obj/item/ammo_casing/a762 +/mob/living/simple_animal/hostile/russian/ranged/mosin + loot = list(/obj/effect/landmark/mobcorpse/russian/ranged, + /obj/item/weapon/gun/projectile/shotgun/boltaction) + casingtype = /obj/item/ammo_casing/a762 /mob/living/simple_animal/hostile/russian/death() ..() - if(corpse) - new corpse (src.loc) - if(weapon1) - new weapon1 (src.loc) qdel(src) return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm index 0ce0cc71a86..5546547046d 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -19,22 +19,14 @@ attacktext = "punches" attack_sound = 'sound/weapons/punch1.ogg' a_intent = I_HARM - var/corpse = /obj/effect/landmark/mobcorpse/syndicatesoldier - var/weapon1 - var/weapon2 unsuitable_atmos_damage = 15 faction = list("syndicate") check_friendly_fire = 1 status_flags = CANPUSH + loot = list(/obj/effect/landmark/mobcorpse/syndicatesoldier) /mob/living/simple_animal/hostile/syndicate/death() ..() - if(corpse) - new corpse (src.loc) - if(weapon1) - new weapon1 (src.loc) - if(weapon2) - new weapon2 (src.loc) qdel(src) return @@ -45,11 +37,10 @@ melee_damage_upper = 25 icon_state = "syndicatemelee" icon_living = "syndicatemelee" - weapon1 = /obj/item/weapon/melee/energy/sword/saber/red - weapon2 = /obj/item/weapon/shield/energy attacktext = "slashes" attack_sound = 'sound/weapons/bladeslice.ogg' status_flags = 0 + loot = list(/obj/effect/landmark/mobcorpse/syndicatesoldier, /obj/item/weapon/melee/energy/sword/saber/red, /obj/item/weapon/shield/energy) /mob/living/simple_animal/hostile/syndicate/melee/attackby(var/obj/item/O as obj, var/mob/user as mob, params) if(O.force) @@ -83,8 +74,8 @@ icon_state = "syndicatemeleespace" icon_living = "syndicatemeleespace" name = "Syndicate Commando" - corpse = /obj/effect/landmark/mobcorpse/syndicatecommando speed = 1 + loot = list(/obj/effect/landmark/mobcorpse/syndicatecommando, /obj/item/weapon/melee/energy/sword/saber/red, /obj/item/weapon/shield/energy) /mob/living/simple_animal/hostile/syndicate/melee/space/Process_Spacemove(var/movement_dir = 0) return @@ -99,8 +90,7 @@ casingtype = /obj/item/ammo_casing/c45 projectilesound = 'sound/weapons/Gunshot_smg.ogg' projectiletype = /obj/item/projectile/bullet/midbullet2 - - weapon1 = /obj/item/weapon/gun/projectile/automatic/c20r + loot = list(/obj/effect/landmark/mobcorpse/syndicatesoldier, /obj/item/weapon/gun/projectile/automatic/c20r) /mob/living/simple_animal/hostile/syndicate/ranged/space icon_state = "syndicaterangedpsace" @@ -108,8 +98,9 @@ name = "Syndicate Commando" 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 - corpse = /obj/effect/landmark/mobcorpse/syndicatecommando speed = 1 + loot = list(/obj/effect/landmark/mobcorpse/syndicatecommando, /obj/item/weapon/gun/projectile/automatic/c20r) + /mob/living/simple_animal/hostile/syndicate/ranged/space/Process_Spacemove(var/movement_dir = 0) return diff --git a/code/modules/mob/living/simple_animal/hostile/tree.dm b/code/modules/mob/living/simple_animal/hostile/tree.dm index bd39b681978..b47312b15df 100644 --- a/code/modules/mob/living/simple_animal/hostile/tree.dm +++ b/code/modules/mob/living/simple_animal/hostile/tree.dm @@ -28,6 +28,7 @@ minbodytemp = 0 faction = list("hostile", "winter") + loot = list(/obj/item/stack/sheet/wood) gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE /mob/living/simple_animal/hostile/tree/FindTarget() @@ -46,5 +47,4 @@ /mob/living/simple_animal/hostile/tree/death() ..() visible_message("\red [src] is hacked into pieces!") - new /obj/item/stack/sheet/wood(loc) qdel(src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm b/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm index 5710005846c..12ede5955ea 100644 --- a/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm @@ -20,15 +20,12 @@ melee_damage_lower = 3 melee_damage_upper = 7 - var/weapon1 - /mob/living/simple_animal/hostile/winter/snowman name = "snowman" desc = "A very angry snowman. Doesn't look like it wants to play around..." icon_state = "snowman" icon_living = "snowman" icon_dead = "snowman-dead" - weapon1 = /obj/item/weapon/melee/candy_sword bodytemperature = 73.0 //it's made of snow and hatred, so it's pretty cold. maxbodytemp = 280.15 //at roughly 7 C, these will start melting (dying) from the warmth. Mind over matter or something. @@ -37,10 +34,10 @@ /mob/living/simple_animal/hostile/winter/snowman/death() - if(weapon1 && prob(50)) //50% chance to drop weapon on death, if it has one to drop - new weapon1(get_turf(src)) + if(prob(50)) //50% chance to drop weapon on death, if it has one to drop + loot = list(/obj/item/weapon/melee/candy_sword) if(prob(20)) //chance to become a stationary snowman structure instead of a corpse - new /obj/structure/snowman(get_turf(src)) + loot.Add(/obj/structure/snowman) visible_message("The [src.name] shimmers as its animating magic fades away!") ..() //this is just to make sure it gets properly killed before we qdel it qdel(src) @@ -52,7 +49,6 @@ retreat_distance = 5 minimum_distance = 5 projectiletype = /obj/item/projectile/snowball - weapon1 = null /mob/living/simple_animal/hostile/winter/reindeer name = "reindeer" diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index aa924444a3a..6e528516e3e 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -36,7 +36,11 @@ small = 1 can_collar = 1 - speak = list("Hi","Hello!","Cracker?","BAWWWWK george mellons griffing me") + var/list/clean_speak = list( + "Hi", + "Hello!", + "Cracker?", + "BAWWWWK george mellons griffing me") speak_emote = list("squawks","says","yells") emote_hear = list("squawks","bawks") emote_see = list("flutters its wings") @@ -95,6 +99,7 @@ /obj/item/device/radio/headset/headset_sci, \ /obj/item/device/radio/headset/headset_cargo) ears = new headset(src) + update_speak() parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var @@ -153,14 +158,12 @@ if("ears") if(ears) if(available_channels.len) - src.say("[pick(available_channels)]BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") + say("[pick(available_channels)]BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") else - src.say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") - ears.loc = src.loc + say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") + ears.forceMove(loc) ears = null - for(var/possible_phrase in speak) - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = copytext(possible_phrase,3,length(possible_phrase)) + update_speak() else to_chat(usr, "\red There is nothing to remove from its [remove_from].") return @@ -187,11 +190,11 @@ var/obj/item/device/radio/headset/headset_to_add = item_to_add usr.drop_item() - headset_to_add.loc = src - src.ears = headset_to_add + headset_to_add.forceMove(src) + ears = headset_to_add to_chat(usr, "You fit the headset onto [src].") - clearlist(available_channels) + available_channels.Cut() for(var/ch in headset_to_add.channels) switch(ch) if("Engineering") @@ -211,6 +214,7 @@ if(headset_to_add.translate_binary) available_channels.Add(":b") + update_speak() show_inv(usr) else ..() @@ -279,7 +283,19 @@ if(pulledby && stat == CONSCIOUS) icon_state = "parrot_fly" -/mob/living/simple_animal/parrot/process_ai() +/mob/living/simple_animal/parrot/proc/update_speak() + speak.Cut() + + if(available_channels.len && ears) + for(var/possible_phrase in clean_speak) + //50/50 chance to not use the radio at all + speak += "[prob(50) ? pick(available_channels) : ""][possible_phrase]" + + else //If we have no headset or channels to use, dont try to use any! + for(var/possible_phrase in clean_speak) + speak += possible_phrase + +/mob/living/simple_animal/parrot/handle_automated_movement() if(pulledby) parrot_state = PARROT_WANDER return @@ -294,11 +310,11 @@ Every once in a while, the parrot picks one of the lines from the buffer and replaces an element of the 'speech' list. Then it clears the buffer to make sure they dont magically remember something from hours ago. */ if(speech_buffer.len && prob(10)) - if(speak.len) - speak.Remove(pick(speak)) + if(clean_speak.len) + clean_speak -= pick(clean_speak) - speak.Add(pick(speech_buffer)) - clearlist(speech_buffer) + clean_speak += pick(speech_buffer) + speech_buffer.Cut() //-----SLEEPING @@ -321,30 +337,7 @@ parrot_sleep_dur = parrot_sleep_max //Cycle through message modes for the headset - if(speak.len) - var/list/newspeak = list() - - if(available_channels.len && src.ears) - for(var/possible_phrase in speak) - - //50/50 chance to not use the radio at all - var/useradio = 0 - if(prob(50)) - useradio = 1 - - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = "[useradio?pick(available_channels):""][copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix - else - possible_phrase = "[useradio?pick(available_channels):""][possible_phrase]" - - newspeak.Add(possible_phrase) - - else //If we have no headset or channels to use, dont try to use any! - for(var/possible_phrase in speak) - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = "[copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix - newspeak.Add(possible_phrase) - speak = newspeak + update_speak() //Search for item to steal parrot_interest = search_for_item() @@ -686,7 +679,14 @@ /mob/living/simple_animal/parrot/Poly name = "Poly" desc = "Poly the Parrot. An expert on quantum cracker theory." - speak = list("Poly wanna cracker!", ":eCheck the singlo, you chucklefucks!",":eCheck the tesla, you shits!",":eSTOP HOT-WIRING THE ENGINE, FUCKING CHRIST!",":eWire the solars, you lazy bums!",":eWHO TOOK THE DAMN HARDSUITS?",":eOH GOD ITS FREE CALL THE SHUTTLE") + clean_speak = list( + "Poly wanna cracker!", + "Check the singlo, you chucklefucks!", + "Check the tesla, you shits!", + "STOP HOT-WIRING THE ENGINE, FUCKING CHRIST!", + "Wire the solars, you lazy bums!", + "WHO TOOK THE DAMN HARDSUITS?", + "OH GOD ITS FREE CALL THE SHUTTLE") gold_core_spawnable = CHEM_MOB_SPAWN_INVALID /mob/living/simple_animal/parrot/Poly/New() @@ -700,15 +700,15 @@ used_radios += ears /mob/living/simple_animal/parrot/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null) - if(prob(50)) + if(speaker != src && prob(50)) parrot_hear(html_decode(message)) ..() /mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/atom/follow_target) - if(prob(50)) - parrot_hear("[pick(available_channels)][html_decode(message)]") + if(speaker != src && prob(50)) + parrot_hear(html_decode(message)) ..() diff --git a/code/modules/mob/living/simple_animal/posessed_object.dm b/code/modules/mob/living/simple_animal/posessed_object.dm new file mode 100644 index 00000000000..0029bbec7fd --- /dev/null +++ b/code/modules/mob/living/simple_animal/posessed_object.dm @@ -0,0 +1,154 @@ +/mob/living/simple_animal/possessed_object + name = "possessed doodad" + var/spirit_name = "mysterious force" // What we call ourselves in attack messages. + health = 50 + maxHealth = 50 + + pass_flags = PASSTABLE // Floating past tables is pretty damn spooky. + status_flags = null // No canpush to prevent grabs ... + density = 0 // ... But a density of 0 means we won't be blocking anyone's way. + healable = 0 // Animated with SPACE NECROMANCY, mere mortal medicines cannot heal such an object. + wander = 0 // These things probably ought to never be AI controlled, but in the event they are probably shouldn't wander. + + universal_speak = 1 // Tell the humans spooky things about the afterlife + speak_emote = list("mumbles", "moans", "whispers", "laments", "screeches") + + allow_spin = 0 // No spinning. Spinning breaks our floating animation and broken floating animations make ghosts SUPER ANGRY. + no_spin_thrown = 1 + + var/obj/item/possessed_item + + +/mob/living/simple_animal/possessed_object/examine() + possessed_item.examine() + if(health > (maxHealth / 30)) + to_chat(usr, "[src] appears to be floating without any support!") + else + to_chat(usr, "[src] appears to be having trouble staying afloat!") + + +/mob/living/simple_animal/possessed_object/do_attack_animation(atom/A) + ..() + animate_ghostly_presence(src, -1, 20, 1) // Restart the floating animation after the attack animation, as it will be cancelled. + + +/mob/living/simple_animal/possessed_object/start_pulling(var/atom/movable/AM) // Silly motherfuckers think they can pull things. + to_chat(src, "You are unable to pull [AM]!") + + +/mob/living/simple_animal/possessed_object/ghost() // Ghosting will return the object to normal, and will not disqualify the ghoster from various mid-round antag positions. + var/response = alert(src, "End your possession of this object? (It will not stop you from respawning later)","Are you sure you want to ghost?","Ghost","Stay in body") + if(response != "Ghost") + return + resting = 1 + var/mob/dead/observer/ghost = ghostize(1) + ghost.timeofdeath = world.time + death(0) // Turn back into a regular object. + + +/mob/living/simple_animal/possessed_object/death(gibbed) + ..() + + if(gibbed) // Leave no trace. + var/mob/dead/observer/ghost = ghostize(1) + ghost.timeofdeath = world.time + qdel(src) + return + + possessed_item.forceMove(loc) // Put the normal item back once the EVIL SPIRIT has been vanquished from it. + qdel(src) + + +/mob/living/simple_animal/possessed_object/Life() + ..() + + if(!possessed_item) // If we're a donut and someone's eaten us, for instance. + death(1) + + if(possessed_item.loc != src) + forceMove(possessed_item.loc) + possessed_item.forceMove(src) + + if(l_hand) // Incase object interactions put things directly into our hands. (Like cameras, or gun magizines) + drop_l_hand() + if(r_hand) + drop_r_hand() + +/mob/living/simple_animal/possessed_object/New(var/atom/loc as obj) + ..() + + if (!istype(loc, /obj/item)) // Some silly motherfucker spawned us directly via the game panel. + message_admins("Posessed object improperly spawned, deleting.") // So silly admins with debug off will see the message too and not spam these things. + log_debug("[src] spawned manually, no object to assign attributes to.") + qdel() + + var/turf/possessed_loc = get_turf(loc) + if(!istype(possessed_loc)) // Will this ever happen? Who goddamn knows. + message_admins("Posessed object could not find turf, deleting.") // So silly admins with debug off will see the message too and not spam these things. + log_debug("[src] attempted to find a turf to spawn on, and could not.") + qdel() + + possessed_item = loc + forceMove(possessed_loc) + possessed_item.forceMove(src) // We'll keep the actual item inside of us until we die. + + zone_sel = new /obj/screen/zone_sel(src) // Create a new zone selection item so the human attacks have something to reference. + + name = possessed_item.name // Take on all the attributes of the item we've possessed. + real_name = name + desc = possessed_item.desc + icon = possessed_item.icon + icon_living = possessed_item.icon_state + icon_state = possessed_item.icon_state + dir = possessed_item.dir + color = possessed_item.color + overlays = possessed_item.overlays + opacity = possessed_item.opacity + + visible_message("[src] rises into the air and begins to float!") // Inform those around us that shit's gettin' spooky. + animate_ghostly_presence(src, -1, 20, 1) + + +/mob/living/simple_animal/possessed_object/get_active_hand() // So that our attacks count as attacking with the item we've possessed. + return possessed_item + + +/mob/living/simple_animal/possessed_object/IsAdvancedToolUser() // So we can shoot guns (Mostly ourselves), among other things. + return 1 + + +/mob/living/simple_animal/possessed_object/get_access() // If we've possessed an ID card we've got access to lots of fun things! + if(istype(possessed_item, /obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/possessed_id = possessed_item + . = possessed_id.access + + +/mob/living/simple_animal/possessed_object/ClickOn(var/atom/A, var/params) + if(client.click_intercept) + client.click_intercept.InterceptClickOn(src, params, A) + return + + if(!istype(loc, /turf)) // If we're inside a card machine or something similar then you're stuck. + return + + name = spirit_name + + if(A == src) // If we're clicking ourself we should not attack ourself. + possessed_item.attack_self(src) + else + ..() + + if(possessed_item.loc != src) // If we've, say, placed the possessed item on the table move onto the table ourselves instead and put it back inside of us. + forceMove(possessed_item.loc) + possessed_item.forceMove(src) + + name = possessed_item.name // Update our status + real_name = name + desc = possessed_item.desc + icon = possessed_item.icon + icon_living = possessed_item.icon_state + icon_state = possessed_item.icon_state + dir = possessed_item.dir + color = possessed_item.color + overlays = possessed_item.overlays + opacity = possessed_item.opacity \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm index 0e01aa51894..9aff96b1fcf 100644 --- a/code/modules/mob/living/simple_animal/shade.dm +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -24,11 +24,11 @@ status_flags = 0 faction = list("cult") status_flags = CANPUSH + loot = list(/obj/item/weapon/reagent_containers/food/snacks/ectoplasm) death() ..() - new /obj/item/weapon/reagent_containers/food/snacks/ectoplasm (src.loc) for(var/mob/M in viewers(src, null)) if((M.client && !( M.blinded ))) M.show_message("\red [src] lets out a contented sigh as their form unwinds. ") diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 9a638ce3a80..9eee62d810a 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -71,6 +71,7 @@ var/master_commander = null //holding var for determining who own/controls a sentient simple animal (for sentience potions). var/sentience_type = SENTIENCE_ORGANIC // Sentience type, for slime potions + var/list/loot = list() //list of things spawned at mob's loc when it dies /mob/living/simple_animal/New() @@ -467,6 +468,9 @@ stat(null, "Health: [round((health / maxHealth) * 100)]%") /mob/living/simple_animal/death(gibbed) + if(loot.len) + for(var/i in loot) + new i(loc) health = 0 icon_state = icon_dead stat = DEAD @@ -532,7 +536,7 @@ return 0 if (istype(the_target,/obj/spacepod)) var/obj/spacepod/S = the_target - if (S.occupant || S.occupant2) + if (S.pilot) return 0 return 1 diff --git a/code/modules/mob/new_player/login.dm b/code/modules/mob/new_player/login.dm index f6e2441e876..bbb0211ce67 100644 --- a/code/modules/mob/new_player/login.dm +++ b/code/modules/mob/new_player/login.dm @@ -34,6 +34,10 @@ verbs += /client/proc/readmin spawn(40) if(client) + if(client.prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates. -CP + winset(client, "rpane.changelog", "background-color=#f4aa94;font-style=bold") + client.prefs.SetChangelog(client,changelog_hash) + to_chat(src, "Changelog has changed since your last visit.") client.playtitlemusic() if(config.player_overflow_cap && config.overflow_server_url) //Overflow rerouting, if set, forces players to be moved to a different server once a player cap is reached. Less rough than a pure kick. @@ -44,4 +48,3 @@ tally++ if(tally > config.player_overflow_cap) src << link(config.overflow_server_url) - diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index c427f6e7a50..60285b092fc 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -446,14 +446,14 @@ chosen_species = all_species[client.prefs.species] if(!(chosen_species && (is_species_whitelisted(chosen_species) || has_admin_rights()))) // Have to recheck admin due to no usr at roundstart. Latejoins are fine though. - log_to_dd("[src] had species [client.prefs.species], though they weren't supposed to. Setting to Human.") + log_debug("[src] had species [client.prefs.species], though they weren't supposed to. Setting to Human.") client.prefs.species = "Human" var/datum/language/chosen_language if(client.prefs.language) chosen_language = all_languages[client.prefs.language] - if(!((chosen_language || client.prefs.language == "None") && (is_alien_whitelisted(src, client.prefs.language) || !config.usealienwhitelist || !(chosen_language.flags & WHITELISTED)))) - log_to_dd("[src] had language [client.prefs.language], though they weren't supposed to. Setting to None.") + if((chosen_language == null && chosen_language != "None") || (chosen_language && chosen_language.flags & RESTRICTED)) + log_debug("[src] had language [client.prefs.language], though they weren't supposed to. Setting to None.") client.prefs.language = "None" /mob/new_player/proc/ViewManifest() diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index e5b12ed022b..e3e8d4620be 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -40,7 +40,7 @@ usr.emote(message) /mob/proc/say_dead(var/message) - if(!src.client.holder) + if(!(client && client.holder)) if(!config.dsay_allowed) to_chat(src, "Deadchat is globally muted.") return diff --git a/code/modules/nano/modules/power_monitor.dm b/code/modules/nano/modules/power_monitor.dm index d6df0229085..f2c9297b1a9 100644 --- a/code/modules/nano/modules/power_monitor.dm +++ b/code/modules/nano/modules/power_monitor.dm @@ -2,7 +2,7 @@ name = "Power monitor" var/select_monitor = 0 var/obj/machinery/computer/monitor/powermonitor - + /datum/nano_module/power_monitor/silicon select_monitor = 1 @@ -10,33 +10,33 @@ ..() if(!select_monitor) powermonitor = nano_host() - + /datum/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) var/data[0] - + data["powermonitor"] = powermonitor if(select_monitor) data["select_monitor"] = 1 data["powermonitors"] = powermonitor_repository.powermonitor_data() - - if (powermonitor && !isnull(powermonitor.powernet)) + + if (powermonitor && !isnull(powermonitor.powernet)) if(select_monitor && (powermonitor.stat & (NOPOWER|BROKEN))) powermonitor = null return data["poweravail"] = powermonitor.powernet.avail - data["powerload"] = num2text(powermonitor.powernet.viewload,10) + data["powerload"] = powermonitor.powernet.viewload data["powerdemand"] = powermonitor.powernet.load data["apcs"] = apc_repository.apc_data(powermonitor) - + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 700, state = state) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) - + /datum/nano_module/power_monitor/Topic(href, href_list) - if(..()) + if(..()) return 1 if(href_list["selectmonitor"]) @@ -44,9 +44,8 @@ powermonitor = locate(href_list["selectmonitor"]) powermonitor.powernet = powermonitor.find_powernet() // Refresh the powernet of the monitor return 1 - + if(href_list["return"]) if(issilicon(usr)) powermonitor = null return 1 - \ No newline at end of file diff --git a/code/modules/pda/core_apps.dm b/code/modules/pda/core_apps.dm index 065253fcfab..4aaaa0667e7 100644 --- a/code/modules/pda/core_apps.dm +++ b/code/modules/pda/core_apps.dm @@ -97,15 +97,15 @@ var/co2_level = environment.carbon_dioxide/total_moles var/plasma_level = environment.toxins/total_moles var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) - data["aircontents"] = list(\ - "pressure" = "[round(pressure,0.1)]",\ - "nitrogen" = "[round(n2_level*100,0.1)]",\ - "oxygen" = "[round(o2_level*100,0.1)]",\ - "carbon_dioxide" = "[round(co2_level*100,0.1)]",\ - "plasma" = "[round(plasma_level*100,0.01)]",\ - "other" = "[round(unknown_level, 0.01)]",\ - "temp" = "[round(environment.temperature-T0C,0.1)]",\ - "reading" = 1\ + data["aircontents"] = list( + "pressure" = pressure, + "nitrogen" = n2_level*100, + "oxygen" = o2_level*100, + "carbon_dioxide" = co2_level*100, + "plasma" = plasma_level*100, + "other" = unknown_level, + "temp" = environment.temperature-T0C, + "reading" = 1 ) if(isnull(data["aircontents"])) data["aircontents"] = list("reading" = 0) \ No newline at end of file diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index edefabf2aff..a66eba09713 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -815,16 +815,12 @@ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) // the ui does not exist, so we'll create a new one - ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 510, data["siliconUser"] ? 465 : 390) + ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 510, data["siliconUser"] ? 535 : 460) // When the UI is first opened this is the data it will use ui.set_initial_data(data) ui.open() // Auto update every Master Controller tick ui.set_auto_update(1) - else - // The UI is already open so push the new data to it - ui.push_data(data) - return /obj/machinery/power/apc/proc/report() return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])" diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 0df18d27150..78ac0d7093a 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -707,3 +707,12 @@ sharp = 1 playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) update() + +/obj/item/weapon/light/suicide_act(mob/living/carbon/human/user) + user.visible_message("[user] touches \the [src], burning their hands off!", "You touch \the [src], burning your hands off!") + + for(var/oname in list("l_hand", "r_hand")) + var/obj/item/organ/external/limb = user.get_organ(oname) + if(limb) + limb.droplimb(0, DROPLIMB_BURN) + return FIRELOSS \ No newline at end of file diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 44f78fa4e38..c8f5fc312e8 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -293,7 +293,7 @@ var/autostart = 0 // Automatically search for connected devices var/obj/machinery/power/tracker/connected_tracker = null var/list/connected_panels = list() - + // Used for mapping in solar array which automatically starts itself (telecomms, for example) /obj/machinery/power/solar_control/autostart track = 2 // Auto tracking mode @@ -301,7 +301,7 @@ /obj/machinery/power/solar_control/initialize() ..() - if(!powernet) + if(!powernet) return connect_to_network() set_panels(cdir) @@ -375,17 +375,17 @@ /obj/machinery/power/solar_control/attack_ai(mob/user as mob) src.add_hiddenprint(user) ui_interact(user) - + /obj/machinery/power/solar_control/attack_ghost(mob/user as mob) - ui_interact(user) - + ui_interact(user) + /obj/machinery/power/solar_control/attack_hand(mob/user) if(..(user)) return 1 - + if(stat & BROKEN) return - + ui_interact(user) /obj/machinery/power/solar_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) @@ -409,9 +409,6 @@ ui.set_initial_data(data) ui.open() ui.set_auto_update(1) - else - ui.push_data(data) - return /obj/machinery/power/solar_control/attackby(I as obj, user as mob, params) if(istype(I, /obj/item/weapon/screwdriver)) diff --git a/code/modules/reagents/newchem/drinks.dm b/code/modules/reagents/newchem/drinks.dm index 01920c617c3..c09b1a06fba 100644 --- a/code/modules/reagents/newchem/drinks.dm +++ b/code/modules/reagents/newchem/drinks.dm @@ -67,7 +67,7 @@ mix_sound = 'sound/goonstation/misc/drinkfizz.ogg' -/datum/reagent/ethanol/dragons_breath +/datum/reagent/ethanol/dragons_breath //inaccessible to players, but here for admin shennanigans name = "Dragon's Breath" id = "dragonsbreath" description = "Possessing this stuff probably breaks the Geneva convention." @@ -108,15 +108,6 @@ return ..() -/datum/chemical_reaction/dragons_breath - name = "Dragon's Breath" - id = "dragonsbreath" - result = "dragonsbreath" - required_reagents = list("whiskey" = 1, "phlogiston" = 1, "pyrosium" = 1, "fuel" = 1, "ghostchilijuice"= 1) - result_amount = 1 - mix_message = "A tiny mushroom cloud erupts from the container. That's not worrying at all!" - mix_sound = 'sound/effects/meteorimpact.ogg' - // ROBOT ALCOHOL PAST THIS POINT // WOOO! diff --git a/code/modules/reagents/newchem/drugs.dm b/code/modules/reagents/newchem/drugs.dm index 62daeee99a3..20607ac87a4 100644 --- a/code/modules/reagents/newchem/drugs.dm +++ b/code/modules/reagents/newchem/drugs.dm @@ -242,10 +242,6 @@ addiction_chance = 60 metabolization_rate = 0.6 -/datum/reagent/methamphetamine/meth2 //for donk pockets - id = "methamphetamine2" - addiction_chance = 0 - /datum/reagent/methamphetamine/on_mob_life(var/mob/living/M as mob) if(!M) M = holder.my_atom if(prob(5)) diff --git a/code/modules/reagents/newchem/food.dm b/code/modules/reagents/newchem/food.dm index e8b5ed3f681..97643169e6f 100644 --- a/code/modules/reagents/newchem/food.dm +++ b/code/modules/reagents/newchem/food.dm @@ -600,45 +600,4 @@ datum/reagent/pepperoni/reaction_mob(var/mob/living/M, var/method=TOUCH, var/vol var/mob/living/carbon/human/H = M if(!H.heart_attack) H.heart_attack = 1 - ..() - -/datum/reagent/ghost_chili_juice - name = "Ghost chili juice" - id = "ghostchilijuice" - description = "Juice from the universe's hottest chilli. Do not consume." - reagent_state = LIQUID - color = "#FF7F32" - -/datum/reagent/ghost_chili_juice/on_mob_life(var/mob/living/M as mob) - if(!M) M = holder.my_atom - if(M.reagents.has_reagent("milk")) - to_chat(M, "The milk stops the burning. Ahhh.") - M.reagents.del_reagent("milk") - M.reagents.del_reagent("ghostchilijuice") - return - if(prob(8)) - to_chat(M, "Oh god! Oh GODD!!") - if(prob(50)) - to_chat(M, "Your throat burns furiously!") - M.emote(pick("scream","cry","choke","gasp")) - M.Stun(1) - if(prob(8)) - to_chat(M, "Why!? WHY!?") - if(prob(8)) - to_chat(M, "ARGHHHH!") - if(prob(33)) - M.visible_message("[M] suddenly and violently vomits!") - M.fakevomit(no_text = 1) - to_chat(M, "Thank goodness. You're not sure how long you could have held out with heat that intense!") - M.reagents.del_reagent("ghostchilijuice") - return - if(prob(10)) - to_chat(M, "OH GOD OH GOD PLEASE NO!!") - if(M.on_fire) - M.adjust_fire_stacks(5) - if(prob(50)) - to_chat(M, "IT BURNS!!!!") - M.visible_message("[M] is consumed in flames!") - M.dust() - return ..() \ No newline at end of file diff --git a/code/modules/reagents/newchem/medicine.dm b/code/modules/reagents/newchem/medicine.dm index aca5897735c..33f04d5e6a8 100644 --- a/code/modules/reagents/newchem/medicine.dm +++ b/code/modules/reagents/newchem/medicine.dm @@ -646,11 +646,14 @@ datum/reagent/strange_reagent metabolization_rate = 0.2 datum/reagent/strange_reagent/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume) - if(istype(M, /mob/living/simple_animal)) + if(isanimal(M)) if(method == TOUCH) - if(M.stat == DEAD) - M.revive() - M.visible_message("[M] seems to rise from the dead!") + var/mob/living/simple_animal/SM = M + if(SM.stat == DEAD) + SM.revive() + SM.loot.Cut() //no abusing strange reagent for unlimited farming of resources + SM.visible_message("[M] seems to rise from the dead!") + if(istype(M, /mob/living/carbon)) if(method == INGEST) if(M.stat == DEAD) diff --git a/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_slime.dm b/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_slime.dm index e9dd50dcf67..9a48e07e6a5 100644 --- a/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_slime.dm +++ b/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_slime.dm @@ -510,7 +510,7 @@ feedback_add_details("slime_cores_used","[type]") var/obj/effect/golemrune/Z = new /obj/effect/golemrune Z.forceMove(get_turf(holder.my_atom)) - notify_ghosts("Golem rune created in [get_area(Z)].", 'sound/effects/ghost2.ogg', source = Z) + notify_ghosts("Golem rune created in [get_area(Z)].", source = Z) //Bluespace /datum/chemical_reaction/slimefloor2 diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm index b92aceb4c79..9d67bb22881 100644 --- a/code/modules/reagents/reagent_containers/borghydro.dm +++ b/code/modules/reagents/reagent_containers/borghydro.dm @@ -2,7 +2,7 @@ /obj/item/weapon/reagent_containers/borghypo name = "Cyborg Hypospray" desc = "An advanced chemical synthesizer and injection system, designed for heavy-duty medical equipment." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/obj/hypo.dmi' item_state = "hypo" icon_state = "borghypo" amount_per_transfer_from_this = 5 @@ -23,7 +23,7 @@ /obj/item/weapon/reagent_containers/borghypo/crisis reagent_ids = list("salglu_solution", "epinephrine", "sal_acid") - + /obj/item/weapon/reagent_containers/borghypo/syndicate name = "syndicate cyborg hypospray" desc = "An experimental piece of Syndicate technology used to produce powerful restorative nanites used to very quickly restore injuries of all types. Also metabolizes potassium iodide, for radiation poisoning, and morphine, for offense." diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 902892d3f7e..8538db0b13d 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -25,7 +25,7 @@ to_chat(user, "You finish eating \the [src].") user.visible_message("[user] finishes eating \the [src].") user.unEquip(src) //so icons update :[ - + Post_Consume(M) if(trash) if(ispath(trash,/obj/item)) var/obj/item/TrashItem = new trash(user) @@ -35,6 +35,9 @@ qdel(src) return +/obj/item/weapon/reagent_containers/food/snacks/proc/Post_Consume(mob/living/M) + return + /obj/item/weapon/reagent_containers/food/snacks/attack_self(mob/user as mob) return @@ -756,27 +759,32 @@ desc = "The food of choice for the seasoned traitor." icon_state = "donkpocket" filling_color = "#DEDEAB" + New() ..() reagents.add_reagent("nutriment", 4) - reagents.add_reagent("omnizine", 4) + + Post_Consume(mob/living/M) + M.reagents.add_reagent("omnizine", 15) /obj/item/weapon/reagent_containers/food/snacks/syndidonkpocket name = "Donk-pocket" desc = "This donk-pocket is emitting a small amount of heat." icon_state = "donkpocket" filling_color = "#DEDEAB" - volume = 90 bitesize = 100 //nom the whole thing at once. New() ..() - reagents.add_reagent("omnizine", 15) - reagents.add_reagent("teporone", 15) - reagents.add_reagent("synaptizine", 15) - reagents.add_reagent("salglu_solution", 15) - reagents.add_reagent("salbutamol", 15) - reagents.add_reagent("methamphetamine2", 15) + reagents.add_reagent("nutriment", 1) + + Post_Consume(mob/living/M) + M.reagents.add_reagent("omnizine", 15) + M.reagents.add_reagent("teporone", 15) + M.reagents.add_reagent("synaptizine", 15) + M.reagents.add_reagent("salglu_solution", 15) + M.reagents.add_reagent("salbutamol", 15) + M.reagents.add_reagent("methamphetamine", 15) /obj/item/weapon/reagent_containers/food/snacks/brainburger name = "brainburger" diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 22466811e3e..a9181138a85 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -5,7 +5,7 @@ /obj/item/weapon/reagent_containers/hypospray name = "hypospray" desc = "The DeForest Medical Corporation hypospray is a sterile, air-needle autoinjector for rapid administration of drugs to patients." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/obj/hypo.dmi' item_state = "hypo" icon_state = "hypo" amount_per_transfer_from_this = 5 diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index e95e213fd9f..bd8a22cd06f 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -8,7 +8,7 @@ /obj/item/weapon/reagent_containers/syringe name = "Syringe" desc = "A syringe." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/goonstation/objects/syringe.dmi' item_state = "syringe_0" icon_state = "0" amount_per_transfer_from_this = 5 @@ -336,7 +336,7 @@ /obj/item/weapon/reagent_containers/ld50_syringe name = "Lethal Injection Syringe" desc = "A syringe used for lethal injections." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/goonstation/objects/syringe.dmi' item_state = "syringe_0" icon_state = "0" amount_per_transfer_from_this = 50 diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index b5d44579d07..8337e0ffaf7 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -688,6 +688,14 @@ build_path = /obj/item/weapon/hand_labeler category = list("initial", "Electronics") +/datum/design/floorpainter + name = "Floor painter" + id = "floor_painter" + build_type = AUTOLATHE + materials = list(MAT_METAL = 150, MAT_GLASS = 125) + build_path = /obj/item/device/floor_painter + category = list("initial", "Electronics") + /datum/design/logic_board name = "Logic Circuit" id = "logic_board" diff --git a/code/modules/research/designs/spacepod_designs.dm b/code/modules/research/designs/spacepod_designs.dm index c1927e47654..759af82404d 100644 --- a/code/modules/research/designs/spacepod_designs.dm +++ b/code/modules/research/designs/spacepod_designs.dm @@ -12,6 +12,7 @@ ////////////////////////////////////////////////// /////////SPACEPOD PARTS/////////////////////////// ////////////////////////////////////////////////// + /datum/design/podframe_fp construction_time = 200 name = "Fore port pod frame" @@ -89,6 +90,7 @@ ////////////////////////////////////////// //////SPACEPOD GUNS/////////////////////// ////////////////////////////////////////// + /datum/design/pod_gun_taser construction_time = 200 name = "Spacepod Equipment (Taser)" @@ -157,6 +159,7 @@ materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 4000, MAT_GOLD = 4000, MAT_DIAMOND = 4000) build_path = /obj/item/device/spacepod_equipment/weaponry/mining_laser_hyper category = list("Pod_Weaponry") + ////////////////////////////////////////// //////SPACEPOD MISC. ITEMS//////////////// ////////////////////////////////////////// @@ -172,16 +175,57 @@ build_path = /obj/item/device/spacepod_equipment/misc/tracker category = list("Pod_Parts") +////////////////////////////////////////// +//////SPACEPOD CARGO ITEMS//////////////// +////////////////////////////////////////// + /datum/design/pod_cargo_ore construction_time = 100 name = "Spacepod Ore Storage Module" desc = "Allows for the construction of a Space Pod Ore Storage Module." id = "podcargo_ore" - req_tech = list("materials" = 3) + req_tech = list("materials" = 3, "engineering" = 2) build_type = PODFAB materials = list(MAT_METAL=20000, MAT_GLASS=2000) build_path = /obj/item/device/spacepod_equipment/cargo/ore - category = list("Pod_Parts") + category = list("Pod_Cargo") + +/datum/design/pod_cargo_crate + construction_time = 100 + name = "Spacepod Crate Storage Module" + desc = "Allows the construction of a Space Pod Crate Storage Module." + id = "podcargo_crate" + req_tech = list("materials" = 4, "engineering" = 2) //hollowing out this much of the pod without compromising structural integrity is hard + build_type = PODFAB + materials = list(MAT_METAL=25000) + build_path = /obj/item/device/spacepod_equipment/cargo/crate + category = list("Pod_Cargo") + +////////////////////////////////////////// +//////SPACEPOD SEC CARGO ITEMS//////////// +////////////////////////////////////////// + +/datum/design/passenger_seat + construction_time = 100 + name = "Spacepod Passenger Seat" + desc = "Allows the construction of a Space Pod Passenger Seat Module." + id = "podcargo_sec_seat" + req_tech = list("materials" = 1) // Because rule number one of refactoring + build_type = PODFAB + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/device/spacepod_equipment/sec_cargo/chair + category = list("Pod_Cargo") + +/datum/design/loot_box + construction_time = 100 + name = "Spacepod Loot Storage Module" + desc = "Allows the construction of a Space Pod Auxillary Cargo Module." + id = "podcargo_sec_lootbox" + req_tech = list("materials" = 1) //it's just a set of shelves, It's not that hard to make + build_type = PODFAB + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/device/spacepod_equipment/sec_cargo/loot_box + category = list("Pod_Cargo") ////////////////////////////////////////// //////SPACEPOD LOCK ITEMS//////////////// diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index f0e3c089cfd..38004bd49fa 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -89,8 +89,9 @@ component_parts += new /obj/item/weapon/stock_parts/manipulator(src) component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) - trackedIan = locate(/mob/living/simple_animal/pet/corgi/Ian) in mob_list - trackedRuntime = locate(/mob/living/simple_animal/pet/cat/Runtime) in mob_list + spawn(1) + trackedIan = locate(/mob/living/simple_animal/pet/corgi/Ian) in mob_list + trackedRuntime = locate(/mob/living/simple_animal/pet/cat/Runtime) in mob_list SetTypeReactions() RefreshParts() @@ -213,7 +214,8 @@ if(loaded_item) if(cloneMode && cloneCount > 0) visible_message("A duplicate [loaded_item] pops out!") - new loaded_item(get_turf(pick(oview(1,src)))) + var/type_to_make = loaded_item.type + new type_to_make(get_turf(pick(oview(1,src)))) --cloneCount if(cloneCount == 0) cloneMode = FALSE @@ -247,7 +249,7 @@ recentlyExperimented = 1 icon_state = "h_lathe_wloop" var/chosenchem - var/criticalReaction = locate(exp_on) in critical_items ? TRUE : FALSE + var/criticalReaction = (exp_on.type in critical_items) ? TRUE : FALSE //////////////////////////////////////////////////////////////////////////////////////////////// if(exp == SCANTYPE_POKE) visible_message("[src] prods at [exp_on] with mechanical arms.") @@ -490,8 +492,21 @@ ejectItem() //Global reactions - if(prob(EFFECT_PROB_VERYLOW-badThingCoeff)) - var/globalMalf = rand(1,100) + + if(prob(EFFECT_PROB_VERYLOW) && prob(13)) + visible_message("[src] improves [exp_on], drawing the life essence of those nearby!") + for(var/mob/living/m in view(4,src)) + to_chat(m, "You feel your flesh being torn from you, mists of blood drifting to [src]!") + m.take_overall_damage(50) + investigate_log("Experimentor has taken 50 brute a blood sacrifice from [m]", "experimentor") + var/list/reqs = ConvertReqString2List(exp_on.origin_tech) + for(var/T in reqs) + reqs[T] = reqs[T] + 1 + exp_on.origin_tech = list2params(reqs) + investigate_log("Experimentor has set the origin tech of [exp_on] to [exp_on.origin_tech]", "experimentor") + + if(prob(EFFECT_PROB_VERYLOW-badThingCoeff) && prob(87)) + var/globalMalf = rand(1,87) if(globalMalf < 15) visible_message("[src]'s onboard detection system has malfunctioned!") item_reactions["[exp_on.type]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE) @@ -507,18 +522,7 @@ new /mob/living/simple_animal/pet/corgi(src.loc) investigate_log("Experimentor has spawned a new corgi.", "experimentor") ejectItem(TRUE) - if(globalMalf > 36 && globalMalf < 50) - visible_message("[src] improves [exp_on], drawing the life essence of those nearby!") - for(var/mob/living/m in view(4,src)) - to_chat(m, "You feel your flesh being torn from you, mists of blood drifting to [src]!") - m.take_overall_damage(50) - investigate_log("Experimentor has taken 50 brute a blood sacrifice from [m]", "experimentor") - var/list/reqs = ConvertReqString2List(exp_on.origin_tech) - for(var/T in reqs) - reqs[T] = reqs[T] + 1 - exp_on.origin_tech = list2params(reqs) - investigate_log("Experimentor has set the origin tech of [exp_on] to [exp_on.origin_tech]", "experimentor") - if(globalMalf > 51 && globalMalf < 75) + if(globalMalf > 36 && globalMalf < 59) visible_message("[src] encounters a run-time error!") throwSmoke(src.loc) if(trackedRuntime) @@ -529,7 +533,7 @@ new /mob/living/simple_animal/pet/cat(src.loc) investigate_log("Experimentor failed to steal runtime, and instead spawned a new cat.", "experimentor") ejectItem(TRUE) - if(globalMalf > 76) + if(globalMalf > 60) visible_message("[src] begins to smoke and hiss, shaking violently!") use_power(500000) investigate_log("Experimentor has drained power from its APC", "experimentor") diff --git a/code/game/vehicles/spacepods/construction.dm b/code/modules/spacepods/construction.dm similarity index 100% rename from code/game/vehicles/spacepods/construction.dm rename to code/modules/spacepods/construction.dm diff --git a/code/game/vehicles/spacepods/equipment.dm b/code/modules/spacepods/equipment.dm similarity index 76% rename from code/game/vehicles/spacepods/equipment.dm rename to code/modules/spacepods/equipment.dm index 91588fa0a8b..24c4fa5110b 100644 --- a/code/game/vehicles/spacepods/equipment.dm +++ b/code/modules/spacepods/equipment.dm @@ -46,12 +46,13 @@ /datum/spacepod/equipment var/obj/spacepod/my_atom + var/list/obj/item/device/spacepod_equipment/installed_modules // holds an easy to access list of installed modules + var/obj/item/device/spacepod_equipment/weaponry/weapon_system // weapons system var/obj/item/device/spacepod_equipment/misc/misc_system // misc system var/obj/item/device/spacepod_equipment/cargo/cargo_system // cargo system + var/obj/item/device/spacepod_equipment/cargo/sec_cargo_system // secondary cargo system var/obj/item/device/spacepod_equipment/lock/lock_system // lock system - //var/obj/item/device/spacepod_equipment/engine/engine_system // engine system - //var/obj/item/device/spacepod_equipment/shield/shield_system // shielding system /datum/spacepod/equipment/New(var/obj/spacepod/SP) ..() @@ -61,11 +62,17 @@ /obj/item/device/spacepod_equipment name = "equipment" var/obj/spacepod/my_atom + var/occupant_mod = 0 // so any module can modify occupancy + var/list/storage_mod = list("slots" = 0, "w_class" = 0) // so any module can modify storage slots /obj/item/device/spacepod_equipment/proc/removed(var/mob/user) // So that you can unload cargo when you remove the module return -// base item for spacepod weapons +/* +/////////////////////////////////////// +/////////Weapon System/////////////////// +/////////////////////////////////////// +*/ /obj/item/device/spacepod_equipment/weaponry name = "pod weapon" @@ -135,7 +142,12 @@ fire_delay = 8 fire_sound = 'sound/weapons/Kenetic_accel.ogg' -//base item for spacepod misc equipment (tracker) +/* +/////////////////////////////////////// +/////////Misc. System/////////////////// +/////////////////////////////////////// +*/ + /obj/item/device/spacepod_equipment/misc name = "pod misc" desc = "You shouldn't be seeing this" @@ -160,37 +172,79 @@ else ..() +/* +/////////////////////////////////////// +/////////Cargo System////////////////// +/////////////////////////////////////// +*/ + /obj/item/device/spacepod_equipment/cargo name = "pod cargo" desc = "You shouldn't be seeing this" icon = 'icons/vehicles/spacepod.dmi' - icon_state = "blank" + icon_state = "cargo_blank" + var/obj/storage = null /obj/item/device/spacepod_equipment/cargo/proc/passover(var/obj/item/I) return -/obj/item/device/spacepod_equipment/cargo/proc/unload() - return +/obj/item/device/spacepod_equipment/cargo/proc/unload() // called by unload verb + if(storage) + storage.forceMove(get_turf(my_atom)) + storage = null -/obj/item/device/spacepod_equipment/cargo/ore - name = "\improper spacepod ore storage system" - desc = "An ore storage system for spacepods. Scoops up any ore you drive over." - icon_state = "cargo_ore" - var/obj/structure/ore_box/box - -/obj/item/device/spacepod_equipment/cargo/ore/passover(var/obj/item/I) - if(box && istype(I,/obj/item/weapon/ore)) - I.forceMove(box) - -/obj/item/device/spacepod_equipment/cargo/ore/unload() - if(box) - box.forceMove(get_turf(my_atom)) - box = null - -/obj/item/device/spacepod_equipment/cargo/ore/removed(var/mob/user) +/obj/item/device/spacepod_equipment/cargo/removed(var/mob/user) // called when system removed . = ..() unload() +// Ore System +/obj/item/device/spacepod_equipment/cargo/ore + name = "spacepod ore storage system" + desc = "An ore storage system for spacepods. Scoops up any ore you drive over." + icon_state = "cargo_ore" + +/obj/item/device/spacepod_equipment/cargo/ore/passover(var/obj/item/I) + if(storage && istype(I,/obj/item/weapon/ore)) + I.forceMove(storage) + +// Crate System +/obj/item/device/spacepod_equipment/cargo/crate + name = "spacepod crate storage system" + desc = "A heavy duty storage system for spacepods. Holds one crate." + icon_state = "cargo_crate" + +/* +/////////////////////////////////////// +/////////Secondary Cargo System//////// +/////////////////////////////////////// +*/ + +/obj/item/device/spacepod_equipment/sec_cargo + name = "secondary cargo" + desc = "you shouldn't be seeing this" + icon = 'icons/vehicles/spacepod.dmi' + icon_state = "blank" + +// Passenger Seat +/obj/item/device/spacepod_equipment/sec_cargo/chair + name = "passanger seat" + desc = "A passenger seat for a spacepod" + icon_state = "sec_cargo_chair" + occupant_mod = 1 + +// Loot Box +/obj/item/device/spacepod_equipment/sec_cargo/loot_box + name = "loot box" + desc = "A small compartment to store valuables" + icon_state = "sec_cargo_loot" + storage_mod = list("slots" = 7, "w_class" = 14) + +/* +/////////////////////////////////////// +/////////Lock System/////////////////// +/////////////////////////////////////// +*/ + /obj/item/device/spacepod_equipment/lock name = "pod lock" desc = "You shouldn't be seeing this" diff --git a/code/modules/spacepods/lock_buster.dm b/code/modules/spacepods/lock_buster.dm new file mode 100644 index 00000000000..276386d89a6 --- /dev/null +++ b/code/modules/spacepods/lock_buster.dm @@ -0,0 +1,13 @@ +/obj/item/device/lock_buster + name = "pod lock buster" + desc = "Destroys a podlock in mere seconds once applied. Waranty void if used." + icon_state = "lock_buster_off" + var/on = 0 + +/obj/item/device/lock_buster/attack_self(mob/user as mob) + on = !on + if(on) + icon_state = "lock_buster_on" + else + icon_state = "lock_buster_off" + to_chat(usr, "You turn the [src] [on ? "on" : "off"].") \ No newline at end of file diff --git a/code/game/vehicles/spacepods/parts.dm b/code/modules/spacepods/parts.dm similarity index 100% rename from code/game/vehicles/spacepods/parts.dm rename to code/modules/spacepods/parts.dm diff --git a/code/game/vehicles/spacepods/pod_fabricator.dm b/code/modules/spacepods/pod_fabricator.dm similarity index 99% rename from code/game/vehicles/spacepods/pod_fabricator.dm rename to code/modules/spacepods/pod_fabricator.dm index 948491c6d29..ed7f421f33e 100644 --- a/code/game/vehicles/spacepods/pod_fabricator.dm +++ b/code/modules/spacepods/pod_fabricator.dm @@ -35,6 +35,7 @@ var/list/part_sets = list( "Pod_Weaponry", "Pod_Armor", + "Pod_Cargo", "Pod_Parts", "Pod_Frame", "Misc", diff --git a/code/game/vehicles/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm similarity index 57% rename from code/game/vehicles/spacepods/spacepod.dm rename to code/modules/spacepods/spacepod.dm index 707b8912460..4d6393b3348 100644 --- a/code/game/vehicles/spacepods/spacepod.dm +++ b/code/modules/spacepods/spacepod.dm @@ -14,8 +14,10 @@ layer = 3.9 infra_luminosity = 15 - var/mob/living/carbon/occupant - var/mob/living/carbon/occupant2 //two seaters + var/list/mob/pilot //There is only ever one pilot and he gets all the privledge + var/list/mob/passengers = list() //passengers can't do anything and are variable in number + var/max_passengers = 0 + var/obj/item/weapon/storage/internal/cargo_hold var/datum/spacepod/equipment/equipment_system @@ -47,7 +49,7 @@ "pod_black" = "#3B8FE5", \ "pod_industrial" = "#CCCC00") - var/allow2enter = 1 + var/unlocked = 1 var/move_delay = 2 var/next_move = 0 @@ -72,12 +74,19 @@ pr_give_air = new /datum/global_iterator/pod_tank_give_air(list(src)) equipment_system = new(src) spacepods_list += src + cargo_hold = new/obj/item/weapon/storage/internal(src) + cargo_hold.w_class = 5 //so you can put bags in + cargo_hold.storage_slots = 0 //You need to install cargo modules to use it. + cargo_hold.max_w_class = 5 //fit almost anything + cargo_hold.max_combined_w_class = 0 //you can optimize your stash with larger items /obj/spacepod/Destroy() if (equipment_system.cargo_system) equipment_system.cargo_system.removed(null) qdel(equipment_system) equipment_system = null + qdel(cargo_hold) + cargo_hold = null qdel(battery) battery = null qdel(cabin_air) @@ -91,12 +100,10 @@ qdel(ion_trail) ion_trail = null occupant_sanity_check() - if(occupant) - occupant.forceMove(get_turf(src)) - occupant = null - if(occupant2) - occupant2.forceMove(get_turf(src)) - occupant2 = null + if(passengers) + for(var/mob/M in passengers) + M.forceMove(get_turf(src)) + passengers -= M spacepods_list -= src return ..() @@ -106,7 +113,6 @@ else processing_objects.Remove(src) - /obj/spacepod/proc/update_icons() if(!pod_overlays) pod_overlays = new/list(2) @@ -155,34 +161,29 @@ health = max(0, health - damage) var/percentage = (health / initial(health)) * 100 occupant_sanity_check() - if(occupant && oldhealth > health && percentage <= 25 && percentage > 0) + if(passengers && oldhealth > health && percentage <= 25 && percentage > 0) var/sound/S = sound('sound/effects/engine_alert2.ogg') S.wait = 0 //No queue S.channel = 0 //Any channel S.volume = 50 - to_chat(occupant, S) - if(occupant2) - to_chat(occupant2, S) - if(occupant && oldhealth > health && !health) + for(var/mob/M in passengers) + to_chat(M, S) + if(passengers && oldhealth > health && !health) var/sound/S = sound('sound/effects/engine_alert1.ogg') S.wait = 0 S.channel = 0 S.volume = 50 - to_chat(occupant, S) - if(occupant2) - to_chat(occupant2, S) + for(var/mob/M in passengers) + to_chat(M, S) if(!health) spawn(0) - if(occupant) - to_chat(occupant, "Critical damage to the vessel detected, core explosion imminent!") - if(occupant2) - to_chat(occupant2, "Critical damage to the vessel detected, core explosion imminent!") - + if(passengers) + for(var/mob/M in passengers) + to_chat(M, "Critical damage to the vessel detected, core explosion imminent!") for(var/i = 10, i >= 0; --i) - if(occupant) - to_chat(occupant, "[i]") - if(occupant2) - to_chat(occupant2, "[i]") + if(passengers) + for(var/mob/M in passengers) + to_chat(M, "[i]") if(i == 0) explosion(loc, 2, 4, 8) qdel(src) @@ -200,16 +201,12 @@ occupant_sanity_check() switch(severity) if(1) - var/mob/living/carbon/human/H = occupant - var/mob/living/carbon/human/H2 = occupant2 - if(H) - H.forceMove(get_turf(src)) - H.ex_act(severity + 1) - to_chat(H, "You are forcefully thrown from \the [src]!") - if(H2) - H2.forceMove(get_turf(src)) - H2.ex_act(severity + 1) - to_chat(H2, "You are forcefully thrown from \the [src]!") + for(var/mob/M in passengers) + var/mob/living/carbon/human/H = M + if(H) + H.forceMove(get_turf(src)) + H.ex_act(severity + 1) + to_chat(H, "You are forcefully thrown from \the [src]!") qdel(ion_trail) qdel(src) if(2) @@ -220,12 +217,14 @@ /obj/spacepod/emp_act(severity) occupant_sanity_check() + cargo_hold.emp_act(severity) switch(severity) if(1) - if(occupant) - to_chat(occupant, "The pod console flashes 'Heavy EMP WAVE DETECTED'.")//warn the occupants - if(occupant2) - to_chat(occupant2, "The pod console flashes 'Heavy EMP WAVE DETECTED'.")//warn the occupants + if(pilot) + to_chat(pilot, "The pod console flashes 'Heavy EMP WAVE DETECTED'.") + if(passengers) + for(var/mob/M in passengers) + to_chat(M, "The pod console flashes 'Heavy EMP WAVE DETECTED'.")//warn the passengers if(battery) @@ -236,10 +235,11 @@ processing_objects.Add(src) if(2) - if(occupant) - to_chat(occupant, "The pod console flashes 'EMP WAVE DETECTED'.")//warn the occupants - if(occupant2) - to_chat(occupant2, "The pod console flashes 'EMP WAVE DETECTED'.")//warn the occupants + if(pilot) + to_chat(pilot, "The pod console flashes 'EMP WAVE DETECTED'.") + if(passengers) + for(var/mob/M in passengers) + to_chat(M, "The pod console flashes 'EMP WAVE DETECTED'.")//warn the passengers deal_damage(40) if(battery) @@ -250,12 +250,13 @@ /obj/spacepod/attackby(obj/item/W as obj, mob/user as mob, params) if(iscrowbar(W)) - if(!equipment_system.lock_system || allow2enter || hatch_open) + if(!equipment_system.lock_system || unlocked || hatch_open) hatch_open = !hatch_open playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) to_chat(user, "You [hatch_open ? "open" : "close"] the maintenance hatch.") else to_chat(user, "The hatch is locked shut!") + return if(istype(W, /obj/item/weapon/stock_parts/cell)) if(!hatch_open) to_chat(user, "\red The maintenance hatch is closed!") @@ -272,61 +273,32 @@ to_chat(user, "\red The maintenance hatch is closed!") return if(!equipment_system) - to_chat(user, "The pod has no equipment datum, yell at pomf") + to_chat(user, "The pod has no equipment datum, yell at the coders") return if(istype(W, /obj/item/device/spacepod_equipment/weaponry)) - if(equipment_system.weapon_system) - to_chat(user, "The pod already has a weapon system, remove it first.") - return - else - to_chat(user, "You insert \the [W] into the equipment system.") - user.drop_item(W) - W.forceMove(src) - equipment_system.weapon_system = W - equipment_system.weapon_system.my_atom = src - return - + add_equipment(user, W, "weapon_system") + return if(istype(W, /obj/item/device/spacepod_equipment/misc)) - if(equipment_system.misc_system) - to_chat(user, "The pod already has a miscellaneous system, remove it first.") - return - else - to_chat(user, "You insert \the [W] into the equipment system.") - user.drop_item(W) - W.forceMove(src) - equipment_system.misc_system = W - equipment_system.misc_system.my_atom = src - return + add_equipment(user, W, "misc_system") + return if(istype(W, /obj/item/device/spacepod_equipment/cargo)) - if(equipment_system.cargo_system) - to_chat(user, "The pod already has a cargo system, remove it first.") - return - else - to_chat(user, "You insert \the [W] into the cargo system.") - user.drop_item(W) - W.forceMove(src) - equipment_system.cargo_system = W - equipment_system.cargo_system.my_atom = src - return + add_equipment(user, W, "cargo_system") + return + if(istype(W, /obj/item/device/spacepod_equipment/sec_cargo)) + add_equipment(user, W, "sec_cargo_system") + return if(istype(W, /obj/item/device/spacepod_equipment/lock)) - if(equipment_system.lock_system) - to_chat(user, "The pod already has a lock system, remove it first.") - return - else - to_chat(user, "You insert \the [W] into the lock system.") - user.drop_item(W) - W.forceMove(src) - equipment_system.lock_system = W - equipment_system.lock_system.my_atom = src - return + add_equipment(user, W, "lock_system") + return if(istype(W, /obj/item/device/spacepod_key) && istype(equipment_system.lock_system, /obj/item/device/spacepod_equipment/lock/keyed)) var/obj/item/device/spacepod_key/key = W if (key.id == equipment_system.lock_system.id) - locksecondseat() + lock_pod() + return else to_chat(user, "This is the wrong key!") - return + return if(istype(W, /obj/item/weapon/weldingtool)) if(!hatch_open) @@ -343,15 +315,76 @@ if(!src || !WT.remove_fuel(3, user)) return repair_damage(10) to_chat(user, "\blue You mend some [pick("dents","bumps","damage")] with \the [WT]") - else - to_chat(user, "\blue \The [src] is fully repaired!") + return + to_chat(user, "\blue \The [src] is fully repaired!") + return + if(istype(W, /obj/item/device/lock_buster)) + var/obj/item/device/lock_buster/L = W + if(L.on & equipment_system.lock_system) + user.visible_message(user, "[user] is drilling through the [src]'s lock!", + "You start drilling through the [src]'s lock!") + if(do_after(user, 100, target = src)) + qdel(equipment_system.lock_system) + equipment_system.lock_system = null + user.visible_message(user, "[user] has destroyed the [src]'s lock!", + "You destroy the [src]'s lock!") + else + user.visible_message(user, "[user] fails to break through the [src]'s lock!", + "You were unable to break through the [src]'s lock!") + return + to_chat(user, "Turn the [L] on first.") + return + + if(cargo_hold.storage_slots > 0 && !hatch_open && unlocked) // must be the last option as all items not listed prior will be stored + cargo_hold.attackby(W, user, params) + +obj/spacepod/proc/add_equipment(mob/user, var/obj/item/device/spacepod_equipment/SPE, var/slot) + if(equipment_system.vars[slot]) + to_chat(user, "The pod already has a [slot], remove it first.") + return + else + to_chat(user, "You insert \the [SPE] into the pod.") + user.drop_item(SPE) + SPE.forceMove(src) + equipment_system.vars[slot] = SPE + var/obj/item/device/spacepod_equipment/system = equipment_system.vars[slot] + system.my_atom = src + equipment_system.installed_modules += SPE + max_passengers += SPE.occupant_mod + cargo_hold.storage_slots += SPE.storage_mod["slots"] + cargo_hold.max_combined_w_class += SPE.storage_mod["w_class"] /obj/spacepod/attack_hand(mob/user as mob) + if(user.a_intent == I_GRAB && unlocked) + var/mob/target + if(pilot) + target = pilot + else if(passengers.len > 0) + target = passengers[1] + + if(target && istype(target)) + src.visible_message("[user] is trying to rip the door open and pull [target] out of the [src]!", + "You see [user] outside the door trying to rip it open!") + if(do_after(user, 50, target = src)) + target.forceMove(get_turf(src)) + target.Stun(1) + passengers -= target + target.visible_message("[user] flings the door open and tears [target] out of the [src]", + "The door flies open and you are thrown out of the [src] and to the ground!") + return + target.visible_message("[user] was unable to get the door open!", + "You manage to keep [user] out of the [src]!") + if(!hatch_open) + if(cargo_hold.storage_slots > 0) + if(unlocked) + cargo_hold.open(user) + else + to_chat(user, "The storage compartment is locked") return ..() if(!equipment_system || !istype(equipment_system)) - to_chat(user, "The pod has no equpment datum, or is the wrong type, yell at pomf.") + to_chat(user, "The pod has no equpment datum, or is the wrong type, yell at IK3I.") return var/list/possible = list() if(battery) @@ -362,74 +395,81 @@ possible.Add("Misc. System") if(equipment_system.cargo_system) possible.Add("Cargo System") + if(equipment_system.sec_cargo_system) + possible.Add("Secondary Cargo System") if(equipment_system.lock_system) possible.Add("Lock System") - /* Not yet implemented - if(equipment_system.engine_system) - possible.Add("Engine System") - if(equipment_system.shield_system) - possible.Add("Shield System") - */ - var/obj/item/device/spacepod_equipment/SPE switch(input(user, "Remove which equipment?", null, null) as null|anything in possible) if("Energy Cell") if(user.put_in_any_hand_if_possible(battery)) to_chat(user, "You remove \the [battery] from the space pod") battery = null + else + to_chat(user, "You need an open hand to do that.") + return if("Weapon System") - SPE = equipment_system.weapon_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - SPE.removed(user) - SPE.my_atom = null - equipment_system.weapon_system = null - else - to_chat(user, "You need an open hand to do that.") + remove_equipment(user, equipment_system.weapon_system, "weapon_system") + return if("Misc. System") - SPE = equipment_system.misc_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - SPE.removed(user) - SPE.my_atom = null - equipment_system.misc_system = null - else - to_chat(user, "You need an open hand to do that.") + remove_equipment(user, equipment_system.misc_system, "misc_system") + return if("Cargo System") - SPE = equipment_system.cargo_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - SPE.removed(user) - SPE.my_atom = null - equipment_system.cargo_system = null - else - to_chat(user, "You need an open hand to do that.") + remove_equipment(user, equipment_system.cargo_system, "cargo_system") + return + if("Secondary Cargo System") + remove_equipment(user, equipment_system.sec_cargo_system, "sec_cargo_system") + return if("Lock System") - SPE = equipment_system.lock_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - SPE.removed(user) - SPE.my_atom = null - equipment_system.lock_system = null - else - to_chat(user, "You need an open hand to do that.") - /* - if("engine system") - SPE = equipment_system.engine_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - equipment_system.engine_system = null - else - to_chat(user, "You need an open hand to do that.") - if("shield system") - SPE = equipment_system.shield_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - equipment_system.shield_system = null - else - to_chat(user, "You need an open hand to do that.") - */ + remove_equipment(user, equipment_system.lock_system, "lock_system") - return +/obj/spacepod/proc/remove_equipment(mob/user, var/obj/item/device/spacepod_equipment/SPE, var/slot) + + if(passengers.len > max_passengers - SPE.occupant_mod) + to_chat(user, "Someone is sitting in \the [SPE]!") + return + + var/sum_w_class = 0 + for(var/obj/item/I in cargo_hold.contents) + sum_w_class += I.w_class + if(cargo_hold.contents.len > cargo_hold.storage_slots - SPE.storage_mod["slots"] || sum_w_class > cargo_hold.max_combined_w_class - SPE.storage_mod["w_class"]) + to_chat(user, "Empty \the [SPE] first!") + return + + if(user.put_in_any_hand_if_possible(SPE)) + to_chat(user, "You remove \the [SPE] from the equipment system.") + equipment_system.installed_modules -= SPE + max_passengers -= SPE.occupant_mod + cargo_hold.storage_slots -= SPE.storage_mod["slots"] + cargo_hold.max_combined_w_class -= SPE.storage_mod["w_class"] + SPE.removed(user) + SPE.my_atom = null + equipment_system.vars[slot] = null + return + to_chat(user, "You need an open hand to do that.") + + +/obj/spacepod/hear_talk/hear_talk(mob/M, var/msg) + cargo_hold.hear_talk(M, msg) + ..() + +/obj/spacepod/hear_message(mob/M, var/msg) + cargo_hold.hear_message(M, msg) + ..() + +/obj/spacepod/proc/return_inv() + + var/list/L = list( ) + + L += src.contents + + for(var/obj/item/weapon/storage/S in src) + L += S.return_inv() + for(var/obj/item/weapon/gift/G in src) + L += G.gift + if (istype(G.gift, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/inv = G.gift + L += inv.return_inv() + return L /obj/spacepod/civilian icon_state = "pod_civ" @@ -456,12 +496,16 @@ equipment_system.misc_system = L equipment_system.misc_system.my_atom = src equipment_system.misc_system.enabled = 1 + var/obj/item/device/spacepod_equipment/sec_cargo/chair/C = new /obj/item/device/spacepod_equipment/sec_cargo/chair + C.loc = equipment_system + equipment_system.sec_cargo_system = C + equipment_system.sec_cargo_system.my_atom = src + max_passengers = 1 var/obj/item/device/spacepod_equipment/lock/keyed/K = new /obj/item/device/spacepod_equipment/lock/keyed K.loc = equipment_system equipment_system.lock_system = K equipment_system.lock_system.my_atom = src equipment_system.lock_system.id = 100000 - return /obj/spacepod/random/New() ..() @@ -486,11 +530,11 @@ set category = "Spacepod" set src = usr.loc set popup_menu = 0 - if(usr!=src.occupant) + if(usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") return use_internal_tank = !use_internal_tank - to_chat(occupant, "Now taking air from [use_internal_tank?"internal airtank":"environment"].") - return + to_chat(usr, "Now taking air from [use_internal_tank?"internal airtank":"environment"].") /obj/spacepod/proc/add_cabin() cabin_air = new @@ -508,7 +552,6 @@ var/turf/T = get_turf(src) if(T) . = T.return_air() - return /obj/spacepod/remove_air(amount) if(use_internal_tank) @@ -517,7 +560,6 @@ var/turf/T = get_turf(src) if(T) return T.remove_air(amount) - return /obj/spacepod/return_air() if(use_internal_tank) @@ -532,7 +574,6 @@ var/datum/gas_mixture/t_air = get_turf_air() if(t_air) . = t_air.return_pressure() - return /obj/spacepod/proc/return_temperature() . = 0 @@ -542,19 +583,21 @@ var/datum/gas_mixture/t_air = get_turf_air() if(t_air) . = t_air.return_temperature() - return /obj/spacepod/proc/moved_other_inside(var/mob/living/carbon/human/H as mob) occupant_sanity_check() - if(!occupant2) + if(passengers.len < max_passengers) H.stop_pulling() H.forceMove(src) - occupant2 = H + passengers += H H.forceMove(src) playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) return 1 /obj/spacepod/MouseDrop_T(atom/A, mob/user) + if(user == pilot || user in passengers) + return + if(istype(A,/mob)) var/mob/M = A if(!isliving(M)) @@ -562,48 +605,51 @@ occupant_sanity_check() - if(M != user && M.stat == DEAD && allow2enter) - if(occupant2 && !occupant) - to_chat(usr, "You can't put a corpse into the driver's seat!") + if(M != user && unlocked && (M.stat == DEAD || M.incapacitated())) + if(passengers.len >= max_passengers && !pilot) + to_chat(usr, "That person can't fly the pod!") return 0 - if(!occupant2) + if(passengers.len < max_passengers) visible_message("[user.name] starts loading [M.name] into the pod!") - sleep(10) - moved_other_inside(M) + if(do_after(user, 50, target = M)) + moved_other_inside(M) + return if(M == user) - if(!equipment_system.lock_system || allow2enter) - enter_pod(user) - else - to_chat(user, "\The [src]'s doors are locked!") + enter_pod(user) + return - - if(istype(A, /obj/structure/ore_box)) // For loading ore boxes - var/obj/structure/ore_box/O = A - if(equipment_system.cargo_system && istype(equipment_system.cargo_system,/obj/item/device/spacepod_equipment/cargo/ore)) - var/obj/item/device/spacepod_equipment/cargo/ore/C = equipment_system.cargo_system - if(!C.box) - to_chat(user, "You begin loading \the [O] into \the [src]'s [equipment_system.cargo_system]") - if(do_after(user, 40, target = src)) - C.box = O - O.forceMove(C) - to_chat(user, "You load \the [O] into \the [src]'s [equipment_system.cargo_system]!") - else - to_chat(user, "You fail to load \the [O] into \the [src]'s [equipment_system.cargo_system]") - else - to_chat(user, "\The [src] already has \an [C.box]") - -/obj/spacepod/verb/enter_pod(mob/user = usr) - set category = "Object" - set name = "Enter Pod" - set src in oview(1) - - if (usr.stat != CONSCIOUS) + if(istype(A, /obj/structure/ore_box) && equipment_system.cargo_system && istype(equipment_system.cargo_system,/obj/item/device/spacepod_equipment/cargo/ore)) // For loading ore boxes + load_cargo(user, A) return + if(istype(A, /obj/structure/closet/crate) && equipment_system.cargo_system && istype(equipment_system.cargo_system, /obj/item/device/spacepod_equipment/cargo/crate)) // For loading crates + load_cargo(user, A) + +/obj/spacepod/proc/load_cargo(mob/user, var/obj/O) + var/obj/item/device/spacepod_equipment/cargo/ore/C = equipment_system.cargo_system + if(!C.storage) + to_chat(user, "You begin loading \the [O] into \the [src]'s [equipment_system.cargo_system]") + if(do_after(user, 40, target = src)) + C.storage = O + O.forceMove(C) + to_chat(user, "You load \the [O] into \the [src]'s [equipment_system.cargo_system]!") + else + to_chat(user, "You fail to load \the [O] into \the [src]'s [equipment_system.cargo_system]") + else + to_chat(user, "\The [src] already has \an [C.storage]") + +/obj/spacepod/proc/enter_pod(mob/user) + if (usr.stat != CONSCIOUS) + return 0 + + if(equipment_system.lock_system && !unlocked) + to_chat(user, "\The [src]'s doors are locked!") + return 0 + if(get_dist(src, user) > 2 || get_dist(usr, user) > 1) to_chat(usr, "They are too far away to put inside") - return + return 0 if(!istype(user)) return 0 @@ -632,53 +678,45 @@ occupant_sanity_check() - if(!occupant) + if(passengers.len <= max_passengers) visible_message("[user] starts to climb into \the [src].") if(do_after(user, 40, target = src)) - if(!occupant) + if(!pilot || pilot == null) user.stop_pulling() - occupant = user + pilot = user + user.forceMove(src) + add_fingerprint(user) + playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) + return + if(passengers.len < max_passengers) + user.stop_pulling() + passengers += user user.forceMove(src) add_fingerprint(user) playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) else - to_chat(user, "[occupant] was faster. Try better next time, loser.") - else - to_chat(user, "You stop entering \the [src].") - - else if(!occupant2) - visible_message("[user] starts to climb into \the [src].") - if(do_after(user, 40, target = src)) - if(!occupant2) - user.stop_pulling() - occupant2 = user - user.forceMove(src) - add_fingerprint(user) - playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) - else - to_chat(user, "[occupant] was faster. Try better next time, loser.") + to_chat(user, "You were too slow. Try better next time, loser.") else to_chat(user, "You stop entering \the [src].") else to_chat(user, "You can't fit in \the [src], it's full!") -/obj/spacepod/proc/occupant_sanity_check() - if(occupant) - if(!ismob(occupant)) - occupant.forceMove(get_turf(src)) - log_debug("##SPACEPOD WARNING: NON-MOB OCCUPANT [occupant], TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") - occupant = null - else if(occupant.loc != src) - log_debug("##SPACEPOD WARNING: OCCUPANT [occupant] ESCAPED, TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") - occupant = null - if(occupant2) - if(!ismob(occupant2)) - occupant2.forceMove(get_turf(src)) - log_debug("##SPACEPOD WARNING: NON-MOB OCCUPANT [occupant2], TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") - occupant2 = null - else if(occupant2.loc != src) - log_debug("##SPACEPOD WARNING: OCCUPANT [occupant2] ESCAPED, TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") - occupant2 = null +/obj/spacepod/proc/occupant_sanity_check() // going to have to adjust this later for cargo refactor + if(passengers) + if(passengers.len > max_passengers) + for(var/i = passengers.len; i <= max_passengers; i--) + var/mob/occupant = passengers[i - 1] + occupant.forceMove(get_turf(src)) + log_debug("##SPACEPOD WARNING: passengers EXCEED CAP: MAX passengers [max_passengers], passengers [english_list(passengers)], TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") + passengers[i - 1] = null + for(var/mob/M in passengers) + if(!ismob(M)) + M.forceMove(get_turf(src)) + log_debug("##SPACEPOD WARNING: NON-MOB OCCUPANT [M], TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") + passengers -= M + else if(M.loc != src) + log_debug("##SPACEPOD WARNING: OCCUPANT [M] ESCAPED, TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") + passengers -= M /obj/spacepod/verb/exit_pod() set name = "Exit pod" @@ -686,64 +724,34 @@ set src = usr.loc var/mob/user = usr - var/spos = 0 if(!istype(user)) return - occupant_sanity_check() - - if(occupant == user) spos = 1 - if(occupant2 == user) spos = 2 - - switch(spos) - if(0) return - if(1) - if(occupant2) - to_chat(occupant2, "[occupant.name] climbs out of the pod!") - occupant.forceMove(src.loc) - occupant = null - to_chat(user, "You climb out of \the [src].") - if(2) - if(occupant) - to_chat(occupant, "[occupant2.name] climbs out of the pod!") - occupant2.forceMove(src.loc) - occupant2 = null - to_chat(user, "You climb out of \the [src].") - -/obj/spacepod/verb/exit_pod2() - set name = "Eject Secondary Seat" - set category = "Spacepod" - set src = usr.loc + if (user.stat != CONSCIOUS || user.incapacitated()) // unconscious and restrained people can't let themselves out + return occupant_sanity_check() - if(!occupant2) - to_chat(usr, "There is no one in the second seat.") - return + if(user == pilot) + user.forceMove(get_turf(src)) + pilot = null + to_chat(user, "You climb out of \the [src].") + if(user in passengers) + user.forceMove(get_turf(src)) + passengers -= user + to_chat(user, "You climb out of \the [src].") - if(usr == occupant2) - to_chat(usr, "How do you plan to do that? The eject button is out of reach.") - return - - if(usr == occupant) - to_chat(usr, "You eject [occupant2.name].") - to_chat(occupant2, "\The [src] ejects you forcefully!") - inertia_dir = 0 - occupant2.forceMove(src.loc) - occupant2 = null - -/obj/spacepod/verb/locksecondseat() +/obj/spacepod/verb/lock_pod() set name = "Lock Doors" set category = "Spacepod" set src = usr.loc - if(CheckIfOccupant2(usr)) - if(!allow2enter) - to_chat(usr, "You can't [allow2enter ? "lock" : "unlock"] the doors from your seat.") - return + if(usr in passengers && usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") + return - allow2enter = !allow2enter - to_chat(usr, "You [allow2enter ? "unlock" : "lock"] the doors.") + unlocked = !unlocked + to_chat(usr, "You [unlocked ? "unlock" : "lock"] the doors.") /obj/spacepod/verb/toggleDoors() @@ -751,7 +759,10 @@ set category = "Spacepod" set src = usr.loc - if(CheckIfOccupant2(usr)) return + if(usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") + return + for(var/obj/machinery/door/poddoor/multi_tile/P in orange(3,src)) var/mob/living/carbon/human/L = usr if(P.check_access(L.get_active_hand()) || P.check_access(L.wear_id)) @@ -761,41 +772,53 @@ else P.close() return 1 + for(var/mob/living/carbon/human/O in passengers) + if(P.check_access(O.get_active_hand()) || P.check_access(O.wear_id)) + if(P.density) + P.open() + return 1 + else + P.close() + return 1 to_chat(usr, "Access denied.") return to_chat(usr, "You are not close to any pod doors.") - return - /obj/spacepod/verb/fireWeapon() - if(!CheckIfOccupant2(usr)) - set name = "Fire Pod Weapons" - set desc = "Fire the weapons." - set category = "Spacepod" - set src = usr.loc - if(!equipment_system.weapon_system) - to_chat(usr, "\The [src] has no weapons!") - return - equipment_system.weapon_system.fire_weapons() + set name = "Fire Pod Weapons" + set desc = "Fire the weapons." + set category = "Spacepod" + set src = usr.loc + if(usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") + return + if(!equipment_system.weapon_system) + to_chat(usr, "\The [src] has no weapons!") + return + equipment_system.weapon_system.fire_weapons() /obj/spacepod/verb/unload() - if(!CheckIfOccupant2(usr)) - set name = "Unload Cargo" - set desc = "Unloads the cargo" - set category = "Spacepod" - set src = usr.loc - if(!equipment_system.cargo_system) - to_chat(usr, "\The [src] has no cargo system!") - return - equipment_system.cargo_system.unload() + set name = "Unload Cargo" + set desc = "Unloads the cargo" + set category = "Spacepod" + set src = usr.loc + if(usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") + return + if(!equipment_system.cargo_system) + to_chat(usr, "\The [src] has no cargo system!") + return + equipment_system.cargo_system.unload() /obj/spacepod/verb/toggleLights() set name = "Toggle Lights" set category = "Spacepod" set src = usr.loc - if(!CheckIfOccupant2(usr)) - lightsToggle() + if(usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") + return + lightsToggle() /obj/spacepod/proc/lightsToggle() lights = !lights @@ -803,8 +826,30 @@ set_light(lights_power) else set_light(0) - to_chat(occupant, "Toggled lights [lights ? "on" : "off"].") - return + to_chat(usr, "Lights toggled [lights ? "on" : "off"].") + for(var/mob/M in passengers) + to_chat(M, "Lights toggled [lights ? "on" : "off"].") + +/obj/spacepod/verb/checkSeat() + set name = "Check under Seat" + set category = "Spacepod" + set src = usr.loc + var/mob/user = usr + to_chat(user, "You start rooting around under the seat for lost items") + if(do_after(user, 40, target = src)) + var/obj/badlist = list(internal_tank, cargo_hold, pilot, battery) + passengers + equipment_system.installed_modules + var/list/true_contents = contents - badlist + if(true_contents.len > 0) + var/obj/I = pick(true_contents) + if(user.put_in_any_hand_if_possible(I)) + src.contents -= I + to_chat(user, "You find a [I] [pick("under the seat", "under the console", "in the mainenance access")]!") + else + to_chat(user, "You think you saw something shiny, but you can't reach it!") + else + to_chat(user, "You fail to find anything of value.") + else + to_chat(user, "You decide against searching the [src]") /obj/spacepod/proc/enter_after(delay as num, var/mob/user as mob, var/numticks = 5) var/delayfraction = delay/numticks @@ -825,7 +870,6 @@ if(spacepod.cabin_air && spacepod.cabin_air.return_volume() > 0) var/delta = spacepod.cabin_air.temperature - T20C spacepod.cabin_air.temperature -= max(-10, min(10, round(delta/4,0.1))) - return /datum/global_iterator/pod_tank_give_air delay = 15 @@ -858,11 +902,11 @@ qdel(removed) else return stop() - return /obj/spacepod/relaymove(mob/user, direction) - if(!CheckIfOccupant2(user)) - handlerelaymove(user, direction) + if(usr != src.pilot) + return + handlerelaymove(user, direction) /obj/spacepod/proc/handlerelaymove(mob/user, direction) if(world.time < next_move) @@ -909,15 +953,6 @@ battery.charge = max(0, battery.charge - 1) next_move = world.time + move_delay -/obj/spacepod/proc/CheckIfOccupant2(mob/user) - if(!src.occupant2) - return 0 - if(src.occupant2) - if(user == src.occupant2) - return 1 - else - return 0 - /obj/effect/landmark/spacepod/random name = "spacepod spawner" invisibility = 101 @@ -929,4 +964,4 @@ ..() #undef DAMAGE -#undef FIRE +#undef FIRE \ No newline at end of file diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index 82cda80e494..88b2f42416c 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -23,7 +23,6 @@ name = "robotic cavity implant" steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/cavity/place_item,/datum/surgery_step/robotics/external/close_hatch) possible_locs = list("chest","head","groin") - allowed_mob = list(/mob/living/carbon/human/machine) /datum/surgery/cavity_implant/can_start(mob/user, mob/living/carbon/target) if(target.get_species() == "Machine") @@ -231,7 +230,6 @@ name = "implant removal" steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/cavity/implant_removal,/datum/surgery_step/robotics/external/close_hatch) possible_locs = list("chest")//head is for borers..i can put it elsewhere - allowed_mob = list(/mob/living/carbon/human/machine) /datum/surgery/cavity_implant_rem/can_start(mob/user, mob/living/carbon/target) if(target.get_species() == "Machine") diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm index 90f2d9afed0..8c0d20224e9 100644 --- a/code/modules/surgery/limb_reattach.dm +++ b/code/modules/surgery/limb_reattach.dm @@ -40,7 +40,6 @@ name = "limb attachment" steps = list(/datum/surgery_step/limb/attach) possible_locs = list("head","l_arm", "l_hand","r_arm","r_hand","r_leg","r_foot","l_leg","l_foot","groin") - allowed_mob = list(/mob/living/carbon/human/machine) /datum/surgery/reattach_synth/can_start(mob/user, mob/living/carbon/target) if(ishuman(target)) diff --git a/code/modules/surgery/organs/helpers.dm b/code/modules/surgery/organs/helpers.dm index 29bd9801b26..a61537f1985 100644 --- a/code/modules/surgery/organs/helpers.dm +++ b/code/modules/surgery/organs/helpers.dm @@ -40,4 +40,9 @@ return O /proc/is_int_organ(atom/A) - return istype(A, /obj/item/organ/internal) \ No newline at end of file + return istype(A, /obj/item/organ/internal) + +/mob/living/carbon/human/proc/get_limb_by_name(limb_name) //Look for a limb with the given limb name in the source mob, and return it if found. + for(var/obj/item/organ/external/O in organs) + if(limb_name == O.limb_name) + return O diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 3bce602694a..9c1398c6405 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -176,7 +176,12 @@ var/list/organ_cache = list() /obj/item/organ/proc/rejuvenate() damage = 0 germ_level = 0 - status &= ~ORGAN_DEAD + if(status & ORGAN_ROBOT) //Robotic organs stay robotic. + status = ORGAN_ROBOT + else if (status & ORGAN_ASSISTED) //Assisted organs stay assisted. + status = ORGAN_ASSISTED + else + status = 0 if(!owner) processing_objects |= src diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm index ac96bd0f775..d0245c224d9 100644 --- a/code/modules/surgery/organs/organ_external.dm +++ b/code/modules/surgery/organs/organ_external.dm @@ -308,14 +308,20 @@ This function completely restores a damaged organ to perfect condition. */ /obj/item/organ/external/rejuvenate() damage_state = "00" - if(status & 128) //Robotic organs stay robotic. Fix because right click rejuvinate makes IPC's organs organic. - status = 128 + if(status & ORGAN_ROBOT) //Robotic organs stay robotic. + status = ORGAN_ROBOT + else if (status & ORGAN_ASSISTED) //Assisted organs stay assisted. + status = ORGAN_ASSISTED else status = 0 germ_level = 0 perma_injury = 0 brute_dam = 0 burn_dam = 0 + open = 0 //Closing all wounds. + wounds.Cut() //Clears all wounds! Good as new. + if(istype(src, /obj/item/organ/external/head) && disfigured) //If their head's disfigured, refigure it. + disfigured = 0 // handle internal organs for(var/obj/item/organ/internal/current_organ in internal_organs) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index e5c6292fa56..8f7ed0e6d67 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -31,7 +31,7 @@ return 0 if(target.get_species() == "Machine")//i know organ robot might be enough but i am not taking chances... return 0 - if(!affected.encased)//no bone, problem. + if(affected && !affected.encased) //no bone, problem. return 0 return 1 @@ -43,9 +43,9 @@ if(affected && (affected.status & ORGAN_ROBOT)) return 0//no operating on robotic limbs in an organic surgery - if(!affected.encased)//no bones no problem. - return 1 - return 0 + if(affected && affected.encased) //no bones no problem. + return 0 + return 1 /datum/surgery/organ_manipulation/alien/can_start(mob/user, mob/living/carbon/target) if(istype(target,/mob/living/carbon/alien/humanoid)) diff --git a/code/modules/vehicle/ambulance.dm b/code/modules/vehicle/ambulance.dm index 526b1e2c0a9..7d3f9084f5f 100644 --- a/code/modules/vehicle/ambulance.dm +++ b/code/modules/vehicle/ambulance.dm @@ -35,7 +35,8 @@ if(bed && get_dist(oldloc, loc) <= 2) bed.Move(oldloc) bed.dir = Dir - bed.buckled_mob.dir = Dir + if(bed.buckled_mob) + bed.buckled_mob.dir = Dir /obj/structure/stool/bed/amb_trolley name = "ambulance train trolley" diff --git a/code/world.dm b/code/world.dm index b217f57b68b..b28a0c2d0de 100644 --- a/code/world.dm +++ b/code/world.dm @@ -115,6 +115,7 @@ var/world_topic_spam_protect_time = world.timeofday else if ("status" in input) var/list/s = list() + var/list/admins = list() s["version"] = game_version s["mode"] = master_mode s["respawn"] = config ? abandon_allowed : 0 @@ -132,6 +133,7 @@ var/world_topic_spam_protect_time = world.timeofday if(C.holder.fakekey) continue //so stealthmins aren't revealed by the hub admin_count++ + admins += list(list(C.key, C.holder.rank)) s["player[player_count]"] = C.key player_count++ s["players"] = player_count @@ -150,6 +152,11 @@ var/world_topic_spam_protect_time = world.timeofday // Shuttle timer, in seconds s["shuttle_timer"] = shuttle_master.emergency.timeLeft() + for(var/i in 1 to admins.len) + var/list/A = admins[i] + s["admin[i - 1]"] = A[1] + s["adminrank[i - 1]"] = A[2] + return list2params(s) else if("adminmsg" in input) diff --git a/html/changelog.html b/html/changelog.html index 0930debbc21..095d98ad174 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,112 @@ -->
+

31 May 2016

+

CrAzYPiLoT updated:

+
    +
  • Fixes potential exploits involving door remotes.
  • +
  • Adds another type of remote door control.
  • +
+

Fox McCloud updated:

+
    +
  • Allows Chaplain to select a wide new range of null rod customizations
  • +
  • Slightly increases null rod damage (15->18)
  • +
  • Fixes abductors speaking other languages
  • +
  • Fixes traitors getting less TC on some game modes
  • +
+

QuinnAggeler updated:

+
    +
  • All lazarus revived mobs become valid for pet collaring
  • +
+

Tastyfish updated:

+
    +
  • Adds a suicide for light tubes.
  • +
  • Progress bars, buttons, and several of the values in UI's are now animated.
  • +
  • Deconstructing glass tables now gives a stack of 2 sheets of glass.
  • +
+

monster860 updated:

+
    +
  • Upgrading the experimentor will no longer reduce the chance of upgrading an item's tech
  • +
  • Guest passes can now be attached to an ID card.
  • +
  • Adds a HoP guest pass computer, which is like a normal guest pass computer, but using an ID with ID computer access will allow it to issue guest passes with any access.
  • +
  • Adds the HoP guest pass computer to the HoP office.
  • +
  • Moves the guest pass computer in robotics to RnD.
  • +
+ +

25 May 2016

+

CrAzYPiLoT updated:

+
    +
  • Adds an unread change notification.
  • +
+

Fox McCloud updated:

+
    +
  • Removes Dragon's Breath Recipe
  • +
  • Removes Ghost Chilli Juice
  • +
  • Fixes buckled flipping over someone
  • +
+

IK3I updated:

+
    +
  • Sleepers, scanners, and borg chargers no longer remove you from existence when destroyed
  • +
  • Hostile mobs are no longer fooled by your clever scanner and recharger tricks
  • +
+ +

24 May 2016

+

CrAzYPiLoT updated:

+
    +
  • Adds the ability to attach signalers to bear traps. Stealthy hunting!
  • +
+

Crazylemon64 updated:

+
    +
  • You can now fasten the circulators in the TEG kit with a wrench - no adminbus needed to set it up, now
  • +
  • You can now rename cassette tapes with a pen.
  • +
  • You can now wipe data from a tape from its right-click menu.
  • +
+

FalseIncarnate updated:

+
    +
  • Adds 4 new types of fudge for the chef to make: Peanut, Chocolate Cherry, Cookies 'n' Cream, and Turtle Fudge.
  • +
  • Normal fudge recipe now uses milk instead of cream.
  • +
  • Mutant/Modified/Enhanced plants will no longer infinitely increase their name length, and instead will be simply "mutant", "modified", or "enhanced" plant as determined by the last type of modification they were subject to.
  • +
  • Bees can no longer phase through hydroponics lids, giving botanists a way to finally stem the tide of pollination.
  • +
  • Premade beeboxes now spawn with the right type of bees, specifically of the worker caste.
  • +
+

Fox McCloud updated:

+
    +
  • Donk pockets have more omnizine, but only upon fully consuming the donk pocket
  • +
  • swarmers will drop an artificial bluespace crystal on death
  • +
  • Orion Trail guards now drop an energy shield and C20R on death
  • +
  • Reviving simple animals with strange reagent will prevent them from dropping any further loot
  • +
+

KasparoVy updated:

+
    +
  • Rejuvenating a mob now unbuckles them correctly (if they're buckled to something).
  • +
  • Rejuvenating a mob will no longer remove their hair.
  • +
  • Rejuvenating a mob will no longer permanently blacken their eyes.
  • +
  • Rejuvenating a mob will no longer remove their prostheses with fleshy limbs, it will just fix the prostheses.
  • +
  • Rejuvenating a mob will not remove organs/limbs belonging to other species if said organs/limbs are in the same place(s) as the mob's default organs/limbs would be.
  • +
  • Fixes a runtime when trying to flip with an object other than a grab in your hand.
  • +
  • Doing a 'cybernetic repair' procedure on the head of a disfigured IPC will re-figure them.
  • +
  • Rejuvenating a mob will only regrow organs/limbs that are missing (by comparison to the standard organs for their species).
  • +
  • The regenerate_icons proc will now update skin tone and body accessories properly.
  • +
  • Organ rejuvenation now clears disfigurement and closes open wounds.
  • +
  • Rejuvenating a mob will end all in-progress surgeries.
  • +
  • Vox get their cortical stacks back, since the non-implant ones don't interfere with the Heist game-mode.
  • +
  • Rejuvenating a long-dead or husked mob will now clear the appropriate mutations.
  • +
+

QuinnAggeler updated:

+
    +
  • Species disguise variable for clothing items
  • +
  • Species disguise string, "High-tech robot," for cardborg suit and helmet
  • +
  • ABSTRACT flagged clothing items will not be displayed on examination
  • +
+

Tastyfish updated:

+
    +
  • Removes n2 pills healing vox oxyloss, and o2 pills poisoning vox.
  • +
+

monster860 updated:

+
    +
  • Adds the floor painter. Sprite by FlattestGuitar
  • +
+

20 May 2016

Fox McCloud updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index a8361706d21..9ae2b44105f 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -1529,3 +1529,98 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. monster860: - rscadd: Adds the permanent teleporter. Use the circuitboard on a teleporter hub to set the target before constructing it. +2016-05-24: + CrAzYPiLoT: + - rscadd: Adds the ability to attach signalers to bear traps. Stealthy hunting! + Crazylemon64: + - rscadd: You can now fasten the circulators in the TEG kit with a wrench - no adminbus + needed to set it up, now + - rscadd: You can now rename cassette tapes with a pen. + - rscadd: You can now wipe data from a tape from its right-click menu. + FalseIncarnate: + - rscadd: 'Adds 4 new types of fudge for the chef to make: Peanut, Chocolate Cherry, + Cookies ''n'' Cream, and Turtle Fudge.' + - tweak: Normal fudge recipe now uses milk instead of cream. + - tweak: Mutant/Modified/Enhanced plants will no longer infinitely increase their + name length, and instead will be simply "mutant", "modified", or "enhanced" + plant as determined by the last type of modification they were subject to. + - tweak: Bees can no longer phase through hydroponics lids, giving botanists a way + to finally stem the tide of pollination. + - bugfix: Premade beeboxes now spawn with the right type of bees, specifically of + the worker caste. + Fox McCloud: + - tweak: Donk pockets have more omnizine, but only upon fully consuming the donk + pocket + - tweak: swarmers will drop an artificial bluespace crystal on death + - tweak: Orion Trail guards now drop an energy shield and C20R on death + - tweak: Reviving simple animals with strange reagent will prevent them from dropping + any further loot + KasparoVy: + - bugfix: Rejuvenating a mob now unbuckles them correctly (if they're buckled to + something). + - bugfix: Rejuvenating a mob will no longer remove their hair. + - bugfix: Rejuvenating a mob will no longer permanently blacken their eyes. + - bugfix: Rejuvenating a mob will no longer remove their prostheses with fleshy + limbs, it will just fix the prostheses. + - bugfix: Rejuvenating a mob will not remove organs/limbs belonging to other species + if said organs/limbs are in the same place(s) as the mob's default organs/limbs + would be. + - bugfix: Fixes a runtime when trying to flip with an object other than a grab in + your hand. + - bugfix: Doing a 'cybernetic repair' procedure on the head of a disfigured IPC + will re-figure them. + - tweak: Rejuvenating a mob will only regrow organs/limbs that are missing (by comparison + to the standard organs for their species). + - tweak: The regenerate_icons proc will now update skin tone and body accessories + properly. + - rscadd: Organ rejuvenation now clears disfigurement and closes open wounds. + - rscadd: Rejuvenating a mob will end all in-progress surgeries. + - rscadd: Vox get their cortical stacks back, since the non-implant ones don't interfere + with the Heist game-mode. + - rscadd: Rejuvenating a long-dead or husked mob will now clear the appropriate + mutations. + QuinnAggeler: + - rscadd: Species disguise variable for clothing items + - rscadd: Species disguise string, "High-tech robot," for cardborg suit and helmet + - tweak: ABSTRACT flagged clothing items will not be displayed on examination + Tastyfish: + - rscdel: Removes n2 pills healing vox oxyloss, and o2 pills poisoning vox. + monster860: + - rscadd: Adds the floor painter. Sprite by FlattestGuitar +2016-05-25: + CrAzYPiLoT: + - rscadd: Adds an unread change notification. + Fox McCloud: + - tweak: Removes Dragon's Breath Recipe + - tweak: Removes Ghost Chilli Juice + - bugfix: Fixes buckled flipping over someone + IK3I: + - bugfix: Sleepers, scanners, and borg chargers no longer remove you from existence + when destroyed + - bugfix: Hostile mobs are no longer fooled by your clever scanner and recharger + tricks +2016-05-31: + CrAzYPiLoT: + - bugfix: Fixes potential exploits involving door remotes. + - rscadd: Adds another type of remote door control. + Fox McCloud: + - rscadd: Allows Chaplain to select a wide new range of null rod customizations + - tweak: Slightly increases null rod damage (15->18) + - bugfix: Fixes abductors speaking other languages + - bugfix: Fixes traitors getting less TC on some game modes + QuinnAggeler: + - tweak: All lazarus revived mobs become valid for pet collaring + Tastyfish: + - rscadd: Adds a suicide for light tubes. + - experiment: Progress bars, buttons, and several of the values in UI's are now + animated. + - tweak: Deconstructing glass tables now gives a stack of 2 sheets of glass. + monster860: + - tweak: Upgrading the experimentor will no longer reduce the chance of upgrading + an item's tech + - rscadd: Guest passes can now be attached to an ID card. + - rscadd: Adds a HoP guest pass computer, which is like a normal guest pass computer, + but using an ID with ID computer access will allow it to issue guest passes + with any access. + - rscadd: Adds the HoP guest pass computer to the HoP office. + - rscadd: Moves the guest pass computer in robotics to RnD. diff --git a/html/changelogs/AutoChangeLog-pr-4383.yml b/html/changelogs/AutoChangeLog-pr-4383.yml new file mode 100644 index 00000000000..ea862e39a05 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4383.yml @@ -0,0 +1,11 @@ +author: IK3I +delete-after: True +changes: + - rscadd: "crate cargo system" + - rscadd: "passenger seat system" + - rscadd: "loot box secondary cargo system (install it and your pod has a standard inventory)" + - rscadd: "lock busters for the CE and Armory" + - bugfix: "incappacitated people can't operate the door controls anymore" + - bugfix: "Items dropped in a pod can now be scrounged up" + - bugfix: "security can rip you out of an unlocked pod" + - bugfix: "The pod code isn't full of tumors any more" diff --git a/html/changelogs/AutoChangeLog-pr-4474.yml b/html/changelogs/AutoChangeLog-pr-4474.yml deleted file mode 100644 index eb58c1daf4a..00000000000 --- a/html/changelogs/AutoChangeLog-pr-4474.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Tastyfish -delete-after: True -changes: - - rscdel: "Removes n2 pills healing vox oxyloss, and o2 pills poisoning vox." diff --git a/html/changelogs/AutoChangeLog-pr-4477.yml b/html/changelogs/AutoChangeLog-pr-4477.yml deleted file mode 100644 index b0e53674ec0..00000000000 --- a/html/changelogs/AutoChangeLog-pr-4477.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: FalseIncarnate -delete-after: True -changes: - - rscadd: "Adds 4 new types of fudge for the chef to make: Peanut, Chocolate Cherry, Cookies 'n' Cream, and Turtle Fudge." - - tweak: "Normal fudge recipe now uses milk instead of cream." diff --git a/html/changelogs/AutoChangeLog-pr-4485.yml b/html/changelogs/AutoChangeLog-pr-4485.yml deleted file mode 100644 index 4888746f37f..00000000000 --- a/html/changelogs/AutoChangeLog-pr-4485.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Crazylemon64 -delete-after: True -changes: - - rscadd: "You can now fasten the circulators in the TEG kit with a wrench - no adminbus needed to set it up, now" diff --git a/html/changelogs/AutoChangeLog-pr-4541.yml b/html/changelogs/AutoChangeLog-pr-4541.yml new file mode 100644 index 00000000000..d8bb77d3f58 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4541.yml @@ -0,0 +1,4 @@ +author: DaveTheHeadcrab +delete-after: True +changes: + - tweak: "Removes xenobio golem rune creation sound" diff --git a/html/changelogs/AutoChangeLog-pr-4545.yml b/html/changelogs/AutoChangeLog-pr-4545.yml new file mode 100644 index 00000000000..03d1f21b0c6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4545.yml @@ -0,0 +1,4 @@ +author: Crazylemon64 +delete-after: True +changes: + - bugfix: "There will no longer be a mountain of startup runtimes when people have custom languages." diff --git a/icons/goonstation/objects/syringe.dmi b/icons/goonstation/objects/syringe.dmi new file mode 100644 index 00000000000..4bde6be96bd Binary files /dev/null and b/icons/goonstation/objects/syringe.dmi differ diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi index 877f91de1f4..ce634c701d9 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index c649cee3ec2..67313e46bfb 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index c0b8af3b551..1462d26e344 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi index 6bad482e8e4..062fb83e28b 100644 Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 46a4a974316..6e749fc11ec 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/icons/obj/hypo.dmi b/icons/obj/hypo.dmi new file mode 100644 index 00000000000..fe42acbe4d2 Binary files /dev/null and b/icons/obj/hypo.dmi differ diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi index 94e2f2e7d27..42ba9cf7f29 100644 Binary files a/icons/obj/reagentfillings.dmi and b/icons/obj/reagentfillings.dmi differ diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi deleted file mode 100644 index 1621a9d8f2d..00000000000 Binary files a/icons/obj/syringe.dmi and /dev/null differ diff --git a/icons/obj/syringefilling.dmi b/icons/obj/syringefilling.dmi index 74f72313b91..7bb9d675437 100644 Binary files a/icons/obj/syringefilling.dmi and b/icons/obj/syringefilling.dmi differ diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi index 728bfaba198..a10524fb9b9 100644 Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ diff --git a/icons/vehicles/spacepod.dmi b/icons/vehicles/spacepod.dmi index e55085622c9..54edb864aba 100644 Binary files a/icons/vehicles/spacepod.dmi and b/icons/vehicles/spacepod.dmi differ diff --git a/interface/interface.dm b/interface/interface.dm index 44f74a20e59..589a5e0dc86 100644 --- a/interface/interface.dm +++ b/interface/interface.dm @@ -39,6 +39,11 @@ ) src << browse('html/changelog.html', "window=changes;size=675x650") + if(prefs.lastchangelog != changelog_hash) //if it's already opened, no need to tell them they have unread changes + prefs.lastchangelog = changelog_hash + prefs.save_preferences() + winset(src, "rpane.changelog", "background-color=none;font-style=") + /client/verb/forum() set name = "forum" set desc = "Visit the forum." @@ -221,7 +226,10 @@ Any-Mode: (hotkey doesn't need to be on) set name = "Set Hotkey Mode" set category = "Preferences" - hotkeytype = input("Choose hotkey mode", "Hotkey mode") as null|anything in hotkeylist//ask the user for the hotkey type + var/hkt = input("Choose hotkey mode", "Hotkey mode") as null|anything in hotkeylist//ask the user for the hotkey type + if(!hkt) + return + hotkeytype = hkt var/hotkeys = hotkeylist[hotkeytype]//get the list containing the hotkey names var/hotkeyname = hotkeys[hotkeyon ? "on" : "off"]//get the name of the hotkey, to not clutter winset() to much diff --git a/nano/assets/libraries.min.js b/nano/assets/libraries.min.js index ba3441604d1..6e3405a7be4 100644 --- a/nano/assets/libraries.min.js +++ b/nano/assets/libraries.min.js @@ -1,5 +1,5 @@ -!function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){function n(e){var t="length"in e&&e.length,n=oe.type(e);return"function"===n||oe.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e}function i(e,t,n){if(oe.isFunction(t))return oe.grep(e,function(e,i){return!!t.call(e,i,e)!==n});if(t.nodeType)return oe.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(de.test(t))return oe.filter(t,e,n);t=oe.filter(t,e)}return oe.grep(e,function(e){return oe.inArray(e,t)>=0!==n})}function o(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function r(e){var t=xe[e]={};return oe.each(e.match(be)||[],function(e,n){t[n]=!0}),t}function s(){he.addEventListener?(he.removeEventListener("DOMContentLoaded",a,!1),e.removeEventListener("load",a,!1)):(he.detachEvent("onreadystatechange",a),e.detachEvent("onload",a))}function a(){(he.addEventListener||"load"===event.type||"complete"===he.readyState)&&(s(),oe.ready())}function l(e,t,n){if(void 0===n&&1===e.nodeType){var i="data-"+t.replace(Ne,"-$1").toLowerCase();if(n=e.getAttribute(i),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:Ce.test(n)?oe.parseJSON(n):n}catch(o){}oe.data(e,t,n)}else n=void 0}return n}function u(e){var t;for(t in e)if(("data"!==t||!oe.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function c(e,t,n,i){if(oe.acceptData(e)){var o,r,s=oe.expando,a=e.nodeType,l=a?oe.cache:e,u=a?e[s]:e[s]&&s;if(u&&l[u]&&(i||l[u].data)||void 0!==n||"string"!=typeof t)return u||(u=a?e[s]=Y.pop()||oe.guid++:s),l[u]||(l[u]=a?{}:{toJSON:oe.noop}),"object"!=typeof t&&"function"!=typeof t||(i?l[u]=oe.extend(l[u],t):l[u].data=oe.extend(l[u].data,t)),r=l[u],i||(r.data||(r.data={}),r=r.data),void 0!==n&&(r[oe.camelCase(t)]=n),"string"==typeof t?(o=r[t],null==o&&(o=r[oe.camelCase(t)])):o=r,o}}function f(e,t,n){if(oe.acceptData(e)){var i,o,r=e.nodeType,s=r?oe.cache:e,a=r?e[oe.expando]:oe.expando;if(s[a]){if(t&&(i=n?s[a]:s[a].data)){oe.isArray(t)?t=t.concat(oe.map(t,oe.camelCase)):t in i?t=[t]:(t=oe.camelCase(t),t=t in i?[t]:t.split(" ")),o=t.length;for(;o--;)delete i[t[o]];if(n?!u(i):!oe.isEmptyObject(i))return}(n||(delete s[a].data,u(s[a])))&&(r?oe.cleanData([e],!0):ne.deleteExpando||s!=s.window?delete s[a]:s[a]=null)}}}function d(){return!0}function p(){return!1}function h(){try{return he.activeElement}catch(e){}}function g(e){var t=We.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function m(e,t){var n,i,o=0,r=typeof e.getElementsByTagName!==_e?e.getElementsByTagName(t||"*"):typeof e.querySelectorAll!==_e?e.querySelectorAll(t||"*"):void 0;if(!r)for(r=[],n=e.childNodes||e;null!=(i=n[o]);o++)!t||oe.nodeName(i,t)?r.push(i):oe.merge(r,m(i,t));return void 0===t||t&&oe.nodeName(e,t)?oe.merge([e],r):r}function v(e){Pe.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t){return oe.nodeName(e,"table")&&oe.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function b(e){return e.type=(null!==oe.find.attr(e,"type"))+"/"+e.type,e}function x(e){var t=Qe.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function w(e,t){for(var n,i=0;null!=(n=e[i]);i++)oe._data(n,"globalEval",!t||oe._data(t[i],"globalEval"))}function T(e,t){if(1===t.nodeType&&oe.hasData(e)){var n,i,o,r=oe._data(e),s=oe._data(t,r),a=r.events;if(a){delete s.handle,s.events={};for(n in a)for(i=0,o=a[n].length;o>i;i++)oe.event.add(t,n,a[n][i])}s.data&&(s.data=oe.extend({},s.data))}}function _(e,t){var n,i,o;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!ne.noCloneEvent&&t[oe.expando]){o=oe._data(t);for(i in o.events)oe.removeEvent(t,i,o.handle);t.removeAttribute(oe.expando)}"script"===n&&t.text!==e.text?(b(t).text=e.text,x(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),ne.html5Clone&&e.innerHTML&&!oe.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Pe.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:"input"!==n&&"textarea"!==n||(t.defaultValue=e.defaultValue)}}function C(t,n){var i,o=oe(n.createElement(t)).appendTo(n.body),r=e.getDefaultComputedStyle&&(i=e.getDefaultComputedStyle(o[0]))?i.display:oe.css(o[0],"display");return o.detach(),r}function N(e){var t=he,n=Ze[e];return n||(n=C(e,t),"none"!==n&&n||(Ke=(Ke||oe("