diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index c05e74a467a..043a47a02ad 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -50,8 +50,8 @@ CREATE TABLE `characters` ( `eyes_red` smallint(4) NOT NULL, `eyes_green` smallint(4) NOT NULL, `eyes_blue` smallint(4) NOT NULL, - `underwear` smallint(4) NOT NULL, - `undershirt` smallint(4) NOT NULL, + `underwear` mediumtext NOT NULL, + `undershirt` mediumtext NOT NULL, `backbag` smallint(4) NOT NULL, `b_type` varchar(45) NOT NULL, `alternate_option` smallint(4) NOT NULL, @@ -438,4 +438,21 @@ CREATE TABLE `whitelist` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +-- +-- Table structure for table `watch` +-- + +DROP TABLE IF EXISTS `erro_watch`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `erro_watch` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ckey` varchar(32) NOT NULL, + `reason` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- Dump completed on 2013-03-24 18:02:35 + -- Dump completed on 2015-05-28 19:57:44 diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index ca6a3416996..62d2c9ec126 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -663,7 +663,7 @@ "amM" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass_security{name = "Security Office"; req_access_txt = "63"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/turf/simulated/floor,/area/security/main) "amN" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass_security{name = "Security Office"; req_access_txt = "63"},/turf/simulated/floor,/area/security/main) "amO" = (/obj/machinery/navbeacon{codes_txt = "delivery;dir=1"; dir = 1; freq = 1400; location = "Security"},/obj/structure/plasticflaps{opacity = 1},/turf/simulated/floor/plating,/area/maintenance/fsmaint) -"amP" = (/obj/machinery/light/small{dir = 1},/obj/structure/closet/emcloset,/obj/machinery/camera/xray{c_tag = "Brig Escape Pod"; network = list("SS13")},/turf/simulated/floor/plating,/area/maintenance/fsmaint) +"amP" = (/obj/machinery/light/small{dir = 1},/obj/structure/closet/emcloset,/obj/machinery/camera{c_tag = "Security Pod"; dir = 2; network = list("SS13")},/turf/simulated/floor/plating,/area/maintenance/fsmaint) "amQ" = (/turf/simulated/floor/plating,/obj/structure/shuttle/engine/propulsion/burst{dir = 4},/turf/simulated/shuttle/wall{tag = "icon-swall_f6"; icon_state = "swall_f6"; dir = 2},/area/shuttle/escape_pod3/station) "amR" = (/turf/simulated/shuttle/wall{tag = "icon-swall12"; icon_state = "swall12"; dir = 2},/area/shuttle/escape_pod3/station) "amS" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s10"; icon_state = "swall_s10"; dir = 2},/area/shuttle/escape_pod3/station) @@ -1337,7 +1337,7 @@ "azK" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/crew_quarters/fitness) "azL" = (/turf/simulated/wall,/area/mimeoffice) "azM" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/table/woodentable,/obj/item/weapon/reagent_containers/spray/waterflower,/turf/simulated/floor/wood,/area/mimeoffice) -"azN" = (/obj/structure/table/woodentable,/obj/item/weapon/pen/red{pixel_x = 2; pixel_y = 6},/obj/item/weapon/paper_bin,/obj/item/toy/crayon/mime,/obj/machinery/light_switch{name = "light switch "; dir = 2; pixel_x = 0; pixel_y = -22},/turf/simulated/floor/wood,/area/mimeoffice) +"azN" = (/obj/structure/table/woodentable,/obj/item/weapon/pen/red{pixel_x = 2; pixel_y = 6},/obj/item/weapon/paper_bin,/obj/item/toy/crayon/mime,/turf/simulated/floor/wood,/area/mimeoffice) "azO" = (/obj/machinery/camera{c_tag = "Magistrate's Office"; dir = 4; network = list("SS13")},/turf/simulated/floor/carpet,/area/magistrateoffice) "azP" = (/obj/machinery/hologram/holopad,/turf/simulated/floor/carpet,/area/magistrateoffice) "azQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/carpet,/area/magistrateoffice) @@ -1353,7 +1353,7 @@ "aAa" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 1; on = 1},/turf/simulated/floor{icon_state = "neutral"; dir = 9},/area/crew_quarters/fitness) "aAb" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 1; on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/machinery/alarm{pixel_y = 23},/turf/simulated/floor{icon_state = "neutral"; dir = 5},/area/crew_quarters/fitness) "aAc" = (/obj/machinery/firealarm{dir = 2; pixel_y = 24},/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/crew_quarters/fitness) -"aAd" = (/obj/machinery/requests_console{department = "Crew Quarters"; name = "Crew Quarters Requests Console"; pixel_y = 30},/obj/machinery/camera/xray{c_tag = "Dormitories North"; network = list("SS13")},/obj/machinery/vending/cigarette,/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/crew_quarters/fitness) +"aAd" = (/obj/machinery/requests_console{department = "Crew Quarters"; name = "Crew Quarters Requests Console"; pixel_y = 30},/obj/machinery/vending/cigarette,/obj/machinery/camera{c_tag = "Dormitories North"; dir = 2; network = list("SS13")},/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/crew_quarters/fitness) "aAe" = (/obj/machinery/vending/cola,/obj/machinery/light{dir = 1},/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/crew_quarters/fitness) "aAf" = (/obj/machinery/vending/snack,/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/crew_quarters/fitness) "aAg" = (/obj/machinery/vending/coffee,/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/crew_quarters/fitness) @@ -1464,7 +1464,7 @@ "aCh" = (/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1450; master_tag = "bar_maint"; name = "exterior access button"; pixel_x = -25; pixel_y = -25; req_access_txt = "13"},/turf/simulated/floor/plating/airless/catwalk,/area/space) "aCi" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor,/area/crew_quarters/fitness) "aCj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor,/area/crew_quarters/fitness) -"aCk" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10; initialize_directions = 10; level = 1},/obj/machinery/camera/xray{c_tag = "Fitness Rooms North"; network = list("SS13")},/turf/simulated/floor{icon_state = "neutral"; dir = 4},/area/crew_quarters/fitness) +"aCk" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10; initialize_directions = 10; level = 1},/obj/machinery/camera{c_tag = "Fitness Rooms North"; dir = 2; network = list("SS13")},/turf/simulated/floor{icon_state = "neutral"; dir = 4},/area/crew_quarters/fitness) "aCl" = (/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/wood,/area/crew_quarters/fitness) "aCm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor,/area/crew_quarters/fitness) "aCn" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor{icon_state = "neutral"; dir = 4},/area/crew_quarters/fitness) @@ -1582,7 +1582,7 @@ "aEv" = (/obj/effect/spawner/window,/turf/simulated/floor/plating,/area/hallway/secondary/construction{name = "\improper Garden"}) "aEw" = (/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/hallway/secondary/entry) "aEx" = (/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth{frequency = 1380; id_tag = "escape_pod_1_berth"; pixel_x = -25; pixel_y = 30; tag_door = "escape_pod_1_berth_hatch"},/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/hallway/secondary/entry) -"aEy" = (/obj/item/device/radio/intercom{broadcasting = 0; name = "Station Intercom (General)"; pixel_y = 20},/obj/machinery/light{dir = 1},/obj/machinery/camera/xray{c_tag = "Arrivals Escape Pods"},/turf/simulated/floor,/area/hallway/secondary/entry) +"aEy" = (/obj/item/device/radio/intercom{broadcasting = 0; name = "Station Intercom (General)"; pixel_y = 20},/obj/machinery/light{dir = 1},/obj/machinery/camera{c_tag = "Arrivals Escape Pods"; dir = 2},/turf/simulated/floor,/area/hallway/secondary/entry) "aEz" = (/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth{frequency = 1380; id_tag = "escape_pod_2_berth"; pixel_x = -25; pixel_y = 30; tag_door = "escape_pod_2_berth_hatch"},/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/hallway/secondary/entry) "aEA" = (/obj/machinery/alarm{frequency = 1439; pixel_y = 23},/turf/simulated/floor{dir = 1; icon_state = "arrival"},/area/hallway/secondary/entry) "aEB" = (/obj/machinery/light{dir = 1},/turf/simulated/floor{dir = 1; icon_state = "arrival"},/area/hallway/secondary/entry) @@ -1661,13 +1661,13 @@ "aFW" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor{icon_state = "dark"},/area/ai_monitored/storage/eva) "aFX" = (/turf/simulated/floor{icon_state = "dark"},/area/ai_monitored/storage/eva) "aFY" = (/obj/machinery/door/airlock/glass_command{name = "Softsuits"; req_access_txt = "18"},/turf/simulated/floor{icon_state = "dark"},/area/ai_monitored/storage/eva) -"aFZ" = (/turf/simulated/floor{dir = 9; icon_state = "warning"},/area/ai_monitored/storage/eva) +"aFZ" = (/obj/machinery/camera/motion{c_tag = "EVA Northwest"; dir = 2; network = list("SS13")},/turf/simulated/floor{dir = 9; icon_state = "warning"},/area/ai_monitored/storage/eva) "aGa" = (/obj/machinery/firealarm{dir = 2; pixel_y = 24},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/ai_monitored/storage/eva) "aGb" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/vending/eva,/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/ai_monitored/storage/eva) "aGc" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/ai_monitored/storage/eva) "aGd" = (/obj/machinery/power/apc{dir = 1; name = "EVA APC"; pixel_x = 3; pixel_y = 23},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/ai_monitored/storage/eva) "aGe" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/alarm{pixel_y = 23},/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/ai_monitored/storage/eva) -"aGf" = (/turf/simulated/floor{dir = 5; icon_state = "warning"},/area/ai_monitored/storage/eva) +"aGf" = (/obj/machinery/camera{c_tag = "EVA Northeast"; dir = 2; network = list("SS13")},/turf/simulated/floor{dir = 5; icon_state = "warning"},/area/ai_monitored/storage/eva) "aGg" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass_command{name = "Softsuits"; req_access_txt = "18"},/turf/simulated/floor{icon_state = "dark"},/area/ai_monitored/storage/eva) "aGh" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor{icon_state = "dark"},/area/ai_monitored/storage/eva) "aGi" = (/turf/simulated/floor{dir = 8; icon_state = "bluecorner"},/area/hallway/primary/fore) @@ -2198,7 +2198,7 @@ "aQn" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/obj/effect/landmark{name = "blobstart"},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aQo" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/turf/simulated/wall,/area/crew_quarters/kitchen) "aQp" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1; level = 1},/turf/simulated/wall,/area/crew_quarters/kitchen) -"aQq" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/obj/structure/disposalpipe/segment,/obj/machinery/door/airlock/maintenance{name = "Kitchen Maintenance"; req_access_txt = "28"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/crew_quarters/kitchen) +"aQq" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/obj/structure/disposalpipe/segment,/obj/machinery/door/airlock/maintenance{name = "Kitchen Maintenance"; req_access_txt = "28"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aQr" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/obj/structure/plasticflaps{opacity = 1},/obj/machinery/navbeacon{codes_txt = "delivery;dir=2"; freq = 1400; location = "Kitchen"},/turf/simulated/floor{icon_state = "bot"; dir = 1},/area/maintenance/fsmaint2) "aQs" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aQt" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/floor{icon_state = "neutral"; dir = 4},/area/crew_quarters/fitness) @@ -2265,9 +2265,9 @@ "aRC" = (/obj/item/clothing/suit/space/eva/mime,/obj/item/clothing/head/helmet/space/eva/mime,/obj/structure/rack{dir = 8; layer = 2.9},/turf/simulated/floor{icon_state = "dark"},/area/ai_monitored/storage/eva) "aRD" = (/obj/item/clothing/suit/space/eva/clown,/obj/item/clothing/head/helmet/space/eva/clown,/obj/structure/rack{dir = 8; layer = 2.9},/turf/simulated/floor{icon_state = "dark"},/area/ai_monitored/storage/eva) "aRE" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/turf/simulated/floor{dir = 8; icon_state = "warning"},/area/ai_monitored/storage/eva) -"aRF" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/turf/simulated/floor,/area/ai_monitored/storage/eva) +"aRF" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/obj/machinery/camera{c_tag = "EVA Soutwest"; dir = 1; network = list("SS13")},/turf/simulated/floor,/area/ai_monitored/storage/eva) "aRG" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor{icon_state = "dark"},/area/ai_monitored/storage/eva) -"aRH" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/machinery/camera{c_tag = "EVA South"; dir = 1; network = list("SS13")},/turf/simulated/floor,/area/ai_monitored/storage/eva) +"aRH" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/machinery/camera{c_tag = "EVA Southeast"; dir = 1; network = list("SS13")},/turf/simulated/floor,/area/ai_monitored/storage/eva) "aRI" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/turf/simulated/floor{dir = 4; icon_state = "warning"},/area/ai_monitored/storage/eva) "aRJ" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/machinery/light_switch{pixel_y = -25},/turf/simulated/floor{icon_state = "dark"},/area/ai_monitored/storage/eva) "aRK" = (/obj/machinery/firealarm{dir = 2; pixel_y = 24},/obj/structure/flora/kirbyplants,/turf/simulated/floor{dir = 9; icon_state = "blue"},/area/hallway/primary/central/north) @@ -2299,7 +2299,7 @@ "aSk" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/wall,/area/hydroponics) "aSl" = (/turf/simulated/wall,/area/hydroponics) "aSm" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/turf/simulated/wall,/area/hydroponics) -"aSn" = (/obj/structure/disposalpipe/segment,/obj/machinery/door/airlock/maintenance{name = "Hydroponics Maintenance"; req_access_txt = "35"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/turf/simulated/floor/plating,/area/hydroponics) +"aSn" = (/obj/structure/disposalpipe/segment,/obj/machinery/door/airlock/maintenance{name = "Hydroponics Maintenance"; req_access_txt = "35"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aSo" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/wall,/area/hydroponics) "aSp" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall,/area/maintenance/electrical) "aSq" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) @@ -4306,7 +4306,7 @@ "bEP" = (/obj/machinery/atmospherics/unary/vent_pump{on = 1},/turf/simulated/floor{icon_state = "white"},/area/assembly/robotics) "bEQ" = (/obj/structure/table,/obj/item/weapon/storage/firstaid/regular{empty = 1; name = "First-Aid (empty)"},/obj/item/weapon/storage/firstaid/regular{empty = 1; name = "First-Aid (empty)"},/obj/item/weapon/storage/firstaid/regular{empty = 1; name = "First-Aid (empty)"},/obj/item/device/healthanalyzer,/obj/item/device/healthanalyzer,/obj/item/device/healthanalyzer,/obj/machinery/newscaster{pixel_x = 26; pixel_y = 1},/turf/simulated/floor{icon_state = "white"},/area/assembly/robotics) "bER" = (/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Biohazard"; name = "Biohazard Shutter"; opacity = 0},/turf/simulated/floor{icon_state = "bot"},/area/medical/research{name = "Research Division"}) -"bES" = (/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Biohazard"; name = "Biohazard Shutter"; opacity = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor{icon_state = "bot"},/area/medical/research{name = "Research Division"}) +"bES" = (/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Biohazard"; name = "Biohazard Shutter"; opacity = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/camera{c_tag = "Research Hallway Entrance"; dir = 2; network = list("Research","SS13")},/turf/simulated/floor{icon_state = "bot"},/area/medical/research{name = "Research Division"}) "bET" = (/obj/machinery/door_control{id = "rdlab2"; name = "Research and Development Lab Shutters Control"; pixel_x = -24; pixel_y = -24; req_access_txt = "47"},/turf/simulated/floor{icon_state = "white"},/area/toxins/lab) "bEU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/table,/obj/machinery/cell_charger,/obj/item/weapon/stock_parts/cell/high{charge = 100; maxcharge = 15000},/turf/simulated/floor{icon_state = "white"},/area/toxins/lab) "bEV" = (/obj/structure/table,/obj/machinery/requests_console{department = "Cargo Bay"; name = "Cargo Requests Console"; departmentType = 2; pixel_x = -30; pixel_y = 0},/obj/machinery/camera{c_tag = "Cargo Office"; dir = 4; network = list("SS13")},/obj/item/stack/sheet/glass{amount = 50; pixel_x = 3; pixel_y = 3},/obj/item/stack/sheet/metal{amount = 50},/obj/item/device/multitool,/turf/simulated/floor,/area/quartermaster/office) @@ -5928,7 +5928,7 @@ "cjZ" = (/obj/machinery/atmospherics/pipe/tank/toxins{volume = 3200},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "cka" = (/obj/machinery/atmospherics/pipe/tank/oxygen{volume = 3200},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "ckb" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/effect/decal/cleanable/cobweb2,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) -"ckc" = (/obj/effect/decal/cleanable/fungus,/turf/simulated/wall,/area/maintenance/incinerator) +"ckc" = (/obj/effect/decal/remains/human{desc = "This guy seemed to have died in terrible way! Half his remains are dust."; icon_state = "remains"; name = "Human remains"},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "ckd" = (/obj/structure/closet,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/effect/spawner/lootdrop/maintenance{lootcount = 2; name = "2maintenance loot spawner"},/turf/simulated/floor/plating,/area/maintenance/asmaint) "cke" = (/obj/item/weapon/storage/belt/medical,/obj/item/weapon/storage/belt/medical,/obj/item/weapon/storage/belt/medical,/obj/item/clothing/glasses/hud/health,/obj/machinery/light{dir = 8},/obj/machinery/camera{c_tag = "Virology Lab West"; dir = 4; network = list("SS13")},/obj/item/weapon/reagent_containers/spray/cleaner,/obj/structure/table/glass,/obj/machinery/light_switch{pixel_x = -27},/turf/simulated/floor{icon_state = "white"},/area/medical/virology/lab) "ckf" = (/obj/machinery/power/smes{charge = 5e+006; input_attempt = 1},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/structure/cable,/obj/machinery/light{dir = 1; on = 1},/turf/simulated/floor,/area/aisat/maintenance) @@ -6003,7 +6003,6 @@ "clw" = (/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "clx" = (/obj/machinery/atmospherics/binary/pump,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "cly" = (/obj/machinery/power/apc{dir = 4; name = "Incinerator APC"; pixel_x = 24; pixel_y = 0},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) -"clz" = (/turf/simulated/wall,/area/maintenance/incinerator) "clA" = (/obj/machinery/light/small{dir = 8},/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plating,/area/maintenance/apmaint) "clB" = (/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/weapon/circuitboard/crew{pixel_x = -1; pixel_y = 1},/obj/item/weapon/circuitboard/card{pixel_x = 2; pixel_y = -2},/obj/item/weapon/circuitboard/communications{pixel_x = 5; pixel_y = -5},/obj/machinery/light/small{dir = 8},/turf/simulated/floor,/area/storage/tech) "clC" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/machinery/hologram/holopad,/turf/simulated/floor,/area/storage/tech) @@ -6417,9 +6416,10 @@ "ctu" = (/obj/machinery/light/small{dir = 1},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/aft) "ctv" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'HIGH VOLTAGE'"; icon_state = "shock"; name = "HIGH VOLTAGE"; pixel_y = 0},/turf/simulated/wall/r_wall,/area/maintenance/portsolar) "ctw" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/portsolar) +"ctx" = (/obj/structure/closet/emcloset,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/camera{c_tag = "Xenobiology Access"; dir = 2; network = list("Research","SS13"); pixel_x = 0},/turf/simulated/floor{tag = "icon-warnwhite (NORTHEAST)"; icon_state = "warnwhite"; dir = 5},/area/toxins/xenobiology) "cty" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/item/device/radio/intercom{dir = 8; name = "Station Intercom (General)"; pixel_x = -28},/obj/machinery/atmospherics/unary/vent_scrubber{dir = 4; on = 1},/turf/simulated/floor{dir = 9; icon_state = "warnwhite"; tag = "icon-warnwhite (NORTHEAST)"},/area/toxins/xenobiology) "ctz" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4; initialize_directions = 11; level = 1},/obj/structure/disposalpipe/segment,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) -"ctA" = (/obj/structure/closet/emcloset,/obj/machinery/camera/xray{c_tag = "Xenobiology Access"; network = list("Research","SS13")},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor{tag = "icon-warnwhite (NORTHEAST)"; icon_state = "warnwhite"; dir = 5},/area/toxins/xenobiology) +"ctA" = (/obj/machinery/light{dir = 8},/obj/machinery/portable_atmospherics/canister/oxygen,/obj/effect/decal/warning_stripes/blue/hollow,/turf/simulated/floor{icon_state = "dark"},/area/atmos) "ctB" = (/obj/structure/table/reinforced,/obj/item/device/taperecorder,/obj/item/device/tape/random{pixel_x = 3; pixel_y = -3},/turf/simulated/floor{icon_state = "white"},/area/toxins/misc_lab) "ctC" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/turf/simulated/floor{icon_state = "white"},/area/toxins/misc_lab) "ctD" = (/obj/machinery/atmospherics/pipe/simple/hidden/green{dir = 4; level = 2},/turf/simulated/wall/r_wall,/area/toxins/test_chamber) @@ -6430,6 +6430,8 @@ "ctI" = (/obj/machinery/light,/obj/structure/clownstatue,/turf/simulated/floor/wood,/area/clownoffice) "ctJ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/engine{icon_state = "stage_stairs"; name = "reinforced stairs"},/area/toxins/test_chamber) "ctK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/sparker{id = "testigniter"; name = "Test Igniter"; pixel_x = -25},/turf/simulated/floor/engine,/area/toxins/test_chamber) +"ctL" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/machinery/portable_atmospherics/canister/nitrogen,/obj/effect/decal/warning_stripes/red/hollow,/obj/machinery/camera{c_tag = "Atmospherics North-West"; dir = 4; network = list("SS13")},/turf/simulated/floor{icon_state = "dark"},/area/atmos) +"ctM" = (/obj/machinery/requests_console{department = "Engineering"; departmentType = 3; name = "Engineering Requests Console"; pixel_y = 30},/obj/structure/table,/obj/item/weapon/book/manual/engineering_guide,/obj/item/weapon/book/manual/engineering_particle_accelerator{pixel_y = 6},/obj/item/weapon/book/manual/engineering_singularity_safety,/obj/machinery/camera{c_tag = "Engineering Northwest"; network = list("SS13")},/turf/simulated/floor,/area/engine/engineering) "ctP" = (/obj/structure/spacepoddoor,/obj/machinery/door/poddoor/three_tile_ver{id_tag = "mechpodbay"; layer = 3.1; req_access_txt = "70"},/turf/simulated/floor/engine,/area/engine/mechanic_workshop) "ctQ" = (/obj/machinery/door_control{desc = "A remote control-switch for the pod doors."; id = "mechpodbay"; name = "Pod Door Control"; pixel_x = 0; pixel_y = -24; req_access_txt = "70"},/turf/simulated/floor/engine,/area/engine/mechanic_workshop) "ctR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_y = -22},/turf/simulated/floor/engine,/area/engine/mechanic_workshop) @@ -6818,7 +6820,6 @@ "cCf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/wall,/area/hallway/primary/aft) "cCh" = (/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Engineering"; name = "Engineering Security Doors"; opacity = 0},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/door/firedoor{dir = 1; name = "Firelock North"},/obj/machinery/door/airlock/glass_engineering{name = "Engineering"; req_access_txt = "10"; req_one_access_txt = "0"},/turf/simulated/floor,/area/engine/equipmentstorage) "cCm" = (/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Engineering"; name = "Engineering Security Doors"; opacity = 0},/obj/machinery/door/firedoor{dir = 1; name = "Firelock North"},/obj/machinery/door/airlock/glass_engineering{name = "Engineering"; req_access_txt = "10"; req_one_access_txt = "0"},/turf/simulated/floor,/area/engine/equipmentstorage) -"cCo" = (/obj/machinery/camera{c_tag = "Atmospherics North-West"; dir = 4; network = list("SS13")},/obj/machinery/light{dir = 8},/obj/machinery/portable_atmospherics/canister/oxygen,/obj/effect/decal/warning_stripes/blue/hollow,/turf/simulated/floor{icon_state = "dark"},/area/atmos) "cCp" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/effect/decal/warning_stripes/blue/hollow,/turf/simulated/floor{icon_state = "dark"},/area/atmos) "cCq" = (/turf/simulated/floor,/turf/simulated/floor{tag = "icon-siding8 (NORTH)"; icon_state = "siding8"; dir = 1},/area/atmos) "cCr" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 1; on = 1},/turf/simulated/floor,/area/atmos) @@ -6875,7 +6876,6 @@ "cDu" = (/turf/simulated/floor,/area/engine/equipmentstorage) "cDv" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/obj/machinery/light_switch{pixel_x = 27},/turf/simulated/floor,/area/engine/equipmentstorage) "cDw" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11; level = 1},/turf/simulated/wall/r_wall,/area/atmos) -"cDx" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/machinery/portable_atmospherics/canister/nitrogen,/obj/effect/decal/warning_stripes/red/hollow,/turf/simulated/floor{icon_state = "dark"},/area/atmos) "cDy" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/obj/effect/decal/warning_stripes/red/hollow,/turf/simulated/floor{icon_state = "dark"},/area/atmos) "cDz" = (/turf/simulated/floor,/obj/item/device/radio/beacon,/turf/simulated/floor{tag = "icon-siding8 (NORTH)"; icon_state = "siding8"; dir = 1},/area/atmos) "cDA" = (/turf/simulated/floor,/area/atmos) @@ -6981,7 +6981,6 @@ "cFK" = (/obj/effect/decal/cleanable/cobweb2,/turf/simulated/floor/plating,/area/maintenance/aft) "cFL" = (/obj/structure/stool/bed/chair,/obj/item/weapon/storage/fancy/cigarettes,/turf/simulated/floor/plating,/area/maintenance/asmaint) "cFM" = (/obj/item/device/radio/intercom{broadcasting = 0; name = "Station Intercom (General)"; pixel_y = 20},/obj/structure/table,/obj/item/weapon/book/manual/engineering_hacking{pixel_x = 3; pixel_y = 3},/obj/item/weapon/book/manual/engineering_construction,/obj/item/weapon/book/manual/supermatter_engine,/turf/simulated/floor,/area/engine/engineering) -"cFN" = (/obj/machinery/requests_console{department = "Engineering"; departmentType = 3; name = "Engineering Requests Console"; pixel_y = 30},/obj/structure/table,/obj/item/weapon/book/manual/engineering_guide,/obj/item/weapon/book/manual/engineering_particle_accelerator{pixel_y = 6},/obj/item/weapon/book/manual/engineering_singularity_safety,/turf/simulated/floor,/area/engine/engineering) "cFO" = (/obj/structure/table,/obj/item/weapon/paper_bin{pixel_x = -3; pixel_y = 7},/obj/item/weapon/pen,/obj/machinery/light{dir = 1},/obj/item/weapon/cartridge/engineering{pixel_x = 3},/obj/item/weapon/cartridge/engineering{pixel_x = -3; pixel_y = 2},/obj/item/weapon/cartridge/engineering{pixel_x = 4; pixel_y = 5},/turf/simulated/floor,/area/engine/engineering) "cFP" = (/obj/machinery/power/apc{cell_type = 15000; dir = 1; name = "Engineering APC"; pixel_x = 0; pixel_y = 25},/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/turf/simulated/floor,/area/engine/engineering) "cFR" = (/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/clothing/shoes/magboots,/obj/item/clothing/suit/space/rig,/obj/item/clothing/mask/breath,/obj/item/clothing/head/helmet/space/rig,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/power/apc{dir = 1; name = "Engineering Hardsuit Storage APC"; pixel_y = 24},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor,/area/engine/hardsuitstorage) @@ -8142,14 +8141,14 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaccZcgfcgecggbTCceIcghcghcghcghcghcghbTIbTIbTIbTIbTIbTIbTIcgicgjcgkcglcgmcgncgocgocgpcgqcfbbHTbHTcgrcgscgtbHTbHTbHTcgucgvcgwcdEcgxcgycgzcfucgAcgBcgCbQWcgBcgDcdTcdTcdTcdTcdTcdTcgBcdTcdTcdTbQWcgEcgFcgGcgHcgIcgJcgKcgLcaAcgMcgNcehcgOcehcgPcgQcgRcgScgTcgUcgVbzwcgWceobXVcgXbDbbDicgYcgZchabumbvWbvWbThchbchcchdchechfchgchhchichjchkchlbThchmchnchochpaacaacaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaachqbWFbWFbWFbWFbWFbWFbWFchrchsbWHbWHbWHbWHchtbdqbUNaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaccZccZccZccZbTCceIccZaaaaaaaaaaaachuchvchwchxchychzchAchBchCchDchEbhrchGchHchIchIchJchKchLchMchMchMchMchNchMbHTbHTbNRchOchPchQchRchSchTcgIchUchVchWchXchYchZciacdTcdTcibcicbhsciebhscicbEDcifcigcigcihciicijcakcikcilcaAcimcinciocipciqcirciscaAcaAbDbcitbDbbDbbDbciucivciwbDbbvWcgYcixciybumbumbumbThbThbThbThbThbThbThbThbThbThbThbThbThbThbThbThbThaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaabUNcbicbicbicbicbicbicizbWHcbhcbiciAbWHbWHbWHbWHbUNaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciBaaaaabaabciCciCciCciCciCciCciDciCbTCcdbbhtaaabhubjJbhYbjYciJciKciLciMciNciOciPciQciRciSciTciUciVciWciXciYciZchLcjacjbcjbcjbcjcchMbHTbHTcjdcjdcjdcjdcjecjdcjfcjfcjgcjdcjdcjhcjdcjicjjbkycjlbkycjmcjncjocjpcjqbuXbuXcjrcjscjtcjucjvcjwcjxcbScaAcaAcjycaAcjzcaAcjAcjBcjCcfdcjDcjFcjGcjHcjIcjJcjKcjLcjIbvWcgYcjMbvWcjNcjOcjPcjQcfQbvWbvWbvWbvWbvWbvWbvWcjRcjEaZCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabUNbWHbWHbWHbWHbWHbWHceDbWHciAbWHbWHbWHbWHbWHbUNbUNaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacjTcjUcjUcjUbkzcjWcjXcjYcjZckackbckccjScdbbhtaaabmZckgckhckickjciKckkbURckmcknchBckoceTbZUbhrckpcgockqcgockrcksbneckuckvckvckvckwchMbHTbHTcjdckxckyckzckAckBckCckCckDckEckFckGckHckIckJckKcdXcdXckLckMckNckOckPaaaaaacjvckQckRckScjrckdckUckVckWckWckXbGickYckZclaclbckZckZckZclcckZckZcldcleclfclgclhclicljclkbWycllclmbWybWybWybWyclnclobWybWybWybWyclpbvWaZCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabUNbUNccYbWHbWHbWHbWHbWHbWHbWHbWHbWHbWHbWHbUNbUNaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaclrclsclsclsclscltcluclvclwclxclxclyclzclAceIbhtaaabmZclBclCclDclEclFclGclHclEclEclIclJclKclLclMclMclNclOcgoclPclQbneckvckvckvckvclSchMbHTbHTcjdclTclUclVclWclXclYclYclZcmacmbcmccmdcmecjdcmfcdTcmgbEDcmhckNcmickPaaaaaacjvcmjcmkcmlcjvbHUcmmcmncmncmncmncmncmnckTcmpcmqcmocmscmsbnfbnfcmscmvcmwcmxcmycmzcmAcmBcmCcmAcmAcmAcmAcmAcmAcmAcmAcmAcmAcmAcmAbvWcmDcmraZCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabZEbUNbUNcgbcgbbWHbWHbWHbWHbWHbWHbWHbWHbUNbUNaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacmEcmFcmGcmHcmGcmIcmJcmKcmLbRSbGWclzcmNcdbbhtaaabmZcmOcmPcmQcmRciKcmScmTcmUcmVchBckoceTcmWcmXceVcmYcmZbhrbhrbhrcndcneckvckvcnfcngchMbHTcnhcjdcnicnjcnkcnlcnlcnlcnmcnncnlcnlcnocnkcnpcnqcnrcdTcnsbEDcntckNcnuckPaaaaaacjvcnvcnwcnxcjvcnybHTcnhcnzcnzcnzcnzcnzbngbnkbnjcnzcnzaaaaaaaaaaaacjIcnDcnEcnFcmAcnGcnIcnHcnKcnJcnMcnLcnOcnNcnQcnPcoXcnRcpacmAcnScnTcnUcnVcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnXcnYbUNbYcbUNbWHbWHbWHbWHbWHbWHbWHbUNbUNaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaaacmEcnZcoacobcocclwcodclwcoeclwcofbxgcohcoibhtaaabnlbjJbnIbjYcomciKciKconcoocopcoqcorcoscotcouceVcovcowcoxcoycozchLcoAckvckvckvcoBchMbHTbHTcoCcoCcoDcoEboQboQboQcoCbpobpobpocoLcoMcoDcoNcmfcdTcmgbEDcoOckNckOckPaaaaaacjvcoPcoQcoRcjvbHTbHTbHTcnzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpPcoTcoUcoVbqlcpbcoYcoYcoZcoYcoYcoYcoYcoYcpdcpccpfcpecphbsybsybYfcpjbsyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabUNcpmcpncpobUNbUNbWHbWHcppbWHbWHbUNbUNaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacmEcpqcmGcprcmGcpsbSzbSHbSEcmKcpwclzcpxcdbccZaaaaaaaaaaaachucpycpzcpAcpAchBcpBchBcpCceTbZUcpDcpEcpFcpGcpHcpHcpHcpIcpJckvcpKckvcpLchMbHTbHTcoCcpMcpNcpOcpPcpQcpRcoCcpQcpRcpPcpScpTcpUcoNcnrcpVcnsbEDcpWckNcpXckPcnzcnzcjvcjvcjvcjvcjvcpYbHTbHTcnzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpPcqacqbcqccqdcpicqfcqhcpgcoYcoYcqjcoYcoYcpdcpfcpfcpfcoXbsycplcpkcqnbsyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcgcqrcqsbYdbUMbUNbUNbWHbdqbWHbUNbUNaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUabCcqtcqtcqtcqtcqtcqtcqtcqtcqucqucqucqucquciCclzclzclzclzclzclzcqvcqwcqxcqxcqxcqxcqxchuchBchBchBchBchBchBchBcqyceTbZUcqzcqAcqBcqCcqDcqEcqFcqGcqHcqIcqJcqKcqLchMbHTbHTcoCcqMcqNcpOcpPcpPcqOcoCcqPcpPcpPcpScpOcqQcoNbEDbEDbEDcqRcqSckNcqTckPczvbHTbHTbHTbHTcqVbHTbHTbHTbHTcnzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpPcqXcqYcqZbricqlcqgcqecqicoYcoYcoYcoYcqmcrhcrbcsvcsucqkbsycqUcqpcribsyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcgbcgbcgbcgbUMbUMbUNbUNbUNbUNbUOaabaabaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacjTcjUcjUcjUbkzcjWcjXcjYcjZckackbciDcjScdbbhtaaabmZckgckhckickjciKckkbURckmcknchBckoceTbZUbhrckpcgockqcgockrcksbneckuckvckvckvckwchMbHTbHTcjdckxckyckzckAckBckCckCckDckEckFckGckHckIckJckKcdXcdXckLckMckNckOckPaaaaaacjvckQckRckScjrckdckUckVckWckWckXbGickYckZclaclbckZckZckZclcckZckZcldcleclfclgclhclicljclkbWycllclmbWybWybWybWyclnclobWybWybWybWyclpbvWaZCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabUNbUNccYbWHbWHbWHbWHbWHbWHbWHbWHbWHbWHbWHbUNbUNaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaclrclsclsclsclscltcluclvclwclxclxclyciCclAceIbhtaaabmZclBclCclDclEclFclGclHclEclEclIclJclKclLclMclMclNclOcgoclPclQbneckvckvckvckvclSchMbHTbHTcjdclTclUclVclWclXclYclYclZcmacmbcmccmdcmecjdcmfcdTcmgbEDcmhckNcmickPaaaaaacjvcmjcmkcmlcjvbHUcmmcmncmncmncmncmncmnckTcmpcmqcmocmscmsbnfbnfcmscmvcmwcmxcmycmzcmAcmBcmCcmAcmAcmAcmAcmAcmAcmAcmAcmAcmAcmAcmAbvWcmDcmraZCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabZEbUNbUNcgbcgbbWHbWHbWHbWHbWHbWHbWHbWHbUNbUNaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacmEcmFcmGcmHcmGcmIcmJcmKcmLbRSbGWciCcmNcdbbhtaaabmZcmOcmPcmQcmRciKcmScmTcmUcmVchBckoceTcmWcmXceVcmYcmZbhrbhrbhrcndcneckvckvcnfcngchMbHTcnhcjdcnicnjcnkcnlcnlcnlcnmcnncnlcnlcnocnkcnpcnqcnrcdTcnsbEDcntckNcnuckPaaaaaacjvcnvcnwcnxcjvcnybHTcnhcnzcnzcnzcnzcnzbngbnkbnjcnzcnzaaaaaaaaaaaacjIcnDcnEcnFcmAcnGcnIcnHcnKcnJcnMcnLcnOcnNcnQcnPcoXcnRcpacmAcnScnTcnUcnVcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnWcnXcnYbUNbYcbUNbWHbWHbWHbWHbWHbWHbWHbUNbUNaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaaacmEcnZcoacobcocclwcodckccoeclwcofbxgcohcoibhtaaabnlbjJbnIbjYcomciKciKconcoocopcoqcorcoscotcouceVcovcowcoxcoycozchLcoAckvckvckvcoBchMbHTbHTcoCcoCcoDcoEboQboQboQcoCbpobpobpocoLcoMcoDcoNcmfcdTcmgbEDcoOckNckOckPaaaaaacjvcoPcoQcoRcjvbHTbHTbHTcnzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpPcoTcoUcoVbqlcpbcoYcoYcoZcoYcoYcoYcoYcoYcpdcpccpfcpecphbsybsybYfcpjbsyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabUNcpmcpncpobUNbUNbWHbWHcppbWHbWHbUNbUNaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacmEcpqcmGcprcmGcpsbSzbSHbSEcmKcpwciCcpxcdbccZaaaaaaaaaaaachucpycpzcpAcpAchBcpBchBcpCceTbZUcpDcpEcpFcpGcpHcpHcpHcpIcpJckvcpKckvcpLchMbHTbHTcoCcpMcpNcpOcpPcpQcpRcoCcpQcpRcpPcpScpTcpUcoNcnrcpVcnsbEDcpWckNcpXckPcnzcnzcjvcjvcjvcjvcjvcpYbHTbHTcnzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpPcqacqbcqccqdcpicqfcqhcpgcoYcoYcqjcoYcoYcpdcpfcpfcpfcoXbsycplcpkcqnbsyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcgcqrcqsbYdbUMbUNbUNbWHbdqbWHbUNbUNaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUabCcqtcqtcqtcqtcqtcqtcqtcqtcqucqucqucqucquciCciCciCciCciCciCciCcqvcqwcqxcqxcqxcqxcqxchuchBchBchBchBchBchBchBcqyceTbZUcqzcqAcqBcqCcqDcqEcqFcqGcqHcqIcqJcqKcqLchMbHTbHTcoCcqMcqNcpOcpPcpPcqOcoCcqPcpPcpPcpScpOcqQcoNbEDbEDbEDcqRcqSckNcqTckPczvbHTbHTbHTbHTcqVbHTbHTbHTbHTcnzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabpPcqXcqYcqZbricqlcqgcqecqicoYcoYcoYcoYcqmcrhcrbcsvcsucqkbsycqUcqpcribsyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcgbcgbcgbcgbUMbUMbUNbUNbUNbUNbUOaabaabaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrmcrncrocrpcrqcrqcrrcrscrtcrucrvcrwcrxbrMcrzcrzcrzcrAcrBcrCcrDcrDcrEcrFcrGcrHcrIcrHcrHcrHcrGcrHcrHcrJcrKcrLcrMceTbZUcrNcrPcrOcrQceVcrRclMcrScrTcrUcrVcrWcrXcrYbHTbHTcoCcrZcsacsbcsccsdcoHcoCcoIcsdcsgcshcsbcsicoNbHTbHTbHTcsjcoOckNcoOcskbHTbHTcFLbHTbHTbHTbHTbHTcfccGOcnzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacslcjIcsmcjLcslcrccrecrdcuQcrfcsocsncoYcoYcsqcspcsscsrcstbsycrkcrjcsxbsyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrmcrncsAcsBcsCcsBcsDcsEcsFcsGcsHcsIcsHcsJcsKcsKcsecsKceTcsfbZVbZVcsKcsLcsKcsKcsKcsKcsKcsKcsKcsKcsKcsKcsMcsNcsOcsPcsQcsRcsScsTcsUcsVcsWcsXcsYcsZctactbctcctdctecmnctfctgcthctictjcoJcoScoKcoCcoWcpPcoJcptcpOctocoNctpcmscmsctqctrctscttckPbnjbnjbnjbnjcnzcnzcnzbnjbnjbnjcnzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacjIctyctzctAcjIcmAcmAcmAcmAcmAcmAcuTcsncuUctBcswctCcmAcmAbsycszcsycszcszaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrmcrncsAcsBcsCcsBcsDcsEcsFcsGcsHcsIcsHcsJcsKcsKcsecsKceTcsfbZVbZVcsKcsLcsKcsKcsKcsKcsKcsKcsKcsKcsKcsKcsMcsNcsOcsPcsQcsRcsScsTcsUcsVcsWcsXcsYcsZctactbctcctdctecmnctfctgcthctictjcoJcoScoKcoCcoWcpPcoJcptcpOctocoNctpcmscmsctqctrctscttckPbnjbnjbnjbnjcnzcnzcnzbnjbnjbnjcnzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacjIctyctzctxcjIcmAcmAcmAcmAcmAcmAcuTcsncuUctBcswctCcmAcmAbsycszcsycszcszaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrmctPcsBctQctRctSctTctUctVctWctXctYctZcuacubcucctkcudcuecdqcufcdqcubcugcubcubcubcubcubcubcubcubcubcubcuhcsKcuicujcukbszbuccuncuocupcuqcurcuscutbufcuvcuwcuxcrVcdzcuycuzcuAcpPcpOcpPcpPcpucoCcpvcpPcpPcpScpOcuEcoNcuFcnzaaacuGckPcuHckPckPaaaaaaaaaaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacjIcjIcjIcjIcjIcjIcjIcjIcjIcuIcuJcuKcjIaabaabaaaaaaaabcmAcmActEcmActGctFctHcmAaaaaaacszctlcszaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUabCcqtcqtcqtcqtcqtcqtcuZcvacvacvbcsHcvccqtcqxcvdcvecvecvfcvecvgcvecvebvYbvZcvecvebvZbvZbvZcvecvecvecvecvlcvmcvncvocvpcvqcvrcvscvtcvscvscvucvscvvbxNcvxcvycvzcrYbHTcuFcvAcvBcvCcvDcvEcvFcvGcoCcvHcvFcvIcpScvJcvKcoNcuFcnzaaacuGcvLcvMcvNckPaaaaaaaaaaaacvOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacjIcvPcvQcvRbxWcvTcvUcvVcvWcvXcvYcvZcjIaabaaaaaaaaaaabaabcwectJcuVcxCcxBcwacweaaaaaacszctmcszaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaczaczaczakSakSaczakSakSakSalwakSakSaabalwawTaaaaabaabcwpcwpcwpcqtcwqcwrcwscwtcwucwvcwwcogcwybxZcwAcwBcwCcwDcwEcwFcwGcwHcwIcvecwHcwJcwKcwLcwLcwMcvecwNcwOcwPcwQbZUcwRbyfcwTcwUcwVcwWcwVcwXcwYbzncxacxbcnBcrYcrYcuFcvAcoNcoNcxdcoNcoNcxecxfcxgcxgcxgcxhcxgcxicxgcxjcnzaaacuGcxkcvMcxlckPbhsbhsbhsbhsckPckPcxpcxqcxqcxrcxqcxqcxrcxsaaaaaacjIcxtbTHcxtcxvcxwcqacxxcvWcxycxzcxycjIaaaaaaaaaaaaaaaaaacwecwbcuWcxCcxCcwccweaaaaaaaaacxJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -8157,10 +8156,10 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKaaaaaaaaaaaaaaaaaaaaaaczaaacyYcyZczaaaacyYcyZczaaaacyYcyZczaaabczbaabaaaaaaaaaaaaaabaabaabaaaaaaaaaaaaaaaaaabxYcwybxZczdcwLcxVczecwLcwLcwLczfcwLczdczdcwLcwLcwLcwLczgbzPcxXczicsKczjbZUcybcybczkcwUczlczmczncwUczoctaczpczqczrczscztcHZbHTczucbSczubHTbHTbHTcuFcZScnzbnjbnjbnjbnjbnjcnzcnzaaaczwczxczycjqczzczAcoOcoOczBbAbczDczEbAbczDczEbAbczDczEcyJaaaaabcjIcvWcvWcvWcvWczFcqaczGczHczIczJczKcjIaabaaaaaaaaaaaaaaacwecuPcuMcxCcxCcuOctDcEpaaaaaacyXaaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaaaaaaaaaaaczaaacyYczVczaaaacyYczVczaaaacyYczVczaaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaabbxYcwybxZczdczYcwLczZcAacAbcAbcxUcwLczdcAccwLcwLcwLcwLcAdcAecAfcAgbYxcAhcAicAjcAkcAlcwUczlcAmcAncwUcAoctacrYcApcrVcAqcArcAscAtcAucAvcAwcAtcAtcAtcAxcAtcnzaaaaaaaaaaaaaaaaaaaabaaacuGcAycvMcAzcAAcABcoOcoOczBbAbcADbAbbAbcADbAbbAbcADbAbcyJaabaabcjIcvPcvQcvRbBBcAIcyMcAJcAKcALcAMcANcjIaabaabaabaabaabaaacwecwecuScuRcwdcwecweaaaaaaaaacyXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaagaaaaaaaaaakSaabcyYczVczaaaacyYczVczaaabcyYczVczaaabaaaaaaaabaabaabaabaabaaaaaaaaaaaaaaaaabaaaaaabxYcwycvecAWcwLcAXcAYcAZcBacBbcBacBccBacBdcBecwHcBfczdczdbzPcBgcBhcBicBjcBkcBlcBmcBncBocBpcBqcBrcBscBtcBucBvcBvcBwcBxcBycBzbBGcBBcBCcBDcBEcBFcBGcBHbBHaabaaaaaaaaaaaaaaaaaaaabaabczwcBJcBKcBLcBMcBNcoOcoOcoOcBOcoOcoOcoOcoOcoOcoOcoOcBPbBIaaaaaacjIcxtbTXcxtcBRcxwcqacBScBTcBUcBVcBWcjIcjIcjIcjIcjIaabaaaaaacwecwecwecwecweaaaaaaaaaaaacyXaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaaaaaaaaaaaabaaacyYczVczaaabcyYczVczaaaacyYczVczaaaaaaaaaaaaaaaaaaaaabaabaabaaaaabaaaaabaabaaaaaacxLcBZcvecCacCbcCbcCccvecvecvecvecvecvecvecvecvecvecvecvecvecCdcCecCdcCfcCdcqxbBYcChbCibChbChbCkcCmbClcBucCocCpcCqcCrcCscCtbBGcCvcCwcCxcCycCzcCAcCBbCwaabcCDcCDcCDcCDcCDaaaaaaaabcuGcCEcvMcCFcCGcCHcCIcoOcoOcCJcoOcoOcoOcoOcoOcCKcoOcCLbBIaaaaaacjIcxtcxtcxtbBBcCNcyMcCOcCPcCQcCRcCScCTcCUcCVcCWcjIaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyXaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaaczaczakSaabaaacyYczVczaaabcyYczVczaaaacyYczVczaaabaaaaaaaaaaaaaaaaaaaaaaaaaabbCxcCYcCYcCYcCYcxLcCZcwycDacDbcDccDccDdcDecDfcDgcDgcDgcDgcDhcDicDjcDicDicDkcDkcDicDlcDmcDncDocDocDpcDqcDrcDscDtcDucDucDvcDwcDxcDycDzcDAcCscDBbBGcDCcDDcDEcDFcDGcDHcDIbCycDKcDLcDMcDNcDOcCDaaaaaacDPcDQcDRcDScDTcDRcDUcDVcDWcDXcDYcDZbzLcDYcEbcEccEdcEebCMcyJaaaaaacjIcvWcvWcvWcvWcEgcqacBScEhcEicBVcEjcEkcElcEmcEnbSIcEpaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyXaabaaaaaaaaaaabaabaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaaaaaaaaaaaabaaacyYczVczaaabcyYczVczaaaacyYczVczaaaaaaaaaaaaaaaaaaaaabaabaabaaaaabaaaaabaabaaaaaacxLcBZcvecCacCbcCbcCccvecvecvecvecvecvecvecvecvecvecvecvecvecCdcCecCdcCfcCdcqxbBYcChbCibChbChbCkcCmbClcBuctAcCpcCqcCrcCscCtbBGcCvcCwcCxcCycCzcCAcCBbCwaabcCDcCDcCDcCDcCDaaaaaaaabcuGcCEcvMcCFcCGcCHcCIcoOcoOcCJcoOcoOcoOcoOcoOcCKcoOcCLbBIaaaaaacjIcxtcxtcxtbBBcCNcyMcCOcCPcCQcCRcCScCTcCUcCVcCWcjIaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyXaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaaczaczakSaabaaacyYczVczaaabcyYczVczaaaacyYczVczaaabaaaaaaaaaaaaaaaaaaaaaaaaaabbCxcCYcCYcCYcCYcxLcCZcwycDacDbcDccDccDdcDecDfcDgcDgcDgcDgcDhcDicDjcDicDicDkcDkcDicDlcDmcDncDocDocDpcDqcDrcDscDtcDucDucDvcDwctLcDycDzcDAcCscDBbBGcDCcDDcDEcDFcDGcDHcDIbCycDKcDLcDMcDNcDOcCDaaaaaacDPcDQcDRcDScDTcDRcDUcDVcDWcDXcDYcDZbzLcDYcEbcEccEdcEebCMcyJaaaaaacjIcvWcvWcvWcvWcEgcqacBScEhcEicBVcEjcEkcElcEmcEnbSIcEpaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyXaabaaaaaaaaaaabaabaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaaczaaaaabaaaaabaabcEqaabaabaabcEqaabaaaaabcEqaabaaaaaaaaaaaaaaaaaaaaaaaabCxbCxbCxcEucEvctnctvctucEzcEAcDacDacEBcECcvecvecEDcEEcEEcEEcEEcEFcEGcEHcEGcEGcEGcDocDocEIcEJcEKcELcEMcDucENcDrcDucDucDucDucEOcBucEPcEQcCqcDAcCscDAbBGcDCcDDcEScETcEUcEVcEWbCUaabcEYcEZcDOcFacCDaaaaaaaaacDQcFbcFccFdcDRcFecFfcFgcFhcFiczEczDcFicFjcFkcFlczEczDcyJaaaaaacjIcvPcvQcvRbDrcAIcyMcFncFocFpcEmcFqcFrcFscFtcFucjIaabaabaagaaaaaaaaaaaaaaaaaaaaaaaaaaacyXaabaaaaaaaaaaabaabaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaakSaabcFvcFwcFwcFxcFycFzcFzcFzcFycFzcFzcFzcFycFzcFzcFAcFwcFwcFwcFwcFwcFBcFCcFDcFEcFFcFGctwcFIcFJceHcwycFKcDacvecvecvecZTcEDcEEcFMcFNcFOcFPbGIcFRcFScFTcFUbDtcFWcFXcFYcFZcGabDtcGccGdcDrcGecDucDucDucGfcBucGgcGgcDAcGhcGicGjcGkcGlcGmcGncGocGpcGqcGrbCycGscDLcGtcDOcDOcCDaaaaaaaabcDQcGucFccGvcDRcGwcGxcCIcGycFicGzcGAcFicGBcGCcFlcGzcGDcyJaaaaaacjIcxtbTHcxtcGEcxwcqacGFcFocGGcqacqacGHcvWcvWcvWcjIaaaaaaaaaaaaamjamjamjawTaabaabaabaabcGIaabaabaabaabaabalwamjamjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaakSaabcFvcFwcFwcFxcFycFzcFzcFzcFycFzcFzcFzcFycFzcFzcFAcFwcFwcFwcFwcFwcFBcFCcFDcFEcFFcFGctwcFIcFJceHcwycFKcDacvecvecvecZTcEDcEEcFMctMcFOcFPbGIcFRcFScFTcFUbDtcFWcFXcFYcFZcGabDtcGccGdcDrcGecDucDucDucGfcBucGgcGgcDAcGhcGicGjcGkcGlcGmcGncGocGpcGqcGrbCycGscDLcGtcDOcDOcCDaaaaaaaabcDQcGucFccGvcDRcGwcGxcCIcGycFicGzcGAcFicGBcGCcFlcGzcGDcyJaaaaaacjIcxtbTHcxtcGEcxwcqacGFcFocGGcqacqacGHcvWcvWcvWcjIaaaaaaaaaaaaamjamjamjawTaabaabaabaabcGIaabaabaabaabaabalwamjamjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaaczaaaaabaaaaabaabcGJaabaaaaabcGJaabaaaaabcGJaabaaaaaaaaaaaaaaaaaaaaaaaabCxbCxbCxcGLcGMcGNcCYcZUceHcGPcEzcEzcEzcEzcGQcEzcFJcEEcGRcGScGTcGUbDGcGWcGXcGYcGZbEocHbcHccHdbFlcktbGPcGccENcDrcZicHjcDucDucHkcBucHlcHmcDAcHncCscHocHpbFvbFtbGBbFQbGEbGCbGEbGGaabcCDcCDcCDcCDcCDaabaabaabcHxcHycFccGvcDRcHzcHAcHBcHCcHDcHEcHFcHFcHGcHFcHHcHIcDRcHJaaaaaacjIcxtcxtcxtbDrcHKcHLcHMcHNcHOcCTcCTcCTcHPcHQcHRbGHaaaaaaaaaaaaamjaaaaabaaaaabaaaaaaaaacHTaaaaabaabaaaaaaaaaaaaamjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaaczaczakSaabaabcyYcHUczaaaacyYcHUczaaaacyYcHUczaaabaaaaaaaaaaaaaaaaaaaaaaabaabbCxcCYcCYcCYcCYcHWcHXcHYceHcZVceHceHcEDcIaceHcEEbYRcaecGTcajbGIcamcIhcIicIjbGRcIlcImcIncIocIpbGRcIrcIscItcIucIvcIwcIxcIycIzcIAcGjcIBcICcIDcIEcIFcIGcIHcIIcIJcIKcILcIMbGVcDKcDLcIPcIOcIOcCDaaaaaaaabcDQcIQcFccIRcDRbIxbIxbIxbIxcDRcIVcIWcIXcIYcIZcJacJbcIYbIBaaacDPcjIcjIcjIcjIcjIcJdcqacJecyMcJfcyMcJgcyMcJhcyMcJibGHaaaaaaaaaaaaamjaaacJkcJkcJkcJkcJkaabcJlaabcJkcJkcJkcJkcJkaaaamjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacJmaaaaaaaaacJmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxKcxKcxKcxKcxKcxKcxKcxKcxKaaaaaaaaaaaaaaaaaaaaaaaacyYcHUczaaabcyYcHUczaaaacyYcHUczaaaaaaaaaaaabaaaaaaaaaaaaaabaabaabaaaaaaaabaabcJncJncJncJncJncJncJncJocJncJncEEcJpcJqcGTcajbGIbICbGIbJhcJvcDocJwcJxcFZcJycJzcDocJAcDucDrcJBcJCcJDcIxcJEcJFcJGcJHcJIcJJcJKcJHcJLcJMcJNcJOcDAcJPcJQcJRbJCaabcEYcJUcJTcJVcCDaaaaaaaaacDQcDRcJWcJXcDRcJYcJZcKacKbciIcFccKdcKecIYbJEcKgcKhcKibIBaabaaaaaaaaaaaaaaacjIcKkcKlcKmcKncKocKpcKqcKrcKocKpcKscjIaaaaaaaaaaaaamjaabcKtcKucKucKucKucKvcKwcKxcKycKycKycKycKzaabamjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacJmcJmcJmcJmcJmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index ea8ceb93c95..4ce8554bb4c 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -36,6 +36,7 @@ #define NO_BLOOD 1 #define NO_BREATHE 2 +#define NO_DNA_RAD 4 #define RAD_ABSORB 8 #define NO_SCAN 16 #define NO_PAIN 32 @@ -43,11 +44,11 @@ #define IS_WHITELISTED 128 #define HAS_LIPS 512 #define HAS_UNDERWEAR 1024 -#define IS_SYNTHETIC 2048 -#define IS_PLANT 4096 -#define CAN_BE_FAT 8192 -#define IS_RESTRICTED 16384 -#define NO_INTORGANS 32768 +#define IS_PLANT 2048 +#define CAN_BE_FAT 4096 +#define IS_RESTRICTED 8192 +#define NO_INTORGANS 16384 +#define NO_POISON 32768 //Species Blood Flags #define BLOOD_SLIME 1 diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 4a5b588a629..0f2d499e5ba 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -51,7 +51,7 @@ #define INFECTION_LEVEL_THREE 1000 // Damage above this value must be repaired with surgery. -#define ROBOLIMB_SELF_REPAIR_CAP 30 +#define ROBOLIMB_SELF_REPAIR_CAP 60 //metal, glass, rod stacks #define MAX_STACK_AMOUNT_METAL 50 @@ -134,6 +134,11 @@ #define RESIZE_DEFAULT_SIZE 1 +//transfer_ai() defines. Main proc in ai_core.dm +#define AI_TRANS_TO_CARD 1 //Downloading AI to InteliCard. +#define AI_TRANS_FROM_CARD 2 //Uploading AI from InteliCard +#define AI_MECH_HACK 3 //Malfunctioning AI hijacking mecha + //singularity defines #define STAGE_ONE 1 #define STAGE_TWO 3 diff --git a/code/__DEFINES/mob.dm b/code/__DEFINES/mob.dm index fcb6e53c365..0080658562b 100644 --- a/code/__DEFINES/mob.dm +++ b/code/__DEFINES/mob.dm @@ -29,6 +29,8 @@ #define ORGAN_ASSISTED 4096 #define DROPLIMB_EDGE 0 +#define DROPLIMB_BLUNT 1 +#define DROPLIMB_BURN 2 #define AGE_MIN 17 //youngest a character can be #define AGE_MAX 85 //oldest a character can be diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 210e5ed891e..c69742b94c8 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -4,32 +4,16 @@ ////////////////////////// /proc/makeDatumRefLists() + //hair + init_sprite_accessory_subtypes(/datum/sprite_accessory/hair, hair_styles_list, hair_styles_male_list, hair_styles_female_list) + //facial hair + init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, facial_hair_styles_list, facial_hair_styles_male_list, facial_hair_styles_female_list) + //underwear + init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, underwear_list, underwear_m, underwear_f) + //undershirt + init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, undershirt_list, undershirt_m, undershirt_f) + var/list/paths - - //Hair - Initialise all /datum/sprite_accessory/hair into an list indexed by hair-style name - paths = subtypesof(/datum/sprite_accessory/hair) - for(var/path in paths) - var/datum/sprite_accessory/hair/H = new path() - hair_styles_list[H.name] = H - switch(H.gender) - if(MALE) hair_styles_male_list += H.name - if(FEMALE) hair_styles_female_list += H.name - else - hair_styles_male_list += H.name - hair_styles_female_list += H.name - - //Facial Hair - Initialise all /datum/sprite_accessory/facial_hair into an list indexed by facialhair-style name - paths = subtypesof(/datum/sprite_accessory/facial_hair) - for(var/path in paths) - var/datum/sprite_accessory/facial_hair/H = new path() - facial_hair_styles_list[H.name] = H - switch(H.gender) - if(MALE) facial_hair_styles_male_list += H.name - if(FEMALE) facial_hair_styles_female_list += H.name - else - facial_hair_styles_male_list += H.name - facial_hair_styles_female_list += H.name - //Surgery Steps - Initialize all /datum/surgery_step into a list paths = subtypesof(/datum/surgery_step) for(var/T in paths) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 4658e6691ea..619716363f9 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -1,4 +1,16 @@ -proc/random_hair_style(gender, species = "Human") +/proc/random_underwear(var/gender) + switch(gender) + if(MALE) return pick(underwear_m) + if(FEMALE) return pick(underwear_f) + else return pick(underwear_list) + +/proc/random_undershirt(var/gender) + switch(gender) + if(MALE) return pick(undershirt_m) + if(FEMALE) return pick(undershirt_f) + else return pick(undershirt_list) + +proc/random_hair_style(var/gender, species = "Human") var/h_style = "Bald" var/list/valid_hairstyles = list() @@ -29,7 +41,7 @@ proc/random_hair_style(gender, species = "Human") if(SOUTHEAST) return NORTHWEST return 0 -proc/random_facial_hair_style(gender, species = "Human") +proc/random_facial_hair_style(var/gender, species = "Human") var/f_style = "Shaved" var/list/valid_facialhairstyles = list() @@ -136,14 +148,14 @@ proc/add_logs(mob/target, mob/user, what_done, var/object=null, var/addition=nul if(!user) return if(ismob(user)) - user.attack_log += text("\[[time_stamp()]\] Has [what_done] [target.name][ismob(target) ? "([target.ckey])" : ""][object ? " with [object]" : " "][addition]") + user.attack_log += text("\[[time_stamp()]\] Has [what_done] [key_name(target)][object ? " with [object]" : " "][addition]") if(ismob(target)) - target.attack_log += text("\[[time_stamp()]\] Has been [what_done] by [user.name][ismob(user) ? "([user.ckey])" : ""][object ? " with [object]" : " "][addition]") + target.attack_log += text("\[[time_stamp()]\] Has been [what_done] by [key_name(user)][object ? " with [object]" : " "][addition]") if(admin) - log_attack("[user.name][ismob(user) ? "([user.ckey])" : ""] [what_done] [target.name][ismob(target) ? "([target.ckey])" : ""][object ? " with [object]" : " "][addition]") + log_attack("[key_name(user)] [what_done] [key_name(target)][object ? " with [object]" : " "][addition]") if(target.client) if(what_done in ignore) return if(target == user)return if(!admin) return - msg_admin_attack("[user.name][ismob(user) ? "([user.ckey])" : ""][isAntag(user) ? "(ANTAG)" : ""] [what_done] [target.name][ismob(target) ? "([target.ckey])" : ""][object ? " with [object]" : " "][addition](JMP)") + msg_admin_attack("[key_name_admin(user)] [what_done] [key_name_admin(target)][object ? " with [object]" : " "][addition]") diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm index 4b521f9bfbb..1be69032cf1 100644 --- a/code/__HELPERS/sanitize_values.dm +++ b/code/__HELPERS/sanitize_values.dm @@ -14,7 +14,7 @@ /proc/sanitize_inlist(value, list/List, default) if(value in List) return value if(default) return default - if(List && List.len)return List[1] + if(List && List.len)return pick(List) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 3d4cfae622c..bdeac1a9565 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -18,6 +18,9 @@ var/sqltext = dbcon.Quote(t); return copytext(sqltext, 2, lentext(sqltext));//Quote() adds quotes around input, we already do that +/proc/format_table_name(table as text) + return sqlfdbktableprefix + table + /* * Text sanitization */ diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index e5219516f27..c24e749cbb4 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -605,55 +605,13 @@ Turf and target are seperate in case you want to teleport some distance from a t return M if(M < 0) return -M - - -/proc/key_name(var/whom, var/include_link = null, var/include_name = 1, var/type = null) - var/mob/M - var/client/C - var/key - - if(!whom) return "*null*" - if(istype(whom, /client)) - C = whom - M = C.mob - key = C.key - else if(ismob(whom)) - M = whom - C = M.client - key = M.key - else if(istype(whom, /datum)) - var/datum/D = whom - return "*invalid:[D.type]*" - else - return "*invalid*" - - . = "" - - if(key) - if(include_link && C) - . += "" - - if(C && C.holder && C.holder.fakekey && !include_name) - . += "Administrator" - else - . += key - - if(include_link) - if(C) . += "" - else . += " (DC)" - else - . += "*no key*" - - if(include_name && M) - if(M.real_name) - . += "/([M.real_name])" - else if(M.name) - . += "/([M.name])" - - return . - -/proc/key_name_admin(var/whom, var/include_name = 1) - return key_name(whom, 1, include_name) + +/proc/get_mob_by_ckey(key) + if(!key) + return + for(var/mob/M in mob_list) + if(M.ckey == key) + return M // Returns the atom sitting on the turf. // For example, using this on a disk, which is in a bag, on a mob, will return the mob because it's on the turf. @@ -859,7 +817,7 @@ proc/anim(turf/location as turf,target as mob|obj,a_icon,a_icon_state as text,fl /proc/hasvar(var/datum/A, var/varname) if(A.vars.Find(lowertext(varname))) return 1 else return 0 - + //Returns: all the areas in the world /proc/return_areas() var/list/area/areas = list() @@ -869,8 +827,8 @@ proc/anim(turf/location as turf,target as mob|obj,a_icon,a_icon_state as text,fl //Returns: all the areas in the world, sorted. /proc/return_sorted_areas() - return sortAtom(return_areas()) - + return sortAtom(return_areas()) + //Takes: Area type as text string or as typepath OR an instance of the area. //Returns: A list of all areas of that type in the world. /proc/get_areas(var/areatype) diff --git a/code/_globalvars/database.dm b/code/_globalvars/database.dm index 437f479f99c..987b31b9ff7 100644 --- a/code/_globalvars/database.dm +++ b/code/_globalvars/database.dm @@ -9,6 +9,7 @@ var/sqlpass = "example" var/sqlfdbkdb = "paradise" var/sqlfdbklogin = "root" var/sqlfdbkpass = "example" +var/sqlfdbktableprefix = "erro_" //backwords compatibility with downstream server hosts var/sqllogging = 0 // Should we log deaths, population stats, etc? diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 8ec230cc13b..882331d21de 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -8,12 +8,13 @@ var/global/list/facial_hair_styles_male_list = list() var/global/list/facial_hair_styles_female_list = list() var/global/list/skin_styles_female_list = list() //unused //Underwear -var/global/list/underwear_m = list("White", "Grey", "Green", "Blue", "Black", "Mankini", "None") -var/global/list/underwear_f = list("Red", "White", "Yellow", "Blue", "Black", "Thong", "None") -var/global/list/underwear_list = underwear_m + underwear_f - //undershirt -var/global/list/undershirt_t = list("White Shirt", "White Tank top", "Black shirt", "Black Tank top", "Grey Shirt", "Grey tank top", "Lover Shirt", "Blue Ian Shirt", "UK Shirt","I Love NT Shirt", "Peace Shirt", "Band Shirt", "PogoMan Shirt", "Matroska Shirt", "White Short-sleeved shirt", "Purple Short-sleeved shirt", "Blue Short-sleeved shirt", "Green Short-sleeved shirt", "Black Short-Sleeved shirt", "Blue T-Shirt", "Red T-Shirt", "Yellow T-Shirt", "Green T-Shirt", "Blue Polo Shirt", "Red Polo Shirt", "White Polo Shirt", "Gray-Yellow Polo Shirt", "Green Sports Shirt", "Red Sports Shirt", "Blue Sports Shirt", "SS13 Shirt", "Fire Tank Top", "Question Shirt", "Skull Shirt", "Commie Shirt", "Nanotrasen Shirt", "Striped Shirt", "Blue Shirt", "Red Shirt", "Green Shirt", "Meat Shirt", "Tie-Dye Shirt", "Red Jersey", "Blue Jersey", "None") -var/global/list/undershirt_list = undershirt_t +var/global/list/underwear_list = list() //stores /datum/sprite_accessory/underwear indexed by name +var/global/list/underwear_m = list() //stores only underwear name +var/global/list/underwear_f = list() //stores only underwear name + //Undershirts +var/global/list/undershirt_list = list() //stores /datum/sprite_accessory/undershirt indexed by name +var/global/list/undershirt_m = list() //stores only undershirt name +var/global/list/undershirt_f = list() //stores only undershirt name //Backpacks var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt") diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index b2ddadd7404..9d2e9fc5c89 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -8,6 +8,7 @@ var/global/list/whitelisted_species = list() var/list/clients = list() //list of all clients var/list/admins = list() //list of all clients whom are admins +var/list/deadmins = list() //list of all clients who have used the de-admin verb. var/list/directory = list() //list of all ckeys with associated client //Since it didn't really belong in any other category, I'm putting this here diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 8c419cc35fb..690ac0e5c5b 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -17,6 +17,6 @@ var/global/list/table_recipes = list() //list of all table craft recipes var/global/list/all_areas = list() var/global/list/machines = list() -var/global/list/processing_power_items = list() - //items that ask to be called every cycle +var/global/list/processing_power_items = list() //items that ask to be called every cycle +var/global/list/rcd_list = list() //list of Rapid Construction Devices. diff --git a/code/_globalvars/mapping.dm b/code/_globalvars/mapping.dm index 5d40a7c9772..1810bff0b47 100644 --- a/code/_globalvars/mapping.dm +++ b/code/_globalvars/mapping.dm @@ -51,5 +51,5 @@ var/list/blobstart = list() var/list/ninjastart = list() var/list/carplist = list() //list of all carp-spawn landmarks - //away missions -var/list/awaydestinations = list() //a list of landmarks that the warpgate can take you to \ No newline at end of file +//away missions +var/list/awaydestinations = list() //a list of landmarks that the warpgate can take you to diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index ca02a66a463..ed0e976c5da 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -43,6 +43,8 @@ return if(modifiers["middle"]) MiddleClickOn(A) + if(controlled_mech) //Are we piloting a mech? Placed here so the modifiers are not overridden. + controlled_mech.click_action(A, src) //Override AI normal click behavior. return if(modifiers["shift"]) ShiftClickOn(A) diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 9c586c3873e..745f747684f 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -191,6 +191,8 @@ var/mob/living/silicon/robot/r = mymob + if(!r.client) return + if(r.shown_robot_modules) //Modules display is shown r.client.screen += r.throw_icon //"store" icon diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index cd3c5878241..a958c3b4eec 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -634,6 +634,8 @@ sqlfdbklogin = value if ("feedback_password") sqlfdbkpass = value + if("feedback_tableprefix") + sqlfdbktableprefix = value if ("enable_stat_tracking") sqllogging = 1 else diff --git a/code/controllers/shuttle_controller.dm b/code/controllers/shuttle_controller.dm index 9c536931ce1..7c8a9847496 100644 --- a/code/controllers/shuttle_controller.dm +++ b/code/controllers/shuttle_controller.dm @@ -279,7 +279,7 @@ var/global/datum/shuttle_controller/shuttle_controller ) WS.announcer = "NSV Icarus" - WS.arrival_message = "Attention, [station_name()], we just tracked a large medical vessel approaching the station from the telecommunications satellite. Can't fire on them without hitting the station - prepare for visitors." + WS.arrival_message = "Attention, [station_name()], we just tracked a large medical vessel approaching the station from the telecommunications satellite. Might have wounded on board, can't destroy it - prepare for visitors." WS.departure_message = "Your guests are pulling away, [station_name()] - moving too fast for us to draw a bead on them. Looks like they're heading back to the telecommunications satellite." WS.interim = locate(/area/shuttle/derelict/ship/transit) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index e0672681da8..0553e65edfb 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -258,6 +258,10 @@ client body += "" body += "" body += "" + body += "" + body += "" + + body += "" body += "" body += "" @@ -270,7 +274,7 @@ client body += "" body += "" body += "" - body += "" + body += "" body += "" body += "" if(isobj(D)) @@ -929,7 +933,65 @@ client else H.verbs -= verb + else if(href_list["addorgan"]) + if(!check_rights(R_SPAWN)) return + var/mob/living/carbon/M = locate(href_list["addorgan"]) + if(!istype(M)) + usr << "This can only be done to instances of type /mob/living/carbon" + return + + var/new_organ = input("Please choose an organ to add.","Organ",null) as null|anything in subtypesof(/obj/item/organ)-/obj/item/organ + if(!new_organ) return + + if(!M) + usr << "Mob doesn't exist anymore" + return + + if(locate(new_organ) in M.internal_organs) + usr << "Mob already has that organ." + return + + new new_organ(M) + + + else if(href_list["remorgan"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/M = locate(href_list["remorgan"]) + if(!istype(M)) + usr << "This can only be done to instances of type /mob/living/carbon" + return + + var/obj/item/organ/rem_organ = input("Please choose an organ to remove.","Organ",null) as null|anything in M.internal_organs + + if(!M) + usr << "Mob doesn't exist anymore" + return + + if(!(locate(rem_organ) in M.internal_organs)) + usr << "Mob does not have that organ." + return + + usr << "Removed [rem_organ] from [M]." + rem_organ.removed() + qdel(rem_organ) + + else if(href_list["fix_nano"]) + if(!check_rights(R_DEBUG)) return + + var/mob/H = locate(href_list["fix_nano"]) + + if(!istype(H) || !H.client) + usr << "This can only be done on mobs with clients" + return + + nanomanager.send_resources(H.client) + + usr << "Resource files sent" + H << "Your NanoUI Resource files have been refreshed" + + log_admin("[key_name(usr)] resent the NanoUI resource files to [key_name(H)] ") else if(href_list["regenerateicons"]) if(!check_rights(0)) return diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 81cdb93fd9a..8f74d67cc62 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -142,7 +142,7 @@ datum/mind var/mob/living/carbon/human/H = current if (istype(current, /mob/living/carbon/human)) /** Impanted**/ - if(H.is_loyalty_implanted(H)) + if(H.is_loyalty_implanted()) text = "Loyalty Implant:Remove|Implanted
" else text = "Loyalty Implant:No Implant|Implant him!
" @@ -152,7 +152,7 @@ datum/mind if (ticker.mode.config_tag=="revolution") text += uppertext(text) text = "[text]: " - if (H.is_loyalty_implanted(H)) + if (H.is_loyalty_implanted()) text += "LOYAL EMPLOYEE|headrev|rev" else if (src in ticker.mode.head_revolutionaries) text = "employee|HEADREV|rev" @@ -188,7 +188,7 @@ datum/mind if (ticker.mode.config_tag=="cult") text = uppertext(text) text = "[text]: " - if (H.is_loyalty_implanted(H)) + if (H.is_loyalty_implanted()) text += "LOYAL EMPLOYEE|cultist" else if (src in ticker.mode.cult) text += "employee|CULTIST" @@ -302,7 +302,7 @@ datum/mind if (ticker.mode.config_tag=="traitor" || ticker.mode.config_tag=="traitorchan") text = uppertext(text) text = "[text]: " - if (H.is_loyalty_implanted(H)) + if (H.is_loyalty_implanted()) text +="traitor|LOYAL EMPLOYEE" else if (src in ticker.mode.traitors) diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 7df1764a2a9..2a4a3d3a14b 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -141,7 +141,7 @@ var/list/uplink_items = list() /datum/uplink_item/jobspecific/syndidonk name = "Syndicate Donk Pockets" - desc = "A box of highly specialized donk pockets with a number of regenerative and stimulating chemicals inside of them; the box comes equipped with a self-heating mechanism." + desc = "A box of highly specialized Donk pockets with a number of regenerative and stimulating chemicals inside of them; the box comes equipped with a self-heating mechanism." reference = "SDP" item = /obj/item/weapon/storage/box/syndidonkpockets cost = 2 @@ -162,7 +162,7 @@ var/list/uplink_items = list() /datum/uplink_item/jobspecific/rad_laser name = "Radiation Laser" - desc = "A radiation laser concealed inside of a Health Analyser, After a moderate delay, causes temporary collapse and radiation. Has adjustable controls, but will not function as a regular health analyser, only appears like one. May not function correctly on radiation resistant humanoids!" + desc = "A radiation laser concealed inside of a Health Analyser. After a moderate delay, causes temporary collapse and radiation. Has adjustable controls, but will not function as a regular health analyser, only appears like one. May not function correctly on radiation resistant humanoids!" reference = "RL" item = /obj/item/device/rad_laser cost = 6 @@ -270,7 +270,7 @@ var/list/uplink_items = list() /datum/uplink_item/dangerous/car name = "C-90gl Compact Assault Rifle" - desc = "A fully-loaded Zashchita Industriya toploading bullpup assault rifle that uses 30-round 5.45x39mm magazines with a togglable underslung 40mm grenade launcher." + desc = "A fully-loaded Zashchita Industriya toploading bullpup assault rifle that uses 30-round 5.45x39mm magazines with a toggleable underslung 40mm grenade launcher." reference = "AR" item = /obj/item/weapon/gun/projectile/automatic/c90gl cost = 18 @@ -297,7 +297,7 @@ var/list/uplink_items = list() /datum/uplink_item/dangerous/flamethrower name = "Flamethrower" - desc = "A flamethrower, fueled by a portion of highly flammable biotoxins stolen previously from Nanotrasen stations. Make a statement by roasting the filth in their own greed. Use with caution." + desc = "A flamethrower, fuelled by a portion of highly flammable bio-toxins stolen previously from Nanotrasen stations. Make a statement by roasting the filth in their own greed. Use with caution." reference = "FT" item = /obj/item/weapon/flamethrower/full/tank cost = 11 @@ -306,7 +306,7 @@ var/list/uplink_items = list() /datum/uplink_item/dangerous/sword name = "Energy Sword" - desc = "The esword is an edged weapon with a blade of pure energy. The sword is small enough to be pocketed when inactive. Activating it produces a loud, distinctive noise." + desc = "The energy sword is an edged weapon with a blade of pure energy. The sword is small enough to be pocketed when inactive. Activating it produces a loud, distinctive noise." reference = "ES" item = /obj/item/weapon/melee/energy/sword cost = 8 @@ -329,7 +329,7 @@ var/list/uplink_items = list() /datum/uplink_item/dangerous/tabungrenades name = "Tabun Gas Grenades" - desc = "A box of four (4) grenades filled with tabun, a deadly neurotoxin. Use extreme caution when handling and be sure to vacate the premise after using; ensure communication is maintaind with team to avoid accidental gassings." + desc = "A box of four (4) grenades filled with Tabun, a deadly neurotoxin. Use extreme caution when handling and be sure to vacate the premise after using; ensure communication is maintained with team to avoid accidental gassings." reference = "TGG" item = /obj/item/weapon/storage/box/syndie_kit/tabun cost = 15 @@ -345,7 +345,7 @@ var/list/uplink_items = list() /datum/uplink_item/dangerous/syndicate_minibomb name = "Syndicate Minibomb" - desc = "The Minibomb is a grenade with a five-second fuse." + desc = "The minibomb is a grenade with a five-second fuse." reference = "SMB" item = /obj/item/weapon/grenade/syndieminibomb cost = 6 @@ -362,7 +362,7 @@ var/list/uplink_items = list() /datum/uplink_item/dangerous/mauler name = "Mauler Exosuit" - desc = "A massive and incredibly deadly Syndicate exosuit. Features long-range targetting, thrust vectoring, and deployable smoke." + desc = "A massive and incredibly deadly Syndicate exosuit. Features long-range targeting, thrust vectoring, and deployable smoke." reference = "ME" item = /obj/mecha/combat/marauder/mauler/loaded cost = 140 @@ -453,8 +453,8 @@ var/list/uplink_items = list() gamemodes = list("nuclear emergency") /datum/uplink_item/ammo/machinegun - name = "Box Magazine - 7.62×51mm" - desc = "A 50-round magazine of 7.62x51mm ammunition for use in the L6 SAW machinegun. By the time you need to use this, you'll already be on a pile of corpses." + name = "Box Magazine - 7.62x51mm" + desc = "A 50-round magazine of 7.62x51mm ammunition for use in the L6 SAW machine gun. By the time you need to use this, you'll already be on a pile of corpses." reference = "762" item = /obj/item/ammo_box/magazine/m762 cost = 12 @@ -489,8 +489,6 @@ var/list/uplink_items = list() item = /obj/item/weapon/cartridge/syndicate cost = 6 -// Commented out until a fix can be found, currently doesn't work with the PDA NanoUI and people keep wasting Telecrystals on it. -- Dave - /datum/uplink_item/stealthy_weapons/silencer name = "Universal Suppressor" desc = "Fitted for use on any small caliber weapon with a threaded barrel, this suppressor will silence the shots of the weapon for increased stealth and superior ambushing capability." @@ -528,7 +526,7 @@ var/list/uplink_items = list() /datum/uplink_item/stealthy_tools/chameleon_stamp name = "Chameleon Stamp" - desc = "A stamp that can be activated to imitate an official Nanotrasen Stamp™. The disguised stamp will work exactly like the real stamp and will allow you to forge false documents to gain access or equipment; \ + desc = "A stamp that can be activated to imitate an official Nanotrasen Stamp. The disguised stamp will work exactly like the real stamp and will allow you to forge false documents to gain access or equipment; \ it can also be used in a washing machine to forge clothing." reference = "CHST" item = /obj/item/weapon/stamp/chameleon @@ -551,14 +549,14 @@ var/list/uplink_items = list() /datum/uplink_item/stealthy_tools/voice_changer name = "Voice Changer" - desc = "A conspicuous gas mask that mimics the voice named on your identification card. When no identification is worn, the mask will render your voice unrecognizable." + desc = "A conspicuous gas mask that mimics the voice named on your identification card. When no identification is worn, the mask will render your voice unrecognisable." reference = "VC" item = /obj/item/clothing/mask/gas/voice cost = 5 /datum/uplink_item/stealthy_tools/chameleon_proj name = "Chameleon-Projector" - desc = "Projects an image across a user, disguising them as an object scanned with it, as long as they don't move the projector from their hand. The disguised user cannot run and rojectiles pass over them." + desc = "Projects an image across a user, disguising them as an object scanned with it, as long as they don't move the projector from their hand. The disguised user cannot run and projectiles pass over them." reference = "CP" item = /obj/item/device/chameleon cost = 7 @@ -594,7 +592,7 @@ var/list/uplink_items = list() /datum/uplink_item/device_tools/emag name = "Cryptographic Sequencer" - desc = "The emag is a small card that unlocks hidden functions in electronic devices, subverts intended functions and characteristically breaks security mechanisms." + desc = "The cryptographic sequencer, also known as an emag, is a small card that unlocks hidden functions in electronic devices, subverts intended functions and characteristically breaks security mechanisms." reference = "EMAG" item = /obj/item/weapon/card/emag cost = 6 @@ -609,7 +607,7 @@ var/list/uplink_items = list() /datum/uplink_item/device_tools/medkit name = "Syndicate Combat Medic Kit" - desc = "The syndicate medkit is a suspicious black and red. Included is a combat stimulant injector for rapid healing, a medical hud for quick identification of injured comrades, \ + desc = "The syndicate medkit is a suspicious black and red. Included is a combat stimulant injector for rapid healing, a medical HUD for quick identification of injured comrades, \ and other medical supplies helpful for a medical field operative." reference = "SCMK" item = /obj/item/weapon/storage/firstaid/tactical @@ -632,8 +630,8 @@ var/list/uplink_items = list() /datum/uplink_item/device_tools/hardsuit name = "Blood-red Hardsuit" - desc = "The feared suit of a syndicate nuclear agent. Features slightly better armoring. When the helmet is deployed your identity will be protected. Toggling the suit into combat mode \ - will allow you all the mobility of a loose fitting uniform without sacrificing armoring. Additionally the suit is collapsible, small enough to fit within a backpack. \ + desc = "The feared suit of a syndicate nuclear agent. Features slightly better armor. When the helmet is deployed your identity will be protected. Toggling the suit into combat mode \ + will allow you all the mobility of a loose fitting uniform without sacrificing armor. Additionally the suit is collapsible, small enough to fit within a backpack. \ Nanotrasen crewmembers are trained to report red space suit sightings, these suits in particular are known to drive employees into a panic." reference = "BRHS" item = /obj/item/weapon/storage/box/syndie_kit/hardsuit @@ -641,7 +639,7 @@ var/list/uplink_items = list() /datum/uplink_item/device_tools/thermal name = "Thermal Imaging Glasses" - desc = "These glasses are thermals disguised as engineers' optical meson scanners. They allow you to see organisms through walls by capturing the upper portion of the infrared light spectrum, emitted as heat and light by objects. Hotter objects, such as warm bodies, cybernetic organisms and artificial intelligence cores emit more of this light than cooler objects like walls and airlocks." + desc = "These glasses are thermals disguised as engineers' optical meson scanners. They allow you to see organisms through walls by capturing the upper portion of the infra-red light spectrum, emitted as heat and light by objects. Hotter objects, such as warm bodies, cybernetic organisms and artificial intelligence cores emit more of this light than cooler objects like walls and airlocks." reference = "THIG" item = /obj/item/clothing/glasses/thermal/syndi cost = 6 @@ -680,7 +678,7 @@ var/list/uplink_items = list() /datum/uplink_item/device_tools/plastic_explosives name = "Composition C-4" - desc = "C-4 is plastic explosive of the common variety Composition C. You can use it to breach walls or connect a signaler to its wiring to make it remotely detonable. It has a modifiable timer with a minimum setting of 10 seconds." + desc = "C-4 is plastic explosive of the common variety Composition C. You can use it to breach walls or connect a signaller to its wiring to make it remotely detonable. It has a modifiable timer with a minimum setting of 10 seconds." reference = "C4" item = /obj/item/weapon/c4 cost = 1 @@ -762,7 +760,7 @@ var/list/uplink_items = list() /datum/uplink_item/implants/uplink name = "Uplink Implant" - desc = "An implant injected into the body, and later activated using a bodily gesture to open an uplink with 5 telecrystals. The ability for an agent to open an uplink after their posessions have been stripped from them makes this implant excellent for escaping confinement." + desc = "An implant injected into the body, and later activated using a bodily gesture to open an uplink with 5 telecrystals. The ability for an agent to open an uplink after their possessions have been stripped from them makes this implant excellent for escaping confinement." reference = "UI" item = /obj/item/weapon/implanter/uplink cost = 14 diff --git a/code/datums/wires/nuclearbomb.dm b/code/datums/wires/nuclearbomb.dm new file mode 100644 index 00000000000..0e28c23fb91 --- /dev/null +++ b/code/datums/wires/nuclearbomb.dm @@ -0,0 +1,64 @@ +/datum/wires/nuclearbomb + holder_type = /obj/machinery/nuclearbomb + random = 1 + wire_count = 7 + +var/const/NUCLEARBOMB_WIRE_LIGHT = 1 +var/const/NUCLEARBOMB_WIRE_TIMING = 2 +var/const/NUCLEARBOMB_WIRE_SAFETY = 4 + +/datum/wires/nuclearbomb/CanUse(var/mob/living/L) + var/obj/machinery/nuclearbomb/N = holder + if(N.panel_open) + return 1 + return 0 + +/datum/wires/nuclearbomb/GetInteractWindow() + var/obj/machinery/nuclearbomb/N = holder + . += ..() + . += "
The device is [N.timing ? "shaking!" : "still."]
" + . += "The device is is [N.safety ? "quiet" : "whirring"].
" + . += "The lights are [N.lighthack ? "static" : "functional"].
" + +/datum/wires/nuclearbomb/UpdatePulsed(var/index) + var/obj/machinery/nuclearbomb/N = holder + switch(index) + if(NUCLEARBOMB_WIRE_LIGHT) + N.lighthack = !N.lighthack + spawn(100) + N.lighthack = !N.lighthack + if(NUCLEARBOMB_WIRE_TIMING) + if(N.timing) + spawn + message_admins("[key_name_admin(usr)] pulsed a nuclear bomb's detonation wire, causing it to explode (JMP)") + N.explode() + if(NUCLEARBOMB_WIRE_SAFETY) + N.safety = !N.safety + spawn(100) + N.safety = !N.safety + if(N.safety == 1) + if(!N.is_syndicate) + set_security_level(N.previous_level) + N.visible_message("\blue The [N] quiets down.") + if(!N.lighthack) + if (N.icon_state == "nuclearbomb2") + N.icon_state = "nuclearbomb1" + else + N.visible_message("\blue The [N] emits a quiet whirling noise!") + +/datum/wires/nuclearbomb/UpdateCut(var/index, var/mended) + var/obj/machinery/nuclearbomb/N = holder + switch(index) + if(NUCLEARBOMB_WIRE_SAFETY) + if(N.timing) + spawn + message_admins("[key_name_admin(usr)] cut a nuclear bomb's timing wire, causing it to explode (JMP)") + N.explode() + if(NUCLEARBOMB_WIRE_TIMING) + if(!N.lighthack) + if (N.icon_state == "nuclearbomb2") + N.icon_state = "nuclearbomb1" + N.timing = 0 + bomb_set = 0 + if(NUCLEARBOMB_WIRE_LIGHT) + N.lighthack = !N.lighthack diff --git a/code/defines/procs/admin.dm b/code/defines/procs/admin.dm index 44d79a38930..c01a18fccbe 100644 --- a/code/defines/procs/admin.dm +++ b/code/defines/procs/admin.dm @@ -1,7 +1,57 @@ -proc/log_and_message_admins(var/message as text) +/proc/key_name(var/whom, var/include_link = null, var/include_name = 1, var/type = null) + var/mob/M + var/client/C + var/key + + if(!whom) return "*null*" + if(istype(whom, /client)) + C = whom + M = C.mob + key = C.key + else if(ismob(whom)) + M = whom + C = M.client + key = M.key + else if(istype(whom, /datum)) + var/datum/D = whom + return "*invalid:[D.type]*" + else + return "*invalid*" + + . = "" + + if(key) + if(include_link && C) + . += "" + + if(C && C.holder && C.holder.fakekey && !include_name) + . += "Administrator" + else + . += key + + if(include_link) + if(C) . += "" + else . += " (DC)" + else + . += "*no key*" + + if(include_name && M) + if(M.real_name) + . += "/([M.real_name])" + else if(M.name) + . += "/([M.name])" + + return . + +/proc/key_name_admin(var/whom, var/include_name = 1) + var/message = "[key_name(whom, 1, include_name)](?)[isAntag(whom) ? "(A)" : ""] ([admin_jump_link(whom, "holder")])" + return message + +/proc/log_and_message_admins(var/message as text) log_admin("[usr]([usr.ckey]) " + message) message_admins("[usr]([usr.ckey]) " + message) -proc/admin_log_and_message_admins(var/message as text) +/proc/admin_log_and_message_admins(var/message as text) log_admin("[key_name(usr)] " + message) - message_admins("[key_name_admin(usr)] " + message, 1) \ No newline at end of file + message_admins("[key_name_admin(usr)] " + message, 1) + \ No newline at end of file diff --git a/code/defines/procs/announce.dm b/code/defines/procs/announce.dm index 1211f9e14f8..34822d2d509 100644 --- a/code/defines/procs/announce.dm +++ b/code/defines/procs/announce.dm @@ -1,3 +1,4 @@ +/var/datum/announcement/minor/minor_announcement = new() /var/datum/announcement/priority/priority_announcement = new(do_log = 0) /var/datum/announcement/priority/command/command_announcement = new(do_log = 0, do_newscast = 1) @@ -15,6 +16,11 @@ sound = new_sound log = do_log newscast = do_newscast + +/datum/announcement/minor/New(var/do_log = 0, var/new_sound = sound('sound/misc/notice2.ogg'), var/do_newscast = 0) + ..(do_log, new_sound, do_newscast) + title = "Attention" + announcement_type = "Minor Announcement" /datum/announcement/priority/New(var/do_log = 1, var/new_sound = sound('sound/misc/notice2.ogg'), var/do_newscast = 0) ..(do_log, new_sound, do_newscast) @@ -55,8 +61,9 @@ datum/announcement/proc/Message(message as text, message_title as text) if (announcer) M << " -[html_encode(announcer)]" -datum/announcement/minor/Message(message as text, message_title as text) - world << "[message]" +/datum/announcement/minor/Message(message as text, message_title as text) + world << "[message_title]" + world << "[message]" datum/announcement/priority/Message(message as text, message_title as text) world << "

[message_title]

" diff --git a/code/defines/procs/statistics.dm b/code/defines/procs/statistics.dm index 91d065e5279..52c0af1af82 100644 --- a/code/defines/procs/statistics.dm +++ b/code/defines/procs/statistics.dm @@ -140,7 +140,7 @@ proc/sql_commit_feedback() log_game("SQL ERROR during feedback reporting. Failed to connect.") else - var/DBQuery/max_query = dbcon.NewQuery("SELECT MAX(roundid) AS max_round_id FROM erro_feedback") + var/DBQuery/max_query = dbcon.NewQuery("SELECT MAX(roundid) AS max_round_id FROM [format_table_name("feedback")]") max_query.Execute() var/newroundid @@ -160,7 +160,7 @@ proc/sql_commit_feedback() var/variable = item.get_variable() var/value = item.get_value() - var/DBQuery/query = dbcon.NewQuery("INSERT INTO erro_feedback (id, roundid, time, variable, value) VALUES (null, [newroundid], Now(), '[variable]', '[value]')") + var/DBQuery/query = dbcon.NewQuery("INSERT INTO [format_table_name("feedback")] (id, roundid, time, variable, value) VALUES (null, [newroundid], Now(), '[variable]', '[value]')") if(!query.Execute()) var/err = query.ErrorMsg() log_game("SQL ERROR during death reporting. Error : \[[err]\]\n") \ No newline at end of file diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 58a2fe59002..098ae32e538 100644 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -54,14 +54,12 @@ NOTE: there are two lists of areas in the end of this file: centcom and station var/air_doors_activated = 0 var/tele_proof = 0 - + /*Adding a wizard area teleport list because motherfucking lag -- Urist*/ /*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/ var/list/teleportlocs = list() - -/hook/startup/proc/setupTeleportLocs() +/hook/startup/proc/process_teleport_locs() for(var/area/AR in world) - if(istype(AR, /area/shuttle) || istype(AR, /area/syndicate_station) || istype(AR, /area/wizard_station)) continue if(teleportlocs.Find(AR.name)) continue var/list/turfs = get_area_turfs(AR.type) if(turfs.len) @@ -73,21 +71,15 @@ var/list/teleportlocs = list() teleportlocs = sortAssoc(teleportlocs) return 1 - + var/list/ghostteleportlocs = list() - -/hook/startup/proc/setupGhostTeleportLocs() +/hook/startup/proc/process_ghost_teleport_locs() for(var/area/AR in world) if(ghostteleportlocs.Find(AR.name)) continue - if(istype(AR, /area/tdome)) - ghostteleportlocs += AR.name - ghostteleportlocs[AR.name] = AR var/list/turfs = get_area_turfs(AR.type) if(turfs.len) - var/turf/picked = pick(turfs) - if ((picked.z in config.player_levels)) - ghostteleportlocs += AR.name - ghostteleportlocs[AR.name] = AR + ghostteleportlocs += AR.name + ghostteleportlocs[AR.name] = AR ghostteleportlocs = sortAssoc(ghostteleportlocs) diff --git a/code/game/asteroid.dm b/code/game/asteroid.dm index 88ff95833ad..3753c888912 100644 --- a/code/game/asteroid.dm +++ b/code/game/asteroid.dm @@ -97,7 +97,7 @@ var/global/max_secret_rooms = 6 theme = "xenoden" walltypes = list(/turf/simulated/mineral/random/high_chance=1) floortypes = list(/turf/simulated/floor/plating/airless/asteroid, /turf/simulated/floor/beach/sand) - treasureitems = list(/obj/item/clothing/mask/facehugger=1) + treasureitems = list(/obj/item/clothing/mask/facehugger=1,/obj/item/stack/sheet/animalhide/xeno=2,/obj/item/clothing/suit/xenos=2,/obj/item/clothing/head/xenos=2) fluffitems = list(/obj/effect/decal/remains/human=1,/obj/effect/decal/cleanable/blood/xeno=5) if("hitech") diff --git a/code/game/dna/dna.dm b/code/game/dna/dna.dm index 2835a1614ed..716d563a6e7 100644 --- a/code/game/dna/dna.dm +++ b/code/game/dna/dna.dm @@ -74,7 +74,7 @@ //Hair var/hair = 0 if(!character.h_style) - character.h_style = "Bald" + character.h_style = random_hair_style(character.gender) var/hrange = round(4095 / hair_styles_list.len) var/index = hair_styles_list.Find(character.h_style) @@ -84,7 +84,7 @@ //Facial Hair var/beard = 0 if(!character.f_style) - character.f_style = "Shaved" + character.f_style = random_facial_hair_style(character.gender) var/f_hrange = round(4095 / facial_hair_styles_list.len) index = facial_hair_styles_list.Find(character.f_style) diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm index 545e65b691d..745af66ac15 100644 --- a/code/game/dna/dna2_domutcheck.dm +++ b/code/game/dna/dna2_domutcheck.dm @@ -52,7 +52,7 @@ /proc/genemutcheck(var/mob/living/M, var/block, var/connected=null, var/flags=0) if(ishuman(M)) // Would've done this via species instead of type, but the basic mob doesn't have a species, go figure. var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) + if(H.species.flags & NO_DNA_RAD) return if(!M) return diff --git a/code/game/dna/genes/goon_disabilities.dm b/code/game/dna/genes/goon_disabilities.dm index db34ccbdbbb..7ea73a79ddd 100644 --- a/code/game/dna/genes/goon_disabilities.dm +++ b/code/game/dna/genes/goon_disabilities.dm @@ -335,8 +335,8 @@ var/mob/living/carbon/L = usr if(L) - usr.attack_log += text("\[[time_stamp()]\] [usr.real_name] ([usr.ckey]) cast the spell [name] on [L.real_name] ([L.ckey]).") - msg_admin_attack("[usr.real_name] ([usr.ckey])[isAntag(usr) ? "(ANTAG)" : ""] has cast the spell [name] on [L.real_name] ([L.ckey]) (JMP)") + usr.attack_log += text("\[[time_stamp()]\] [key_name(usr)] cast the spell [name] on [key_name(L)]") + msg_admin_attack("[key_name_admin(usr)] has cast the spell [name] on [key_name_admin(L)]") L.adjust_fire_stacks(0.5) L.visible_message("\red [L.name] suddenly bursts into flames!") diff --git a/code/game/dna/genes/goon_powers.dm b/code/game/dna/genes/goon_powers.dm index 452a8cd6c8d..06a16390fa7 100644 --- a/code/game/dna/genes/goon_powers.dm +++ b/code/game/dna/genes/goon_powers.dm @@ -169,13 +169,13 @@ if(H.internal) H.visible_message("\red [usr] sprays a cloud of fine ice crystals, engulfing [H]!", "[usr] sprays a cloud of fine ice crystals over your [H.head]'s visor.") - log_admin("[ckey(usr.key)] has used cryokinesis on [ckey(C.key)], internals yes, suit yes") - msg_admin_attack("[usr.real_name] ([usr.ckey])[isAntag(usr) ? "(ANTAG)" : ""] has cast cryokinesis on [C.real_name] ([C.ckey]), (JMP)") + log_admin("[key_name(usr)] has used cryokinesis on [key_name(C)] while wearing internals and a suit") + msg_admin_attack("[key_name_admin(usr)] has cast cryokinesis on [key_name_admin(C)]") else H.visible_message("\red [usr] sprays a cloud of fine ice crystals engulfing, [H]!", "[usr] sprays a cloud of fine ice crystals cover your [H.head]'s visor and make it into your air vents!.") - log_admin("[usr.real_name] ([ckey(usr.key)]) has used cryokinesis on [C.real_name] ([ckey(C.key)]), ()") - msg_admin_attack("[usr.real_name] ([usr.ckey])[isAntag(usr) ? "(ANTAG)" : ""] has cast cryokinesis on [C.real_name] ([C.ckey]), (JMP)") + log_admin("[key_name(usr)] has used cryokinesis on [key_name(C)]") + msg_admin_attack("[key_name_admin(usr)] has cast cryokinesis on [key_name_admin(C)]") H.bodytemperature = max(0, H.bodytemperature - 50) H.adjustFireLoss(5) if(!handle_suit) @@ -184,8 +184,8 @@ C.ExtinguishMob() C.visible_message("\red [usr] sprays a cloud of fine ice crystals, engulfing [C]!") - log_admin("[ckey(usr.key)] has used cryokinesis on [ckey(C.key)], internals no, suit no") - msg_admin_attack("[usr.real_name] ([usr.ckey])[isAntag(usr) ? "(ANTAG)" : ""] has cast cryokinesis on [C.real_name] ([C.ckey]), (JMP)") + log_admin("[key_name(usr)] has used cryokinesis on [key_name(C)] without internals or a suit") + msg_admin_attack("[key_name_admin(usr)] has cast cryokinesis on [key_name_admin(C)]") //playsound(usr.loc, 'bamf.ogg', 50, 0) diff --git a/code/game/dna/genes/vg_powers.dm b/code/game/dna/genes/vg_powers.dm index 1495d5b50ae..497e69bc10c 100644 --- a/code/game/dna/genes/vg_powers.dm +++ b/code/game/dna/genes/vg_powers.dm @@ -82,7 +82,7 @@ Obviously, requires DNA2. M.update_mutations() //update our mutation overlays M.update_body() //M.say(pick("",";")+pick("HULK MAD","YOU MADE HULK ANGRY")) // Just a note to security. - message_admins("[key_name(usr)] has hulked out! ([formatJumpTo(usr)])") + message_admins("[key_name_admin(usr)] has hulked out! ([formatJumpTo(usr)])") return */ @@ -224,8 +224,7 @@ Obviously, requires DNA2. var/list/validtargets = new /list() for(var/mob/M in living_mob_list) if(M && M.mind) - var/special_role = M.mind.special_role - if (special_role == "Wizard" || special_role == "Ninja" || special_role == "Syndicate" || special_role == "Syndicate Commando" || special_role == "Vox Raider" || special_role == "Alien") + if(M.z != user.z || isNonCrewAntag(M)) continue validtargets += M @@ -244,15 +243,14 @@ Obviously, requires DNA2. var/say = strip_html(input("What do you wish to say")) for(var/mob/living/target in targets) + log_say("Project Mind: [key_name(usr)]->[key_name(target)]: [say]") if(REMOTE_TALK in target.mutations) target.show_message("\blue You hear [usr.real_name]'s voice: [say]") else target.show_message("\blue You hear a voice that seems to echo around the room: [say]") usr.show_message("\blue You project your mind into [target.real_name]: [say]") for(var/mob/dead/observer/G in player_list) - G.show_message("Telepathic message from [usr] to [target]: [say]") - - + G.show_message("Telepathic message from [usr] ([ghost_follow_link(usr, ghost=G)]) to [target] ([ghost_follow_link(target, ghost=G)]): [say]") /datum/dna/gene/basic/grant_spell/remoteview name="Remote Viewing" @@ -279,17 +277,22 @@ Obviously, requires DNA2. action_icon_state = "genetic_view" -/obj/effect/proc_holder/spell/targeted/remoteview/choose_targets(mob/user = usr) +/obj/effect/proc_holder/spell/targeted/remoteview/choose_targets(mob/user = usr) var/list/targets = living_mob_list - var/list/remoteviewers = new /list() + var/list/validtargets = new /list() for(var/mob/M in targets) - if(REMOTE_VIEW in M.mutations) - remoteviewers += M - if(!remoteviewers.len || remoteviewers.len == 1) + if(M && M.mind) + if(M.z != user.z || isNonCrewAntag(M)) + continue + + validtargets += M + + if(!validtargets.len || validtargets.len == 1) usr << "No valid targets with remote view were found!" start_recharge() return - targets += input("Choose the target to spy on.", "Targeting") as mob in remoteviewers + + targets += input("Choose the target to spy on.", "Targeting") as mob in validtargets perform(targets) diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm index 5329c966b92..7a87a77c7a1 100644 --- a/code/game/gamemodes/blob/blob.dm +++ b/code/game/gamemodes/blob/blob.dm @@ -125,13 +125,13 @@ var/list/blob_nodes = list() if(location.z != ZLEVEL_STATION || istype(location, /turf/space)) if(!warned) C << "You feel ready to burst, but this isn't an appropriate place! You must return to the station!" - message_admins("[key_name(C)] was in space when the blobs burst, and will die if he doesn't return to the station.") + message_admins("[key_name_admin(C)] was in space when the blobs burst, and will die if he doesn't return to the station.") spawn(300) burst_blob(blob, 1) else burst ++ log_admin("[key_name(C)] was in space when attempting to burst as a blob.") - message_admins("[key_name(C)] was in space when attempting to burst as a blob.") + message_admins("[key_name_admin(C)] was in space when attempting to burst as a blob.") C.gib() make_blobs(1) check_finished() //Still needed in case we can't make any blobs diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index ab0a7b5a464..2687a886e7d 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -296,10 +296,10 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" user << "DNA of [target] is ruined beyond usability!" return - if(T.species.flags & IS_SYNTHETIC) + if(T.species.flags & NO_DNA_RAD) user << "This creature does not have DNA!" - return - + return + if(T.species.flags & NO_SCAN) user << "We do not know how to parse this creature's DNA!" return diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm index 3fc888f8cac..8e4313b92b0 100644 --- a/code/game/gamemodes/changeling/powers/revive.dm +++ b/code/game/gamemodes/changeling/powers/revive.dm @@ -28,6 +28,7 @@ user.germ_level = 0 user.next_pain_time = 0 user.traumatic_shock = 0 + user.timeofdeath = 0 if(ishuman(user)) var/mob/living/carbon/human/H = user H.restore_blood() diff --git a/code/game/gamemodes/changeling/powers/swap_form.dm b/code/game/gamemodes/changeling/powers/swap_form.dm index 4b5646dc237..ffbadfab21c 100644 --- a/code/game/gamemodes/changeling/powers/swap_form.dm +++ b/code/game/gamemodes/changeling/powers/swap_form.dm @@ -17,7 +17,7 @@ if((NOCLONE || SKELETON || HUSK) in target.mutations) user << "DNA of [target] is ruined beyond usability!" return - if(!istype(target) || issmall(target) || target.species.flags & IS_SYNTHETIC || target.species.flags & NO_SCAN || target.species.flags & NO_BLOOD) + if(!istype(target) || issmall(target) || target.species.flags & NO_DNA_RAD || target.species.flags & NO_SCAN || target.species.flags & NO_BLOOD) user << "[target] is not compatible with this ability." return return 1 diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm index b772cfca49a..bc21b6d7ebc 100644 --- a/code/game/gamemodes/changeling/powers/tiny_prick.dm +++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm @@ -34,7 +34,7 @@ return if(ishuman(target)) var/mob/living/carbon/human/H = target - if(H.species.flags & IS_SYNTHETIC) + if(H.isSynthetic()) user << "This won't work on synthetics." return if(!isturf(user.loc)) diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 93f2c468aa6..50819be8c1d 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -16,6 +16,8 @@ return 0 if(iscultist(mind.current)) return 1 //If they're already in the cult, assume they are convertable + if(jobban_isbanned(mind.current, "cultist") || jobban_isbanned(mind.current, "Syndicate")) + return 0 if(ishuman(mind.current) && (mind.assigned_role in list("Captain", "Chaplain"))) return 0 if(ishuman(mind.current)) diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index 98451fe2ee7..f58a93b931f 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -330,9 +330,9 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology", attack(mob/living/M as mob, mob/living/user as mob) - M.attack_log += text("\[[time_stamp()]\] Has had the [name] used on him by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used [name] on [M.name] ([M.ckey])") - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] used [name] on [M.name] ([M.ckey]) (JMP)") + M.attack_log += text("\[[time_stamp()]\] Has had the [name] used on him by [key_name(user)]") + user.attack_log += text("\[[time_stamp()]\] Used [name] on [key_name(M)]") + msg_admin_attack("[key_name_admin(user)] used [name] on [key_name_admin(M)]") if(!iscarbon(M)) M.LAssailant = null else diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index d6343e88142..3b7ca6d5b0e 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -111,7 +111,7 @@ var/list/sacrificed = list() "\red AAAAAAHHHH!.", \ "\red You hear an anguished scream.") cult_log("[key_name_admin(usr)] tried to convert [key_name_admin(M)]") - if(is_convertable_to_cult(M.mind) && !jobban_isbanned(M, "cultist") && !jobban_isbanned(M,"Syndicate"))//putting jobban check here because is_convertable uses mind as argument + if(is_convertable_to_cult(M.mind)) ticker.mode.add_cultist(M.mind) M.mind.special_role = "Cultist" M << "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root." @@ -558,12 +558,16 @@ var/list/sacrificed = list() else usr.whisper("[input]") + log_say("Cult Message: [key_name(usr)]: [input]") for(var/datum/mind/H in ticker.mode.cult) if (H.current) H.current << "[cultName]: [input]" for(var/mob/spirit/spirit in spirits) spirit << "[displayName]: [input]" + + for(var/mob/dead/observer/G in player_list) + G.show_message("[displayName] ([cultName]) ([ghost_follow_link(usr, ghost=G)]): [input]") qdel(src) return 1 diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm index aaa06ccf403..87d8e4e083c 100644 --- a/code/game/gamemodes/events.dm +++ b/code/game/gamemodes/events.dm @@ -42,7 +42,7 @@ if(!(T.z in config.station_levels)) continue if(istype(H,/mob/living/carbon/human)) - if(H.species.flags & IS_SYNTHETIC) + if(H.species.flags & NO_DNA_RAD) return H.apply_effect((rand(15,75)),IRRADIATE,0) if (prob(5)) diff --git a/code/game/gamemodes/events/holidays/Holidays.dm b/code/game/gamemodes/events/holidays/Holidays.dm index 53d6e0171f7..a4db5022f03 100644 --- a/code/game/gamemodes/events/holidays/Holidays.dm +++ b/code/game/gamemodes/events/holidays/Holidays.dm @@ -133,7 +133,7 @@ var/global/Holiday = null world.update_status() Holiday_Game_Start() - message_admins("\blue ADMIN: Event: [key_name(src)] force-set Holiday to \"[Holiday]\"") + message_admins("\blue ADMIN: Event: [key_name_admin(src)] force-set Holiday to \"[Holiday]\"") log_admin("[key_name(src)] force-set Holiday to \"[Holiday]\"") diff --git a/code/game/gamemodes/events/holidays/Other.dm b/code/game/gamemodes/events/holidays/Other.dm deleted file mode 100644 index 74b47506aaf..00000000000 --- a/code/game/gamemodes/events/holidays/Other.dm +++ /dev/null @@ -1,10 +0,0 @@ -/proc/GameOver() - if(!hadevent) - hadevent = 1 - message_admins("The apocalypse has begun! (this holiday event can be disabled by toggling events off within 60 seconds)") - spawn(600) - if(!config.allow_random_events) return - Show2Group4Delay(ScreenText(null,"
GAME OVER
"),null,150) - for(var/i=1,i<=4,i++) - spawn_dynamic_event() - sleep(50) \ No newline at end of file diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 8fd1c2638bc..8809476c3ed 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -129,7 +129,7 @@ msg += "You have been sent the $[pay], as agreed." else msg += "However, we were unable to send you the $[pay] you're entitled." - if(useMS) + if(useMS && P) // THIS SHOULD HAVE DONE EVERYTHING FOR ME useMS.send_pda_message("[P.owner]", "[command_name()] Payroll", msg) @@ -238,8 +238,7 @@ var/list/suspects = list() for(var/mob/living/carbon/human/man in player_list) if(man.client && man.mind) // NT relation option - var/special_role = man.mind.special_role - if (special_role == "Wizard" || special_role == "Ninja" || special_role == "Syndicate" || special_role == "Syndicate Commando" || special_role == "Vox Raider" || special_role == "Alien") + if(isNonCrewAntag(man)) continue //NT intelligence ruled out possiblity that those are too classy to pretend to be a crew. if(man.client.prefs.nanotrasen_relation == "Opposed" && prob(50) || \ man.client.prefs.nanotrasen_relation == "Skeptical" && prob(20)) @@ -247,6 +246,7 @@ // Antags else if(special_role == "traitor" && prob(40) || \ special_role == "Changeling" && prob(50) || \ + special_role == "Vampire" && prob(40) || \ special_role == "Cultist" && prob(30) || \ special_role == "Head Revolutionary" && prob(30) || \ special_role == "Shadowling" && prob(15)) @@ -474,7 +474,7 @@ proc/display_roundstart_logout_report() if(L.suiciding) //Suicider msg += "[L.name] ([L.ckey]), the [L.job] (Suicide)\n" job_master.FreeRole(L.job) - message_admins("[L.name] ([L.ckey]), the [L.job] has been freed due to (Early Round Suicide)\n") + message_admins("[key_name_admin(L)], the [L.job] has been freed due to (Early Round Suicide)\n") continue //Disconnected client if(L.stat == UNCONSCIOUS) msg += "[L.name] ([L.ckey]), the [L.job] (Dying)\n" @@ -500,7 +500,7 @@ proc/display_roundstart_logout_report() else msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Ghosted)\n" job_master.FreeRole(L.job) - message_admins("[L.name] ([L.ckey]), the [L.job] has been freed due to (Early Round Ghosted While Alive)\n") + message_admins("[key_name_admin(L)], the [L.job] has been freed due to (Early Round Ghosted While Alive)\n") continue //Ghosted while alive diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm index f32407a62af..622ec56bf4f 100644 --- a/code/game/gamemodes/malfunction/Malf_Modules.dm +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -34,7 +34,7 @@ rcd light flash thingy on matter drain /datum/AI_Module/large/fireproof_core - module_name = "Core upgrade" + module_name = "Core Upgrade" mod_pick_name = "coreup" description = "An upgrade to improve core resistance, making it immune to fire and heat. This effect is permanent." cost = 50 @@ -51,9 +51,9 @@ rcd light flash thingy on matter drain src << "Core fireproofed." /datum/AI_Module/large/upgrade_turrets - module_name = "AI Turret upgrade" + module_name = "AI Turret Upgrade" mod_pick_name = "turret" - description = "Improves the firing speed and health of all AI turrets. This effect is permanent." + description = "Improves the firing power and health of all AI turrets. This effect is permanent." cost = 50 one_time = 1 @@ -62,26 +62,25 @@ rcd light flash thingy on matter drain /mob/living/silicon/ai/proc/upgrade_turrets() set category = "Malfunction" set name = "Upgrade Turrets" + + if(stat) + return + src.verbs -= /mob/living/silicon/ai/proc/upgrade_turrets - for(var/obj/machinery/turret/turret in machines) - var/turf/T = get_turf(turret) - if(T.z in config.station_levels) - turret.health += 30 - turret.shot_delay = 20 for(var/obj/machinery/porta_turret/turret in machines) var/turf/T = get_turf(turret) if(T.z in config.station_levels) // Increase health by 37.5% of original max, decrease delays between shots to 66% turret.health += initial(turret.health) * 3 / 8 - turret.shot_delay = initial(turret.shot_delay) * 2 / 3 + turret.eprojectile = /obj/item/projectile/beam/heavylaser //Once you see it, you will know what it means to FEAR. + turret.eshot_sound = 'sound/weapons/lasercannonfire.ogg' src << "Turrets upgraded." /datum/AI_Module/large/lockdown module_name = "Hostile Station Lockdown" mod_pick_name = "lockdown" - description = "Take control of the airlock, blast door and fire control networks, locking them down. Caution! This command also electrifies all airlocks." + description = "Overload the airlock, blast door and fire control networks, locking them down. Caution! This command also electrifies all airlocks. The networks will automatically reset after 120 seconds." cost = 20 - one_time = 1 power_type = /mob/living/silicon/ai/proc/lockdown @@ -89,12 +88,43 @@ rcd light flash thingy on matter drain set category = "Malfunction" set name = "Initiate Hostile Lockdown" - if(src.stat == 2) - src <<"You cannot begin a lockdown because you are dead!" + if(stat) return + + for(var/datum/AI_Module/large/lockdown/lockdown in current_modules) + if(lockdown.uses > 0) + lockdown.uses -- + + var/obj/machinery/door/airlock/AL + for(var/obj/machinery/door/D in airlocks) + if(!(D.z in config.contact_levels)) + continue + spawn() + if(istype(D, /obj/machinery/door/airlock)) + AL = D + if(AL.canAIControl() && !AL.stat) //Must be powered and have working AI wire. + AL.locked = 0 //For airlocks that were bolted open. + AL.safe = 0 //DOOR CRUSH + AL.close() + AL.lock() + AL.electrified_until = -1 //Shock it! + else if(!D.stat) //So that only powered doors are closed. + D.close() //Close ALL the doors! - if(malf_cooldown) - return + var/obj/machinery/computer/communications/C = locate() in machines + if(C) + C.post_status("alert", "lockdown") + + minor_announcement.Announce("Hostile runtime detected in door controllers. Isolation lockdown protocols are now in effect. Please remain calm.","Network Alert") + src << "Lockdown initiated. Network reset in two minutes." + spawn(1200) //120 Seconds. + disablelockdown() //Reset the lockdown after 120 seconds. + else + src << "Out of uses." + +/mob/living/silicon/ai/proc/disablelockdown() + set category = "Malfunction" + set name = "Disable Lockdown" var/obj/machinery/door/airlock/AL for(var/obj/machinery/door/D in airlocks) @@ -104,77 +134,73 @@ rcd light flash thingy on matter drain if(istype(D, /obj/machinery/door/airlock)) AL = D if(AL.canAIControl() && !AL.stat) //Must be powered and have working AI wire. - AL.locked = 0 //For airlocks that were bolted open. - AL.safe = 0 //DOOR CRUSH - AL.close() - AL.locked = 1 //Bolt it! - AL.lights = 0 //Stealth bolt for a classic AI door trap. - AL.electrified_until = -1 //Shock it! - else if(!D.stat) //So that only powered doors are closed. - D.close() //Close ALL the doors! - - var/obj/machinery/computer/communications/C = locate() in machines - if(C) - C.post_status("alert", "lockdown") - - src.verbs += /mob/living/silicon/ai/proc/disablelockdown - src << "Lockdown Initiated." - malf_cooldown = 1 - spawn(30) - malf_cooldown = 0 - -/mob/living/silicon/ai/proc/disablelockdown() - set category = "Malfunction" - set name = "Disable Lockdown" - - if(src.stat == 2) - src <<"You cannot disable lockdown because you are dead!" - return - if(malf_cooldown) - return - - var/obj/machinery/door/airlock/AL - for(var/obj/machinery/door/D in airlocks) - spawn() - if(istype(D, /obj/machinery/door/airlock)) - AL = D - if(AL.canAIControl() && !AL.stat) //Must be powered and have working AI wire. - AL.locked = 0 + AL.unlock() AL.electrified_until = 0 AL.open() AL.safe = 1 - AL.lights = 1 //Essentially reset the airlock to normal. else if(!D.stat) //Opens only powered doors. - D.open() //Open everything! + D.open() //Open everything! + + var/obj/machinery/computer/communications/C = locate() in machines + if(C) + C.post_status("alert", "default") + + minor_announcement.Announce("Automatic system reboot complete. Have a secure day.","Network Reset") - src << "Lockdown Lifted." - malf_cooldown = 1 - spawn(30) - malf_cooldown = 0 - -/datum/AI_Module/large/disable_rcd - module_name = "RCD disable" +/datum/AI_Module/large/destroy_rcd + module_name = "Destroy RCDs" mod_pick_name = "rcd" - description = "Send a specialised pulse to break all RCD devices on the station." - cost = 50 + description = "Send a specialised pulse to detonate all hand-held and exosuit Rapid Cconstruction Devices on the station." + cost = 25 + one_time = 1 power_type = /mob/living/silicon/ai/proc/disable_rcd /mob/living/silicon/ai/proc/disable_rcd() set category = "Malfunction" - set name = "Disable RCDs" - for(var/datum/AI_Module/large/disable_rcd/rcdmod in current_modules) - if(rcdmod.uses > 0) - rcdmod.uses -- - for(var/obj/item/weapon/rcd/rcd in world) - rcd.disabled = 1 - for(var/obj/item/mecha_parts/mecha_equipment/tool/rcd/rcd in world) - rcd.disabled = 1 - src << "Out of uses." + set name = "Destroy RCDs" + set desc = "Detonate all RCDs on the station, while sparing onboard cyborg RCDs." + + if(stat || malf_cooldown) + return + + for(var/obj/item/RCD in rcd_list) + if(!istype(RCD, /obj/item/weapon/rcd/borg)) //Ensures that cyborg RCDs are spared. + RCD.audible_message("[RCD] begins to vibrate and buzz loudly!","[RCD] begins vibrating violently!") + spawn(50) //5 seconds to get rid of it! + if(RCD) //Make sure it still exists (In case of chain-reaction) + explosion(RCD, 0, 0, 3, 1, flame_range = 1) + qdel(RCD) + src << "RCD detonation pulse emitted." + malf_cooldown = 1 + spawn(100) + malf_cooldown = 0 + +/datum/AI_Module/large/mecha_domination + module_name = "Viral Mech Domination" + mod_pick_name = "mechjack" + description = "Hack into a mech's onboard computer, shunting all processes into it and ejecting any occupants. Once uploaded to the mech, it is impossible to leave.\ + Do not allow the mech to leave the station's vicinity or allow it to be destroyed." + cost = 30 + one_time = 1 + + power_type = /mob/living/silicon/ai/proc/mech_takeover + +/mob/living/silicon/ai/proc/mech_takeover() + set name = "Compile Mecha Virus" + set category = "Malfunction" + set desc = "Target a mech by clicking it. Click the appropriate command when ready." + + if(stat) + return + + can_dominate_mechs = 1 //Yep. This is all it does. Honk! + src << "Virus package compiled. Select a target mech at any time. You must remain on the station at all times. Loss of signal will result in total system lockout." + verbs -= /mob/living/silicon/ai/proc/mech_takeover + /datum/AI_Module/small/overload_machine - module_name = "Machine overload" + module_name = "Machine Overload" mod_pick_name = "overload" description = "Overloads an electrical machine, causing a small explosion. 2 uses." uses = 2 @@ -185,6 +211,10 @@ rcd light flash thingy on matter drain /mob/living/silicon/ai/proc/overload_machine(obj/machinery/M as obj in world) set name = "Overload Machine" set category = "Malfunction" + + if(stat) + return + if (istype(M, /obj/machinery)) if(istype(M,/obj/machinery/field_generator)) src << "This machine can not be overloaded due to a firewall." @@ -197,11 +227,11 @@ rcd light flash thingy on matter drain spawn(50) explosion(get_turf(M), 0,1,1,0) qdel(M) - else src << "Out of uses." + else src << "Out of uses." else src << "That's not a machine." /datum/AI_Module/small/override_machine - module_name = "Machine override" + module_name = "Machine Override" mod_pick_name = "override" description = "Overrides a machine's programming, causing it to rise up and attack everyone except other machines. 4 uses." uses = 4 @@ -213,6 +243,10 @@ rcd light flash thingy on matter drain /mob/living/silicon/ai/proc/override_machine(obj/machinery/M as obj in world) set name = "Override Machine" set category = "Malfunction" + + if(stat) + return + if (istype(M, /obj/machinery)) if(istype(M,/obj/machinery/field_generator)) src << "This machine can not be overloaded due to a firewall." @@ -226,7 +260,7 @@ rcd light flash thingy on matter drain spawn(50) if(M) new /mob/living/simple_animal/hostile/mimic/copy/machine(get_turf(M), M, src, 1) - else src << "Out of uses." + else src << "Out of uses." else src << "That's not a machine." /datum/AI_Module/large/place_cyborg_transformer @@ -246,8 +280,10 @@ rcd light flash thingy on matter drain /mob/living/silicon/ai/proc/place_transformer() set name = "Place Robotic Factory" set category = "Malfunction" + if(!canPlaceTransformer()) return + var/sure = alert(src, "Are you sure you want to place the machine here?", "Are you sure?", "Yes", "No") if(sure == "Yes") if(!canPlaceTransformer()) @@ -312,6 +348,10 @@ rcd light flash thingy on matter drain /mob/living/silicon/ai/proc/blackout() set category = "Malfunction" set name = "Blackout" + + if(stat) + return + for(var/datum/AI_Module/small/blackout/blackout in current_modules) if(blackout.uses > 0) blackout.uses -- @@ -320,72 +360,88 @@ rcd light flash thingy on matter drain apc.overload_lighting() else apc.overload++ src << "Overcurrent applied to the powernet." - else src << "Out of uses." + else src << "Out of uses." -/datum/AI_Module/small/reactivate_camera - module_name = "Reactivate camera" +/datum/AI_Module/small/reactivate_cameras + module_name = "Reactivate Camera Network" mod_pick_name = "recam" - description = "Reactivates a currently disabled camera. 5 uses." - uses = 5 - cost = 5 + description = "Runs a network-wide diagnostic on the camera network, resetting focus and re-routing power to failed cameras. Can be used to repair up to 30 cameras." + uses = 30 + cost = 10 + one_time = 1 - power_type = /client/proc/reactivate_camera + power_type = /mob/living/silicon/ai/proc/reactivate_cameras -/client/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.cameras) - set name = "Reactivate Camera" +/mob/living/silicon/ai/proc/reactivate_cameras() + set name = "Reactivate Cameranet" set category = "Malfunction" - if (istype (C, /obj/machinery/camera)) - for(var/datum/AI_Module/small/reactivate_camera/camera in usr:current_modules) + + if(stat || malf_cooldown) + return + var/fixedcams = 0 //Tells the AI how many cams it fixed. Stats are fun. + + for(var/datum/AI_Module/small/reactivate_cameras/camera in current_modules) + for(var/obj/machinery/camera/C in cameranet.cameras) + var/initial_range = initial(C.view_range) //To prevent calling the proc twice if(camera.uses > 0) if(!C.status) - C.deactivate(src) - camera.uses -- - src << "Camera reactivated." - else - src << "This camera is either active, or not repairable." - else src << "Out of uses." - else src << "That's not a camera." - -/datum/AI_Module/small/upgrade_camera - module_name = "Upgrade Camera" - mod_pick_name = "upgradecam" - description = "Upgrades a camera to have X-Ray vision, Motion and be EMP-Proof. 5 uses." - uses = 5 - cost = 5 - - power_type = /client/proc/upgrade_camera - -/client/proc/upgrade_camera(obj/machinery/camera/C as obj in cameranet.cameras) - set name = "Upgrade Camera" - set category = "Malfunction" - if(istype(C)) - var/datum/AI_Module/small/upgrade_camera/UC = locate(/datum/AI_Module/small/upgrade_camera) in usr:current_modules - if(UC) - if(UC.uses > 0) - if(C.assembly) - var/upgraded = 0 - - if(!C.isXRay()) - C.upgradeXRay() - upgraded = 1 - - if(!C.isEmpProof()) - C.upgradeEmpProof() - upgraded = 1 - - if(!C.isMotion()) - C.upgradeMotion() - upgraded = 1 - - if(upgraded) - UC.uses -- - C.visible_message("\icon[C] *beep*") - src << "Camera successully upgraded!" - else - src << "This camera is already upgraded!" + C.deactivate(src, 1) //Reactivates the camera based on status. Badly named proc. + fixedcams++ + camera.uses-- + if(C.view_range != initial_range) + C.view_range = initial_range //Fixes cameras with bad focus. + camera.uses-- + fixedcams++ + //If a camera is both deactivated and has bad focus, it will cost two uses to fully fix! else - src << "Out of uses." + src << "Out of uses." + verbs -= /mob/living/silicon/ai/proc/reactivate_cameras //It is useless now, clean it up. + break + src << "Diagnostic complete! Operations completed: [fixedcams]." + malf_cooldown = 1 + spawn(30) //Lag protection + malf_cooldown = 0 + +/datum/AI_Module/small/upgrade_cameras + module_name = "Upgrade Camera Network" + mod_pick_name = "upgradecam" + description = "Install broad-spectrum scanning and electrical redundancy firmware to the camera network, enabling EMP-Proofing and light-amplified X-ray vision." //I <3 pointless technobabble + //This used to have motion sensing as well, but testing quickly revealed that giving it to the whole cameranet is PURE HORROR. + one_time = 1 + cost = 35 //Decent price for omniscience! + + power_type = /mob/living/silicon/ai/proc/upgrade_cameras + +/mob/living/silicon/ai/proc/upgrade_cameras() + set name = "Upgrade Cameranet" + set category = "Malfunction" + + if(stat) + return + + var/upgradedcams = 0 + see_override = SEE_INVISIBLE_MINIMUM //Night-vision, without which X-ray would be very limited in power. + + for(var/obj/machinery/camera/C in cameranet.cameras) + if(C.assembly) + var/upgraded = 0 + + if(!C.isXRay()) + C.upgradeXRay() + //Update what it can see. + cameranet.updateVisibility(C, 0) + upgraded = 1 + + if(!C.isEmpProof()) + C.upgradeEmpProof() + upgraded = 1 + + if(upgraded) + upgradedcams++ + + src << "OTA firmware distribution complete! Cameras upgraded: [upgradedcams]. Light amplification system online." + verbs -= /mob/living/silicon/ai/proc/upgrade_cameras /datum/module_picker var/temp = null @@ -411,9 +467,9 @@ rcd light flash thingy on matter drain Install Module:
The number afterwards is the amount of processing time it consumes.
"} for(var/datum/AI_Module/large/module in src.possible_modules) - dat += "[module.module_name] ([module.cost])
" + dat += "[module.module_name]\[?\] ([module.cost])
" for(var/datum/AI_Module/small/module in src.possible_modules) - dat += "[module.module_name] ([module.cost])
" + dat += "[module.module_name]\[?\] ([module.cost])
" dat += "
" if (src.temp) dat += "[src.temp]" @@ -455,5 +511,9 @@ rcd light flash thingy on matter drain temp = AM.description src.processing_time -= AM.cost + if(href_list["showdesc"]) + if(AM.mod_pick_name == href_list["showdesc"]) + temp = AM.description + src.use(usr) return diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index fdca56bd5cc..e3fb3809c39 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -127,7 +127,7 @@ /datum/game_mode/malfunction/proc/capture_the_station() - world << "The AI has won!" + world << "The AI has accessed the station's core files!" world << "It has fully taken control of all of [station_name()]'s systems." to_nuke_or_not_to_nuke = 1 @@ -328,7 +328,8 @@ /datum/game_mode/proc/auto_declare_completion_malfunction() if( malf_ai.len || istype(ticker.mode,/datum/game_mode/malfunction) ) var/text = "The malfunctioning AI were:" - + var/module_text_temp = "
Purchased modules:
" //Added at the end + for(var/datum/mind/malf in malf_ai) text += "
[malf.key] was [malf.name] (" @@ -339,9 +340,13 @@ text += "operational" if(malf.current.real_name != malf.name) text += " as [malf.current.real_name]" + var/mob/living/silicon/ai/AI = malf.current + for(var/datum/AI_Module/mod in AI.current_modules) + module_text_temp += mod.module_name + "
" else text += "hardware destroyed" text += ")" - + text += module_text_temp + world << text return 1 \ No newline at end of file diff --git a/code/game/gamemodes/mutiny/mutiny.dm b/code/game/gamemodes/mutiny/mutiny.dm index ad4513e6709..a198fb21eac 100644 --- a/code/game/gamemodes/mutiny/mutiny.dm +++ b/code/game/gamemodes/mutiny/mutiny.dm @@ -329,8 +329,8 @@ datum/game_mode/mutiny if (M) src << "Attempting to recruit [M]..." - log_admin("[src]([src.ckey]) attempted to recruit [M] as a loyalist.") - message_admins("\red [src]([src.ckey]) attempted to recruit [M] as a loyalist.") + log_admin("[key_name(src)] attempted to recruit [M] as a loyalist.") + message_admins("\red [key_name_admin(src)] attempted to recruit [M] as a loyalist.") var/choice = alert(M, "Asked by [src]: Will you help me complete Directive X?", "Loyalist recruitment", "Yes", "No") if(choice == "Yes") @@ -366,8 +366,8 @@ datum/game_mode/mutiny if (M) src << "Attempting to recruit [M]..." - log_admin("[src]([src.ckey]) attempted to recruit [M] as a mutineer.") - message_admins("\red [src]([src.ckey]) attempted to recruit [M] as a mutineer.") + log_admin("[key_name(src)] attempted to recruit [M] as a mutineer.") + message_admins("\red [key_name_admin(src)] attempted to recruit [M] as a mutineer.") var/choice = alert(M, "Asked by [src]: Will you help me stop Directive X?", "Mutineer recruitment", "Yes", "No") if(choice == "Yes") diff --git a/code/game/gamemodes/mutiny/mutiny_hooks.dm b/code/game/gamemodes/mutiny/mutiny_hooks.dm index 14766e520ec..f87ab7c1919 100644 --- a/code/game/gamemodes/mutiny/mutiny_hooks.dm +++ b/code/game/gamemodes/mutiny/mutiny_hooks.dm @@ -12,7 +12,7 @@ mode.update_icon(H.mind) return 1 -/hook/harvest_podman/proc/update_icon(mob/living/carbon/primitive/diona/D) +/hook/harvest_podman/proc/update_icon(mob/living/simple_animal/diona/D) var/datum/game_mode/mutiny/mode = get_mutiny_mode() if (!mode) return 1 diff --git a/code/game/gamemodes/nations/nations.dm b/code/game/gamemodes/nations/nations.dm index 52df698a96f..9efc2e4f6f4 100644 --- a/code/game/gamemodes/nations/nations.dm +++ b/code/game/gamemodes/nations/nations.dm @@ -293,8 +293,7 @@ datum/game_mode/nations else new_character.gender = pick(MALE,FEMALE) var/datum/preferences/A = new() - A.randomize_appearance_for(new_character) - new_character.real_name = real_name + A.copy_to(new_character) if(!new_character.real_name) if(new_character.gender == MALE) @@ -428,9 +427,9 @@ datum/game_mode/nations H << "You are now part of the great sovereign nation of [H.mind.nation.name]!" return 1 else - message_admins("[H.name] with [H.mind.assigned_role] could not find any nation to assign!") + message_admins("[key_name_admin(H)] with [H.mind.assigned_role] could not find any nation to assign!") return 1 - message_admins("[H.name] latejoined with no mind.") + message_admins("[key_name_admin(H)] latejoined with no mind.") return 1 /proc/get_nations_mode() diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 741bc4769bd..0850f6ad46b 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -6,26 +6,23 @@ var/bomb_set icon = 'icons/obj/stationobjs.dmi' icon_state = "nuclearbomb0" density = 1 - var/deployable = 0.0 - var/extended = 0.0 + var/deployable = 0 + var/extended = 0 var/lighthack = 0 - var/opened = 0.0 - var/timeleft = 60.0 - var/timing = 0.0 + var/timeleft = 120 + var/timing = 0 var/r_code = "ADMIN" var/code = "" - var/yes_code = 0.0 - var/safety = 1.0 + var/yes_code = 0 + var/safety = 1 var/obj/item/weapon/disk/nuclear/auth = null - var/list/wires = list() - var/light_wire - var/safety_wire - var/timing_wire var/removal_stage = 0 // 0 is no removal, 1 is covers removed, 2 is covers open, 3 is sealant open, 4 is unwrenched, 5 is removed from bolts. var/lastentered var/is_syndicate = 0 use_power = 0 unacidable = 1 + var/previous_level = "" + var/datum/wires/nuclearbomb/wires = null /obj/machinery/nuclearbomb/syndicate is_syndicate = 1 @@ -33,68 +30,60 @@ var/bomb_set /obj/machinery/nuclearbomb/New() ..() r_code = "[rand(10000, 99999.0)]"//Creates a random code upon object spawn. - src.wires["Red"] = 0 - src.wires["Blue"] = 0 - src.wires["Green"] = 0 - src.wires["Marigold"] = 0 - src.wires["Fuschia"] = 0 - src.wires["Black"] = 0 - src.wires["Pearl"] = 0 - var/list/w = list("Red","Blue","Green","Marigold","Black","Fuschia","Pearl") - src.light_wire = pick(w) - w -= src.light_wire - src.timing_wire = pick(w) - w -= src.timing_wire - src.safety_wire = pick(w) - w -= src.safety_wire - + wires = new/datum/wires/nuclearbomb(src) + previous_level = get_security_level() + +/obj/machinery/nuclearbomb/Destroy() + qdel(wires) + return ..() + /obj/machinery/nuclearbomb/process() - if (src.timing) + if (timing) bomb_set = 1 //So long as there is one nuke timing, it means one nuke is armed. - src.timeleft-- - if (src.timeleft <= 0) - explode() - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - nanomanager.update_uis(src) + timeleft = max(timeleft - 2, 0) // 2 seconds per process() + if (timeleft <= 0) + spawn + explode() + nanomanager.update_uis(src) return /obj/machinery/nuclearbomb/attackby(obj/item/weapon/O as obj, mob/user as mob, params) if (istype(O, /obj/item/weapon/screwdriver)) - src.add_fingerprint(user) - if (src.auth) - if (src.opened == 0) - src.opened = 1 + add_fingerprint(user) + if (auth) + if (panel_open == 0) + panel_open = 1 overlays += image(icon, "npanel_open") user << "You unscrew the control panel of [src]." + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) else - src.opened = 0 + panel_open = 0 overlays -= image(icon, "npanel_open") user << "You screw the control panel of [src] back on." + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) else - if (src.opened == 0) + if (panel_open == 0) user << "[src] emits a buzzing noise, the panel staying locked in." - if (src.opened == 1) - src.opened = 0 + if (panel_open == 1) + panel_open = 0 overlays -= image(icon, "npanel_open") user << "You screw the control panel of [src] back on." + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) flick("nuclearbombc", src) - ui_interact(user) return - if (istype(O, /obj/item/device/multitool) || istype(O, /obj/item/weapon/wirecutters)) - ui_interact(user) + if (panel_open && (istype(O, /obj/item/device/multitool) || istype(O, /obj/item/weapon/wirecutters))) + return attack_hand(user) - if (src.extended) + if (extended) if (istype(O, /obj/item/weapon/disk/nuclear)) usr.drop_item() O.loc = src - src.auth = O - src.add_fingerprint(user) - ui_interact(user) - return + auth = O + add_fingerprint(user) + return attack_hand(user) - if (src.anchored) + if (anchored) switch(removal_stage) if(0) if(istype(O,/obj/item/weapon/weldingtool)) @@ -164,73 +153,56 @@ var/bomb_set ..() /obj/machinery/nuclearbomb/attack_ghost(mob/user as mob) - ui_interact(user) + attack_hand(user) /obj/machinery/nuclearbomb/attack_hand(mob/user as mob) - if (src.extended) - if (src.opened) + if (extended) + if (panel_open) + wires.Interact(user) + else ui_interact(user) - else if (src.deployable) + else if (deployable) if(removal_stage < 5) - src.anchored = 1 + anchored = 1 visible_message("\red With a steely snap, bolts slide out of [src] and anchor it to the flooring!") else visible_message("\red \The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") - if(!src.lighthack) + if(!lighthack) flick("nuclearbombc", src) - src.icon_state = "nuclearbomb1" - src.extended = 1 + icon_state = "nuclearbomb1" + extended = 1 return /obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/data[0] - var/uiwidth - var/uiheight - var/uititle data["is_syndicate"] = is_syndicate - if(!src.opened) - data["hacking"] = 0 - data["auth"] = is_auth(user) - if (is_auth(user)) - if (src.yes_code) - data["authstatus"] = src.timing ? "Functional/Set" : "Functional" - else - data["authstatus"] = "Auth. S2" + data["hacking"] = 0 + data["auth"] = is_auth(user) + if (is_auth(user)) + if (yes_code) + data["authstatus"] = timing ? "Functional/Set" : "Functional" else - if (src.timing) - data["authstatus"] = "Set" - else - data["authstatus"] = "Auth. S1" - data["safe"] = src.safety ? "Safe" : "Engaged" - data["time"] = src.timeleft - data["timer"] = src.timing - data["safety"] = src.safety - data["anchored"] = src.anchored - data["yescode"] = src.yes_code - data["message"] = "AUTH" - if (is_auth(user)) - data["message"] = src.code - if (src.yes_code) - data["message"] = "*****" - uiwidth = 300 - uiheight = 510 - uititle = "Nuke Control Panel" + data["authstatus"] = "Auth. S2" else - data["hacking"] = 1 - var/list/tempwires[0] - for(var/wire in src.wires) - tempwires.Add(list(list("name" = wire, "cut" = src.wires[wire]))) - data["wires"] = tempwires - data["timing"] = src.timing - data["safety"] = src.safety - data["lighthack"] = src.lighthack - uiwidth = 420 - uiheight = 440 - uititle = "Nuclear Bomb Defusion" + if (timing) + data["authstatus"] = "Set" + else + data["authstatus"] = "Auth. S1" + data["safe"] = safety ? "Safe" : "Engaged" + data["time"] = timeleft + data["timer"] = timing + data["safety"] = safety + data["anchored"] = anchored + data["yescode"] = yes_code + data["message"] = "AUTH" + if (is_auth(user)) + data["message"] = code + if (yes_code) + data["message"] = "*****" ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "nuclear_bomb.tmpl", uititle, uiwidth, uiheight) + ui = new(user, src, ui_key, "nuclear_bomb.tmpl", "Nuke Control Panel", 300, 510) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -243,12 +215,12 @@ var/bomb_set if(usr.stat || !usr.canmove || usr.restrained()) return - if (src.deployable) + if (deployable) usr << "\red You close several panels to make [src] undeployable." - src.deployable = 0 + deployable = 0 else usr << "\red You adjust some panels to make [src] deployable." - src.deployable = 1 + deployable = 1 return /obj/machinery/nuclearbomb/proc/is_auth(user as mob) @@ -263,71 +235,29 @@ var/bomb_set if(..()) return 1 - if(href_list["act"]) - var/temp_wire = href_list["wire"] - if(href_list["act"] == "pulse") - if (!istype(usr.get_active_hand(), /obj/item/device/multitool)) - usr << "You need a multitool!" - else - if(src.wires[temp_wire]) - usr << "You can't pulse a cut wire." - else - if(src.light_wire == temp_wire) - src.lighthack = !src.lighthack - spawn(100) src.lighthack = !src.lighthack - if(src.timing_wire == temp_wire) - if(src.timing) - explode() - if(src.safety_wire == temp_wire) - src.safety = !src.safety - spawn(100) src.safety = !src.safety - if(src.safety == 1) - visible_message("\blue The [src] quiets down.") - if(!src.lighthack) - if (src.icon_state == "nuclearbomb2") - src.icon_state = "nuclearbomb1" - else - visible_message("\blue The [src] emits a quiet whirling noise!") - if(href_list["act"] == "wire") - if (!istype(usr.get_active_hand(), /obj/item/weapon/wirecutters)) - usr << "You need wirecutters!" - else - wires[temp_wire] = !wires[temp_wire] - if(src.safety_wire == temp_wire) - if(src.timing) - explode() - if(src.timing_wire == temp_wire) - if(!src.lighthack) - if (src.icon_state == "nuclearbomb2") - src.icon_state = "nuclearbomb1" - src.timing = 0 - bomb_set = 0 - if(src.light_wire == temp_wire) - src.lighthack = !src.lighthack - if (href_list["auth"]) - if (src.auth) - src.auth.loc = src.loc - src.yes_code = 0 - src.auth = null + if (auth) + auth.loc = loc + yes_code = 0 + auth = null else var/obj/item/I = usr.get_active_hand() if (istype(I, /obj/item/weapon/disk/nuclear)) usr.drop_item() I.loc = src - src.auth = I + auth = I if (is_auth(usr)) if (href_list["type"]) if (href_list["type"] == "E") - if (src.code == src.r_code) - src.yes_code = 1 - src.code = null + if (code == r_code) + yes_code = 1 + code = null else - src.code = "ERROR" + code = "ERROR" else if (href_list["type"] == "R") - src.yes_code = 0 - src.code = null + yes_code = 0 + code = null else lastentered = text("[]", href_list["type"]) if (text2num(lastentered) == null) @@ -335,51 +265,61 @@ var/bomb_set message_admins("[key_name_admin(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered]! ([LOC ? "JMP" : "null"])", 0) log_admin("EXPLOIT: [key_name(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered]!") else - src.code += lastentered - if (length(src.code) > 5) - src.code = "ERROR" - if (src.yes_code) + code += lastentered + if (length(code) > 5) + code = "ERROR" + if (yes_code) if (href_list["time"]) var/time = text2num(href_list["time"]) - src.timeleft += time - src.timeleft = min(max(round(src.timeleft), 60), 600) + timeleft += time + timeleft = min(max(round(src.timeleft), 120), 600) if (href_list["timer"]) - if (src.timing == -1.0) + if (timing == -1.0) nanomanager.update_uis(src) return - if (src.safety) + if (safety) usr << "\red The safety is still on." nanomanager.update_uis(src) return - src.timing = !( src.timing ) - if (src.timing) - if(!src.lighthack) - src.icon_state = "nuclearbomb2" - if(!src.safety) - bomb_set = 1//There can still be issues with this reseting when there are multiple bombs. Not a big deal tho for Nuke/N + timing = !(timing) + if (timing) + if(!lighthack) + icon_state = "nuclearbomb2" + if(!safety) + message_admins("[key_name_admin(usr)] engaged a nuclear bomb (JMP)") + if(!is_syndicate) + set_security_level("delta") + bomb_set = 1 //There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke/N else bomb_set = 0 else + if(!is_syndicate) + set_security_level(previous_level) bomb_set = 0 - if(!src.lighthack) - src.icon_state = "nuclearbomb1" + if(!lighthack) + icon_state = "nuclearbomb1" if (href_list["safety"]) - src.safety = !( src.safety ) + safety = !(safety) if(safety) - src.timing = 0 + if(!is_syndicate) + set_security_level(previous_level) + timing = 0 bomb_set = 0 if (href_list["anchor"]) if(removal_stage == 5) - src.anchored = 0 + anchored = 0 visible_message("\red \The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") nanomanager.update_uis(src) return - - src.anchored = !( src.anchored ) - if(src.anchored) - visible_message("\red With a steely snap, bolts slide out of [src] and anchor it to the flooring.") + + if(!isinspace()) + anchored = !(anchored) + if(anchored) + visible_message("\red With a steely snap, bolts slide out of [src] and anchor it to the flooring.") + else + visible_message("\red The anchoring bolts slide back into the depths of [src].") else - visible_message("\red The anchoring bolts slide back into the depths of [src].") + usr << "There is nothing to anchor to!" nanomanager.update_uis(src) @@ -387,7 +327,7 @@ var/bomb_set return /obj/machinery/nuclearbomb/blob_act() - if (src.timing == -1.0) + if (timing == -1.0) return else return ..() @@ -395,14 +335,14 @@ var/bomb_set #define NUKERANGE 80 /obj/machinery/nuclearbomb/proc/explode() - if (src.safety) - src.timing = 0 + if (safety) + timing = 0 return - src.timing = -1.0 - src.yes_code = 0 - src.safety = 1 - if(!src.lighthack) - src.icon_state = "nuclearbomb3" + timing = -1.0 + yes_code = 0 + safety = 1 + if(!lighthack) + icon_state = "nuclearbomb3" playsound(src,'sound/machines/Alarm.ogg',100,0,5) if (ticker && ticker.mode) ticker.mode.explosion_in_progress = 1 @@ -477,8 +417,8 @@ var/bomb_set var/obj/item/weapon/disk/nuclear/NEWDISK = new(pick(blobstart)) transfer_fingerprints_to(NEWDISK) var/turf/diskturf = get_turf(src) - message_admins("[src] has been destroyed in ([diskturf.x], [diskturf.y] ,[diskturf.z] - JMP). Moving it to ([NEWDISK.x], [NEWDISK.y], [NEWDISK.z] - JMP).") - log_game("[src] has been destroyed in ([diskturf.x], [diskturf.y] ,[diskturf.z]). Moving it to ([NEWDISK.x], [NEWDISK.y], [NEWDISK.z]).") + message_admins("[src] has been destroyed at ([diskturf.x], [diskturf.y], [diskturf.z] - JMP). Moving it to ([NEWDISK.x], [NEWDISK.y], [NEWDISK.z] - JMP).") + log_game("[src] has been destroyed in ([diskturf.x], [diskturf.y], [diskturf.z]). Moving it to ([NEWDISK.x], [NEWDISK.y], [NEWDISK.z]).") return QDEL_HINT_HARDDEL_NOW else error("[src] was supposed to be destroyed, but we were unable to locate a blobstart landmark to spawn a new one.") diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 591d5f8f5ba..099a8e61bad 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -250,7 +250,7 @@ if(beingborged) rev_mind.current << "\red The frame's firmware detects and deletes your neural reprogramming! You remember nothing from the moment you were flashed until now." - + message_admins("[key_name_admin(rev_mind.current)] has been borged while being a member of the revolution.") else rev_mind.current << "\red You have been brainwashed! You are no longer a revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you..." diff --git a/code/game/gamemodes/revolution/rp-revolution.dm b/code/game/gamemodes/revolution/rp-revolution.dm index 963579af7c8..7e2b42461fe 100644 --- a/code/game/gamemodes/revolution/rp-revolution.dm +++ b/code/game/gamemodes/revolution/rp-revolution.dm @@ -294,8 +294,8 @@ mob/living/carbon/human/proc src << "\red Wait five seconds before reconversion attempt." return src << "\red Attempting to convert [M]..." - log_admin("[src]([src.ckey]) attempted to convert [M].") - message_admins("\red [src]([src.ckey]) attempted to convert [M].") + log_admin("[key_name(src)] attempted to convert [M].") + message_admins("\red [key_name_admin(src)] attempted to convert [M].") var/choice = alert(M,"Asked by [src]: Do you want to join the revolution?","Align Thyself with the Revolution!","No!","Yes!") if(choice == "Yes!") ticker.mode:add_revolutionary(M.mind) diff --git a/code/game/gamemodes/shadowling/shadowling.dm b/code/game/gamemodes/shadowling/shadowling.dm index 8ce55e77526..421582d26a1 100644 --- a/code/game/gamemodes/shadowling/shadowling.dm +++ b/code/game/gamemodes/shadowling/shadowling.dm @@ -152,9 +152,9 @@ Made by Xhuis update_shadow_icons_added(new_thrall_mind) new_thrall_mind.current.attack_log += "\[[time_stamp()]\] Became a thrall" new_thrall_mind.current.add_language("Shadowling Hivemind") - new_thrall_mind.current.AddSpell(new /obj/effect/proc_holder/spell/targeted/lesser_glare) - new_thrall_mind.current.AddSpell(new /obj/effect/proc_holder/spell/targeted/lesser_shadow_walk) - //new_thrall_mind.current.AddSpell(new /obj/effect/proc_holder/spell/targeted/thrall_vision) //Uncomment when vision code is unfucked. + new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/lesser_glare) + new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/lesser_shadow_walk) + //new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/thrall_vision) //Uncomment when vision code is unfucked. new_thrall_mind.current << "You see the truth. Reality has been torn away and you realize what a fool you've been." new_thrall_mind.current << "The shadowlings are your masters. Serve them above all else and ensure they complete their goals." new_thrall_mind.current << "You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls." diff --git a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm index 46d05fa38a9..1566e3b254b 100644 --- a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm +++ b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm @@ -91,11 +91,11 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N sleep(10) H << "Your powers are awoken. You may now live to your fullest extent. Remember your goal. Cooperate with your thralls and allies." H.mind.remove_spell(/obj/effect/proc_holder/spell/targeted/shadowling_hatch) - H.AddSpell(new /obj/effect/proc_holder/spell/targeted/glare) - H.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/veil) - H.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk) - H.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/flashfreeze) - H.AddSpell(new /obj/effect/proc_holder/spell/targeted/collective_mind) + H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/glare) + H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/veil) + H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk) + H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/flashfreeze) + H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/collective_mind) /obj/effect/proc_holder/spell/targeted/shadowling_ascend name = "Ascend" @@ -156,11 +156,11 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N H.mind.transfer_to(A) A.name = H.real_name A.languages = H.languages - A.AddSpell(new /obj/effect/proc_holder/spell/targeted/annihilate) - A.AddSpell(new /obj/effect/proc_holder/spell/targeted/hypnosis) - A.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_phase_shift) - A.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/ascendant_storm) - A.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit) + A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/annihilate) + A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/hypnosis) + A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_phase_shift) + A.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/ascendant_storm) + A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit) if(A.real_name) A.real_name = H.real_name H.invisibility = 60 //This is pretty bad, but is also necessary for the shuttle call to function properly diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index 03d0c002c78..b25aa1b6ae8 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -198,7 +198,8 @@ if(M.current.vampire_power(50, 0)) M.current.visible_message("[M.current.name] transforms!") M.current.client.prefs.real_name = M.current.generate_name() //random_name(M.current.gender) - M.current.client.prefs.randomize_appearance_for(M.current) + M.current.client.prefs.random_character() + M.current.client.prefs.copy_to(M.current) M.current.regenerate_icons() M.current.remove_vampire_blood(50) M.current.verbs -= /client/vampire/proc/vampire_shapeshift diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm index 33425ebd135..c8f683406e2 100644 --- a/code/game/gamemodes/wizard/rightandwrong.dm +++ b/code/game/gamemodes/wizard/rightandwrong.dm @@ -5,7 +5,7 @@ var/list/magiclist = list("fireball","smoke","blind","mindswap","forcewall","knock","horsemask","charge", "summonitem", "wandnothing", "wanddeath", "wandresurrection", "wandpolymorph", "wandteleport", "wanddoor", "wandfireball", "staffhealing", "armor", "scrying", "staffdoor", "special") var/list/magicspeciallist = list("staffchange","staffanimation", "wandbelt", "contract", "staffchaos") usr << "You summoned [summon_type ? "magic" : "guns"]!" - message_admins("[key_name_admin(usr, 1)] summoned [summon_type ? "magic" : "guns"]!") + message_admins("[key_name_admin(usr)] summoned [summon_type ? "magic" : "guns"]!") for(var/mob/living/carbon/human/H in player_list) if(H.stat == 2 || !(H.client)) continue if(H.mind) diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index a5881156f80..3921bcf19a2 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -91,7 +91,7 @@ if (C == user) user.visible_message("[user] climbs on the operating table.","You climb on the operating table.") else - visible_message("\red [C] has been laid on the operating table by [user].", 3) + visible_message("[C] has been laid on the operating table by [user].", 3) if (C.client) C.client.perspective = EYE_PERSPECTIVE C.client.eye = src @@ -126,12 +126,12 @@ /obj/machinery/optable/proc/check_table(mob/living/carbon/patient as mob) - if(src.victim) - usr << "\blue The table is already occupied!" + if(src.victim && get_turf(victim) == get_turf(src) && victim.lying) + usr << "The table is already occupied!" return 0 - + if(patient.buckled) - usr << "\blue Unbuckle first!" + usr << "Unbuckle first!" return 0 - + return 1 diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index b11edd5ae8d..f9f13d4f907 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -992,7 +992,8 @@ /obj/machinery/alarm/emag_act(mob/user) if(!emagged) src.emagged = 1 - user.visible_message("Sparks fly out of the [src]!", "You emag the [src], disabling its safeties.") + if(user) + user.visible_message("Sparks fly out of the [src]!", "You emag the [src], disabling its safeties.") playsound(src.loc, 'sound/effects/sparks4.ogg', 50, 1) return diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 27a825e2d5c..702f7512535 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -438,16 +438,26 @@ update_flag menu = text2num(href_list["mode_target"]) if(href_list["toggle"]) + var/logmsg if (valve_open) if (holding) - release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding]
" + logmsg = "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding]
" else - release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the air
" + logmsg = "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the air
" else if (holding) - release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the [holding]
" + logmsg = "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the [holding]
" else - release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the air
" + logmsg = "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the air
" + if(air_contents.toxins > 0) + message_admins("[key_name_admin(usr)] opened a canister that contains plasma! (JMP)") + log_admin("[key_name(usr)] opened a canister that contains plasma at [x], [y], [z]") + var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in air_contents.trace_gases + if(sleeping_agent && (sleeping_agent.moles > 1)) + message_admins("[key_name_admin(usr)] opened a canister that contains N2O! (JMP)") + log_admin("[key_name(usr)] opened a canister that contains N2O at [x], [y], [z]") + investigate_log(logmsg, "atmos") + release_log += logmsg valve_open = !valve_open if (href_list["remove_tank"]) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index c08ae986c6d..353f807a682 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -198,7 +198,7 @@ if(istype(O, /mob/living/silicon/ai)) var/mob/living/silicon/ai/AI = O if(U.name == "Unknown") AI << "[U] holds \a [itemname] up to one of your cameras ..." - else AI << "[U] holds \a [itemname] up to one of your cameras ..." + else AI << "[U] holds \a [itemname] up to one of your cameras ..." AI.last_paper_seen = "[itemname][info]" else if (O.client && O.client.eye == src) O << "[U] holds \a [itemname] up to one of the cameras ..." diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm index 28523b3c761..1c423bf1da0 100644 --- a/code/game/machinery/camera/tracking.dm +++ b/code/game/machinery/camera/tracking.dm @@ -129,8 +129,9 @@ if(istype(M, /mob/living/carbon/human)) human = 1 var/mob/living/carbon/human/H = M - //Cameras can't track people wearing an agent card or a ninja hood. - if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) + //Cameras can't track people wearing an untrackable card + var/obj/item/weapon/card/id/id = H.wear_id + if(istype(id) && id.is_untrackable()) continue if(istype(H.head, /obj/item/clothing/head)) var/obj/item/clothing/head/hat = H.head @@ -189,25 +190,9 @@ while (U.cameraFollow == target) if (U.cameraFollow == null) return - if (istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = target - if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) - U.ai_cancel_tracking(1) - return - if(H.digitalcamo) - U.ai_cancel_tracking(1) - return - if(istype(H.head, /obj/item/clothing/head)) - var/obj/item/clothing/head/hat = H.head - if (hat.blockTracking) - U.ai_cancel_tracking(1) - return - if(istype(target.loc,/obj/effect/dummy)) - U.ai_cancel_tracking() - return if (!trackable(target)) - U << "Target is not near any active cameras." + U << "Target is not on or near any active cameras on the station." sleep(100) continue @@ -229,7 +214,21 @@ /proc/trackable(atom/movable/M) var/turf/T = get_turf(M) - if(T && (T.z in config.contact_levels) && (hassensorlevel(M, SUIT_SENSOR_TRACKING) || M in aibots)) + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/obj/item/weapon/card/id/id = H.wear_id + if(istype(id) && id.is_untrackable()) + return 0 + if(H.digitalcamo) + return 0 + if(istype(H.head, /obj/item/clothing/head)) + var/obj/item/clothing/head/hat = H.head + if (hat.blockTracking) + return 0 + if(istype(M.loc,/obj/effect/dummy)) + return 0 + + if((T && (T.z in config.contact_levels)) && ((hassensorlevel(M, SUIT_SENSOR_TRACKING) || M in aibots))) return 1 return near_camera(M) diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index 8aa64e18b6b..76fd8cf7ea5 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -233,201 +233,28 @@ This is a good place for AI-related object verbs so I'm sticking it here. If adding stuff to this, don't forget that an AI need to cancel_camera() whenever it physically moves to a different location. That prevents a few funky behaviors. */ -//What operation to perform based on target, what ineraction to perform based on object used, target itself, user. The object used is src and calls this proc. -/obj/item/proc/transfer_ai(var/choice as text, var/interaction as text, var/target, var/mob/U as mob) - if(!src:flush) - switch(choice) - if("AICORE")//AI mob. - var/mob/living/silicon/ai/T = target - switch(interaction) - if("AICARD") - var/obj/item/device/aicard/C = src - if(C.contents.len)//If there is an AI on card. - U << "\red Transfer failed: \black Existing AI found on this terminal. Remove existing AI to install a new one." - else - if (ticker.mode.name == "AI malfunction") - var/datum/game_mode/malfunction/malf = ticker.mode - for (var/datum/mind/malfai in malf.malf_ai) - if (T.mind == malfai) - U << "\red ERROR: \black Remote transfer interface disabled."//Do ho ho ho~ - return - new /obj/structure/AIcore/deactivated(T.loc)//Spawns a deactivated terminal at AI location. - T.aiRestorePowerRoutine = 0//So the AI initially has power. - T.control_disabled = 1//Can't control things remotely if you're stuck in a card! - T.loc = C//Throw AI into the card. - C.name = "inteliCard - [T.name]" - if (T.stat == 2) - C.icon_state = "aicard-404" - else - C.icon_state = "aicard-full" - T.cancel_camera() - T << "You have been downloaded to a mobile storage device. Remote device connection severed." - U << "\blue Transfer successful: \black [T.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory." - /*if("NINJASUIT") - var/obj/item/clothing/suit/space/space_ninja/C = src - if(C.AI)//If there is an AI on card. - U << "\red Transfer failed: \black Existing AI found on this terminal. Remove existing AI to install a new one." - else - if (ticker.mode.name == "AI malfunction") - var/datum/game_mode/malfunction/malf = ticker.mode - for (var/datum/mind/malfai in malf.malf_ai) - if (T.mind == malfai) - U << "\red ERROR: \black Remote transfer interface disabled." - return - if(T.stat)//If the ai is dead/dying. - U << "\red ERROR: \black [T.name] data core is corrupted. Unable to install." - else - new /obj/structure/AIcore/deactivated(T.loc) - T.aiRestorePowerRoutine = 0 - T.control_disabled = 1 - T.loc = C - C.AI = T - T.cancel_camera() - T << "You have been downloaded to a mobile storage device. Remote device connection severed." - U << "\blue Transfer successful: \black [T.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory."*/ +//The type of interaction, the player performing the operation, the AI itself, and the card object, if any. - if("INACTIVE")//Inactive AI object. - var/obj/structure/AIcore/deactivated/T = target - switch(interaction) - if("AICARD") - var/obj/item/device/aicard/C = src - var/mob/living/silicon/ai/A = locate() in C//I love locate(). Best proc ever. - if(A)//If AI exists on the card. Else nothing since both are empty. - A.control_disabled = 0 - A.loc = T.loc//To replace the terminal. - C.icon_state = "aicard" - C.name = "inteliCard" - C.overlays.Cut() - A.cancel_camera() - A << "You have been uploaded to a stationary terminal. Remote device connection restored." - U << "\blue Transfer successful: \black [A.name] ([rand(1000,9999)].exe) installed and executed succesfully. Local copy has been removed." - qdel(T) - /*if("NINJASUIT") - var/obj/item/clothing/suit/space/space_ninja/C = src - var/mob/living/silicon/ai/A = C.AI - if(A) - A.control_disabled = 0 - C.AI = null - A.loc = T.loc - A.cancel_camera() - A << "You have been uploaded to a stationary terminal. Remote device connection restored." - U << "\blue Transfer succesful: \black [A.name] ([rand(1000,9999)].exe) installed and executed succesfully. Local copy has been removed." - del(T)*/ - if("AIFIXER")//AI Fixer terminal. - var/obj/machinery/computer/aifixer/T = target - switch(interaction) - if("AICARD") - var/obj/item/device/aicard/C = src - if(!T.contents.len) - if (!C.contents.len) - U << "No AI to copy over!"//Well duh - else for(var/mob/living/silicon/ai/A in C) - C.icon_state = "aicard" - C.name = "inteliCard" - C.overlays.Cut() - A.loc = T - T.occupant = A - A.control_disabled = 1 - if (A.stat == 2) - T.overlays += image('icons/obj/computer.dmi', "ai-fixer-404") - else - T.overlays += image('icons/obj/computer.dmi', "ai-fixer-full") - T.overlays -= image('icons/obj/computer.dmi', "ai-fixer-empty") - A.cancel_camera() - A << "You have been uploaded to a stationary terminal. Sadly, there is no remote access from here." - U << "\blue Transfer successful: \black [A.name] ([rand(1000,9999)].exe) installed and executed succesfully. Local copy has been removed." - else - if(!C.contents.len && T.occupant && !T.active) - C.name = "inteliCard - [T.occupant.name]" - T.overlays += image('icons/obj/computer.dmi', "ai-fixer-empty") - if (T.occupant.stat == 2) - C.icon_state = "aicard-404" - T.overlays -= image('icons/obj/computer.dmi', "ai-fixer-404") - else - C.icon_state = "aicard-full" - T.overlays -= image('icons/obj/computer.dmi', "ai-fixer-full") - T.occupant << "You have been downloaded to a mobile storage device. Still no remote access." - U << "\blue Transfer succesful: \black [T.occupant.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory." - T.occupant.loc = C - T.occupant.cancel_camera() - T.occupant = null - else if (C.contents.len) - U << "\red ERROR: \black Artificial intelligence detected on terminal." - else if (T.active) - U << "\red ERROR: \black Reconstruction in progress." - else if (!T.occupant) - U << "\red ERROR: \black Unable to locate artificial intelligence." - /*if("NINJASUIT") - var/obj/item/clothing/suit/space/space_ninja/C = src - if(!T.contents.len) - if (!C.AI) - U << "No AI to copy over!" - else - var/mob/living/silicon/ai/A = C.AI - A.loc = T - T.occupant = A - C.AI = null - A.control_disabled = 1 - T.overlays += image('icons/obj/computer.dmi', "ai-fixer-full") - T.overlays -= image('icons/obj/computer.dmi', "ai-fixer-empty") - A.cancel_camera() - A << "You have been uploaded to a stationary terminal. Sadly, there is no remote access from here." - U << "\blue Transfer successful: \black [A.name] ([rand(1000,9999)].exe) installed and executed succesfully. Local copy has been removed." - else - if(!C.AI && T.occupant && !T.active) - if (T.occupant.stat) - U << "\red ERROR: \black [T.occupant.name] data core is corrupted. Unable to install." - else - T.overlays += image('icons/obj/computer.dmi', "ai-fixer-empty") - T.overlays -= image('icons/obj/computer.dmi', "ai-fixer-full") - T.occupant << "You have been downloaded to a mobile storage device. Still no remote access." - U << "\blue Transfer successful: \black [T.occupant.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory." - T.occupant.loc = C - T.occupant.cancel_camera() - T.occupant = null - else if (C.AI) - U << "\red ERROR: \black Artificial intelligence detected on terminal." - else if (T.active) - U << "\red ERROR: \black Reconstruction in progress." - else if (!T.occupant) - U << "\red ERROR: \black Unable to locate artificial intelligence."*/ - /*if("NINJASUIT")//Ninjasuit - var/obj/item/clothing/suit/space/space_ninja/T = target - switch(interaction) - if("AICARD") - var/obj/item/device/aicard/C = src - if(T.s_initialized&&U==T.affecting)//If the suit is initialized and the actor is the user. - var/mob/living/silicon/ai/A_T = locate() in C//Determine if there is an AI on target card. Saves time when checking later. - var/mob/living/silicon/ai/A = T.AI//Deterine if there is an AI in suit. +atom/proc/transfer_ai(var/interaction, var/mob/user, var/mob/living/silicon/ai/AI, var/obj/item/device/aicard/card) + if(istype(card)) + if(card.flush) + user << "ERROR: AI flush is in progress, cannot execute transfer protocol." + return 0 + return 1 - if(A)//If the host AI card is not empty. - if(A_T)//If there is an AI on the target card. - U << "\red ERROR: \black [A_T.name] already installed. Remove [A_T.name] to install a new one." - else - A.loc = C//Throw them into the target card. Since they are already on a card, transfer is easy. - C.name = "inteliCard - [A.name]" - C.icon_state = "aicard-full" - T.AI = null - A.cancel_camera() - A << "You have been uploaded to a mobile storage device." - U << "\blue SUCCESS: \black [A.name] ([rand(1000,9999)].exe) removed from host and stored within local memory." - else//If host AI is empty. - if(C.flush)//If the other card is flushing. - U << "\red ERROR: \black AI flush is in progress, cannot execute transfer protocol." - else - if(A_T&&!A_T.stat)//If there is an AI on the target card and it's not inactive. - A_T.loc = T//Throw them into suit. - C.icon_state = "aicard" - C.name = "inteliCard" - C.overlays.Cut() - T.AI = A_T - A_T.cancel_camera() - A_T << "You have been uploaded to a mobile storage device." - U << "\blue SUCCESS: \black [A_T.name] ([rand(1000,9999)].exe) removed from local memory and installed to host." - else if(A_T)//If the target AI is dead. Else just go to return since nothing would happen if both are empty. - U << "\red ERROR: \black [A_T.name] data core is corrupted. Unable to install."*/ - else - U << "\red ERROR: \black AI flush is in progress, cannot execute transfer protocol." - return \ No newline at end of file +/obj/structure/AIcore/deactivated/transfer_ai(var/interaction, var/mob/user, var/mob/living/silicon/ai/AI, var/obj/item/device/aicard/card) + if(!..()) + return + //Transferring a carded AI to a core. + if(interaction == AI_TRANS_FROM_CARD) + AI.control_disabled = 0 + AI.aiRadio.disabledAi = 0 + AI.loc = loc//To replace the terminal. + AI << "You have been uploaded to a stationary terminal. Remote device connection restored." + user << "Transfer successful: [AI.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed." + qdel(src) + else //If for some reason you use an empty card on an empty AI terminal. + user << "There is no AI loaded on this terminal!" + \ No newline at end of file diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm index d291c65ac78..a7dd1874424 100644 --- a/code/game/machinery/computer/aifixer.dm +++ b/code/game/machinery/computer/aifixer.dm @@ -10,77 +10,64 @@ light_color = LIGHT_COLOR_PURPLE -/obj/machinery/computer/aifixer/New() - src.overlays += image('icons/obj/computer.dmi', "ai-fixer-empty") - - /obj/machinery/computer/aifixer/attackby(I as obj, user as mob, params) - if(istype(I, /obj/item/device/aicard)) + if(occupant && istype(I, /obj/item/weapon/screwdriver)) if(stat & (NOPOWER|BROKEN)) - user << "This terminal isn't functioning right now, get it working!" - return - I:transfer_ai("AIFIXER","AICARD",src,user) - - ..() - return - + user << "The screws on [name]'s screen won't budge." + else + user << "The screws on [name]'s screen won't budge and it emits a warning beep." + return + else + ..() + /obj/machinery/computer/aifixer/attack_ai(var/mob/user as mob) - return attack_hand(user) + ui_interact(user) /obj/machinery/computer/aifixer/attack_hand(var/mob/user as mob) - if(..()) - return - - user.set_machine(src) - var/dat = "

AI System Integrity Restorer



" - - if (src.occupant) - var/laws - dat += "Stored AI: [src.occupant.name]
System integrity: [(src.occupant.health+100)/2]%
" - - if (src.occupant.laws.zeroth) - laws += "0: [src.occupant.laws.zeroth]
" + ui_interact(user) +/obj/machinery/computer/aifixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + if(occupant) + data["occupant"] = occupant.name + data["reference"] = "\ref[occupant]" + data["integrity"] = (occupant.health+100)/2 + data["stat"] = occupant.stat + data["active"] = active + data["wireless"] = occupant.control_disabled + data["radio"] = occupant.aiRadio.disabledAi + data["zeroth"] = occupant.laws.zeroth + + var/laws[0] var/number = 1 - for (var/index = 1, index <= src.occupant.laws.inherent.len, index++) - var/law = src.occupant.laws.inherent[index] - if (length(law) > 0) - laws += "[number]: [law]
" + for (var/index = 1, index <= occupant.laws.inherent.len, index++) + var/law = occupant.laws.inherent[index] + if(length(law) > 0) + laws.Add(list(list("law" = law, "number" = number))) number++ - for (var/index = 1, index <= src.occupant.laws.supplied.len, index++) - var/law = src.occupant.laws.supplied[index] + for (var/index = 1, index <= occupant.laws.supplied.len, index++) + var/law = occupant.laws.supplied[index] if (length(law) > 0) - laws += "[number]: [law]
" - number++ + laws += "[number]: [law]
" + number++ + + data["laws"] = laws + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) - dat += "Laws:
[laws]
" - - if (src.occupant.stat == 2) - dat += "AI nonfunctional" - else - dat += "AI functional" - if (!src.active) - dat += {"

Begin Reconstruction"} - else - dat += "

Reconstruction in process, please wait.
" - dat += {" Close"} - - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") - return - -/obj/machinery/computer/aifixer/process() - if(..()) - src.updateDialog() - return + if (!ui) + ui = new(user, src, ui_key, "ai_fixer.tmpl", "AI System Integrity Restorer", 550, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) /obj/machinery/computer/aifixer/Topic(href, href_list) if(..()) return 1 - if (href_list["fix"]) + + if(href_list["fix"]) src.active = 1 - src.overlays += image('icons/obj/computer.dmi', "ai-fixer-on") while (src.occupant.health < 100) src.occupant.adjustOxyLoss(-1) src.occupant.adjustFireLoss(-1) @@ -92,32 +79,66 @@ src.occupant.lying = 0 dead_mob_list -= src.occupant living_mob_list += src.occupant - src.overlays -= image('icons/obj/computer.dmi', "ai-fixer-404") - src.overlays += image('icons/obj/computer.dmi', "ai-fixer-full") - src.updateUsrDialog() sleep(10) src.active = 0 - src.overlays -= image('icons/obj/computer.dmi', "ai-fixer-on") - - src.add_fingerprint(usr) - src.updateUsrDialog() - return + + if(href_list["wireless"]) + var/wireless = text2num(href_list["wireless"]) + if(wireless == 0 || wireless == 1) + occupant.control_disabled = wireless + + if(href_list["radio"]) + var/radio = text2num(href_list["radio"]) + if(radio == 0 || radio == 1) + occupant.aiRadio.disabledAi = radio + nanomanager.update_uis(src) + update_icon() + return /obj/machinery/computer/aifixer/update_icon() ..() - // Broken / Unpowered - if((stat & BROKEN) || (stat & NOPOWER)) - overlays.Cut() - - // Working / Powered + if(stat & (NOPOWER|BROKEN)) + return else + var/overlay_layer = LIGHTING_LAYER+0.2 // +0.1 from the default computer overlays + if(active) + overlays += image(icon,"ai-fixer-on",overlay_layer) if (occupant) switch (occupant.stat) if (0) - overlays += image('icons/obj/computer.dmi', "ai-fixer-full") + overlays += image(icon,"ai-fixer-full",overlay_layer) if (2) - overlays += image('icons/obj/computer.dmi', "ai-fixer-404") + overlays += image(icon,"ai-fixer-404",overlay_layer) else - overlays += image('icons/obj/computer.dmi', "ai-fixer-empty") + overlays += image(icon,"ai-fixer-empty",overlay_layer) + +/obj/machinery/computer/aifixer/transfer_ai(var/interaction, var/mob/user, var/mob/living/silicon/ai/AI, var/obj/item/device/aicard/card) + if(!..()) + return + //Downloading AI from card to terminal. + if(interaction == AI_TRANS_FROM_CARD) + if(stat & (NOPOWER|BROKEN)) + user << "[src] is offline and cannot take an AI at this time!" + return + AI.loc = src + occupant = AI + AI.control_disabled = 1 + AI.aiRadio.disabledAi = 1 + AI << "You have been uploaded to a stationary terminal. Sadly, there is no remote access from here." + user << "Transfer successful: [AI.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed." + update_icon() + + else //Uploading AI from terminal to card + if(occupant && !active) + occupant << "You have been downloaded to a mobile storage device. Still no remote access." + user << "Transfer successful: [occupant.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory." + occupant.loc = card + occupant = null + update_icon() + else if (active) + user << "ERROR: Reconstruction in progress." + else if (!occupant) + user << "ERROR: Unable to locate artificial intelligence." + \ No newline at end of file diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 89a67f6f122..6f8ea8eaf4d 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -3,7 +3,7 @@ /obj/structure/computerframe density = 1 anchored = 0 - name = "Computer-frame" + name = "computer frame" icon = 'icons/obj/stock_parts.dmi' icon_state = "0" var/state = 0 @@ -14,7 +14,7 @@ density = 0 anchored = 0 w_class = 2.0 - name = "Circuit board" + name = "circuit board" icon = 'icons/obj/module.dmi' icon_state = "id_mod" item_state = "electronic" diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 66c56dd196a..189338e14e9 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -170,8 +170,8 @@ var/shuttle_call/shuttle_calls[0] message_cooldown = 0 if("callshuttle") - var/input = stripped_input(usr, "Please enter the reason for calling the shuttle.", "Shuttle Call Reason.","") as text|null - if(!input || ..() || !(is_authenticated(usr) == 2)) + var/input = input(usr, "Please enter the reason for calling the shuttle.", "Shuttle Call Reason.","") as text|null + if(!input || ..() || !is_authenticated(usr)) nanomanager.update_uis(src) return @@ -426,7 +426,7 @@ var/shuttle_call/shuttle_calls[0] return if(world.time < 6000) // Ten minute grace period to let the game get going without lolmetagaming. -- TLE - user << "The emergency shuttle is refueling. Please wait another [round((6000-world.time)/60)] minutes before trying again." + user << "The emergency shuttle is refueling. Please wait another [round((6000-world.time)/600)] minutes before trying again." return if(emergency_shuttle.going_to_centcom()) @@ -470,7 +470,7 @@ var/shuttle_call/shuttle_calls[0] return if(world.time < 54000) // 30 minute grace period to let the game get going - user << "The shuttle is refueling. Please wait another [round((54000-world.time)/60)] minutes before trying again." + user << "The shuttle is refueling. Please wait another [round((54000-world.time)/600)] minutes before trying again." return if(ticker.mode.name == "epidemic") diff --git a/code/game/machinery/computer/hologram.dm b/code/game/machinery/computer/hologram.dm index c21e3cf8b4f..bfd95d46457 100644 --- a/code/game/machinery/computer/hologram.dm +++ b/code/game/machinery/computer/hologram.dm @@ -36,7 +36,7 @@ I.Blend(rgb(- src.lumens, -src.lumens, -src.lumens), ICON_SUBTRACT) I.Blend(new /icon('icons/mob/human.dmi', "mouth_m_s"), ICON_OVERLAY) - I.Blend(new /icon('icons/mob/human.dmi', "underwear1_m_s"), ICON_OVERLAY) + I.Blend(new /icon('icons/mob/underwear.dmi', "Mens White"), ICON_OVERLAY) var/icon/U = new /icon('icons/mob/human_face.dmi', "hair_a_s") U.Blend(rgb(src.h_r, src.h_g, src.h_b), ICON_ADD) diff --git a/code/game/machinery/computer/pod_tracking_console.dm b/code/game/machinery/computer/pod_tracking_console.dm index 5c40d9a11f8..060b58eda90 100644 --- a/code/game/machinery/computer/pod_tracking_console.dm +++ b/code/game/machinery/computer/pod_tracking_console.dm @@ -5,39 +5,43 @@ icon_screen = "rdcomp" light_color = LIGHT_COLOR_PURPLE req_access = list(access_robotics) - circuit = "/obj/item/weapon/circuitboard/pod_locater" + circuit = /obj/item/weapon/circuitboard/pod_locater /obj/machinery/computer/podtracker/attack_ai(var/mob/user as mob) - return src.attack_hand(user) - -/obj/machinery/computer/podtracker/attack_hand(var/mob/user as mob) - if(..()) - return - user.set_machine(src) - var/dat = "[src.name]" - dat += "

Pod beacons data

" + return attack_hand(user) + +/obj/machinery/computer/podtracker/attack_hand(user as mob) + ui_interact(user) + +/obj/machinery/computer/podtracker/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + 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/enabled = TR.enabled if(myPod && enabled) - dat += {"
[capitalize(myPod.name)]
-  Pod SPS X: [myPod.x]
-  Pod SPS Y: [myPod.y]
-  Pod SPS Z: [myPod.z]
"} + var/podname = capitalize(sanitize(myPod.name)) + var/occupant = "None" + var/occupant2 = "None" if(myPod.occupant) - dat += {" Pod Pilot: [myPod.occupant.name]
"} + occupant = myPod.occupant.name if(myPod.occupant2) - dat += {" Pod Passenger: [myPod.occupant2.name]
"} + 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))) + + data["pods"] = pods - dat += "(Refresh)
" - dat += "" + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") - return + if (!ui) + ui = new(user, src, ui_key, "pod_tracking.tmpl", "Pod Tracking Console", 400, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) /obj/machinery/computer/podtracker/Topic(href, href_list) if(..()) - return - src.updateUsrDialog() - return + return 1 + + if(href_list["refresh"]) + nanomanager.update_uis(src) diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index ba3727ee30b..4fda7a334d3 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -72,14 +72,14 @@ target << "Extreme danger. Termination codes detected. Scrambling security codes and automatic AI unlink triggered." target.ResetSecurityCodes() else - message_admins("\blue [key_name_admin(usr)] detonated [target.name]!") - log_game("\blue [key_name_admin(usr)] detonated [target.name]!") + message_admins("[key_name_admin(usr)] detonated [key_name_admin(target)] (JMP)!") + log_game("\[key_name(usr)] detonated [key_name(target)]!") target << "Self-destruct command received." + if(target.connected_ai) + target.connected_ai << "

ALERT - Cyborg detonation detected: [target.name]
" spawn(10) target.self_destruct() - - // Locks or unlocks the cyborg else if (href_list["lockdown"]) var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["lockdown"]) @@ -101,15 +101,13 @@ if(!target || !istype(target)) return - message_admins("\blue [key_name_admin(usr)] [target.canmove ? "locked down" : "released"] [target.name]!") - log_game("[key_name(usr)] [target.canmove ? "locked down" : "released"] [target.name]!") + message_admins("[key_name_admin(usr)] [target.canmove ? "locked down" : "released"] [key_name_admin(target)]!") + log_game("[key_name(usr)] [target.canmove ? "locked down" : "released"] [key_name(target)]!") target.canmove = !target.canmove - if (target.lockcharge) - target.lockcharge = !target.lockcharge - target << "Your lockdown has been lifted!" - else - target.lockcharge = !target.lockcharge - target << "You have been locked down!" + target.lockcharge = !target.lockcharge + target << "[!target.lockcharge ? "Your lockdown has been lifted!" : "You have been locked down!"]" + if(target.connected_ai) + target.connected_ai << "[!target.lockcharge ? "NOTICE - Cyborg lockdown lifted" : "ALERT - Cyborg lockdown detected"]: [target.name]
" // Remotely hacks the cyborg. Only antag AIs can do this and only to linked cyborgs. else if (href_list["hack"]) @@ -137,8 +135,8 @@ if(!target || !istype(target)) return - message_admins("\blue [key_name_admin(usr)] emagged [target.name] using robotic console!") - log_game("[key_name(usr)] emagged [target.name] using robotic console!") + message_admins("\blue [key_name_admin(usr)] emagged [key_name_admin(target)] using robotic console!") + log_game("[key_name(usr)] emagged [key_name(target)] using robotic console!") target.emagged = 1 target << "Failsafe protocols overriden. New tools available." @@ -160,9 +158,9 @@ user << "Self-destruct aborted - safety active" return - message_admins("\blue [key_name_admin(usr)] detonated all cyborgs!") - log_game("[key_name(usr)] detonated all cyborgs!") - + message_admins("[key_name_admin(usr)] detonated all cyborgs!") + log_game("\[key_name(usr)] detonated all cyborgs!") + for(var/mob/living/silicon/robot/R in mob_list) if(istype(R, /mob/living/silicon/robot/drone)) continue @@ -170,6 +168,8 @@ if(R.scrambledcodes) continue R << "Self-destruct command received." + if(R.connected_ai) + R.connected_ai << "

ALERT - Cyborg detonation detected: [R.name]
" spawn(10) R.self_destruct() diff --git a/code/game/machinery/computer/shuttle.dm b/code/game/machinery/computer/shuttle.dm index d9f3dcd996e..28125a24c96 100644 --- a/code/game/machinery/computer/shuttle.dm +++ b/code/game/machinery/computer/shuttle.dm @@ -37,12 +37,12 @@ src.authorized -= W:registered_name src.authorized += W:registered_name if (src.auth_need - src.authorized.len > 0) - message_admins("[key_name_admin(user)] has authorized early shuttle launch") - log_game("[user.ckey] has authorized early shuttle launch") + message_admins("[key_name_admin(user.client)] has authorized early shuttle launch ",0,1) + log_game("[key_name(user)] has authorized early shuttle launch in ([x],[y],[z])") world << text("\blue Alert: [] authorizations needed until shuttle is launched early", src.auth_need - src.authorized.len) else - message_admins("[key_name_admin(user)] has launched the shuttle") - log_game("[user.ckey] has launched the shuttle early") + message_admins("[key_name_admin(user.client)] has launched the emergency shuttle before launch.",0,1) + log_game("[key_name(user)] has launched the emergency shuttle before launch in ([x],[y],[z]).") world << "\blue Alert: Shuttle launch time shortened to 10 seconds!" emergency_shuttle.set_launch_countdown(10) //src.authorized = null @@ -59,13 +59,15 @@ src.authorized = list( ) return - emag_act(user as mob) + emag_act(mob/user as mob) if (!emagged) var/choice = alert(user, "Would you like to launch the shuttle?","Shuttle control", "Launch", "Cancel") if(!emagged && !emergency_shuttle.location()) switch(choice) if("Launch") + message_admins("[key_name_admin(user.client)] has emagged the emergency shuttle before launch.",0,1) + log_game("[key_name(user)] has emagged the emergency shuttle in ([x],[y],[z]) before launch.") world << "\blue Alert: Shuttle launch time shortened to 10 seconds!" emergency_shuttle.set_launch_countdown(10) emagged = 1 diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index d52c6d2adf7..c28edd89e55 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -488,9 +488,8 @@ Gh << "Warning: Your body has entered cryostorage." // Book keeping! - var/turf/location = get_turf(src) - log_admin("[key_name_admin(M)] has entered a stasis pod. (JMP)") - message_admins("[key_name_admin(M)] has entered a stasis pod.") + log_admin("[key_name(M)] has entered a stasis pod.") + message_admins("[key_name_admin(user)] has entered a stasis pod. (JMP)") //Despawning occurs when process() is called with an occupant without a client. src.add_fingerprint(M) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 6eaa50bc1f1..abc14227433 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -851,7 +851,9 @@ About the new airlock wires panel: return /obj/machinery/door/airlock/plasma/attackby(C as obj, mob/user as mob, params) - if(C) + if(is_hot(C) > 300) + message_admins("Plasma airlock ignited by [key_name_admin(user)] in ([x],[y],[z] - JMP)") + log_game("Plasma wall ignited by [key_name(user)] in ([x],[y],[z])") ignite(is_hot(C)) ..() diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 5322c3da301..e32146ff69f 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -82,7 +82,7 @@ if (istype(O, /mob/living/carbon/human)) var/mob/living/carbon/human/H = O var/obj/item/organ/eyes/E = H.internal_organs_by_name["eyes"] - if ((E.damage > E.min_bruised_damage && prob(E.damage + 50))) + if (E && (E.damage > E.min_bruised_damage && prob(E.damage + 50))) flick("e_flash", O:flash) E.damage += rand(1, 2) else diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm index df6727ce3f8..7c08f2ebd07 100644 --- a/code/game/machinery/kitchen/gibber.dm +++ b/code/game/machinery/kitchen/gibber.dm @@ -339,7 +339,7 @@ return if(UserOverride) - msg_admin_attack("[occupant] ([occupant.ckey]) was gibbed by an autogibber (\the [src]) at (JMP)") + msg_admin_attack("[key_name_admin(occupant)] was gibbed by an autogibber (\the [src]) (JMP)") if(src.operating) return @@ -374,11 +374,11 @@ new /obj/effect/decal/cleanable/blood/gibs(src) if(!UserOverride) - src.occupant.attack_log += "\[[time_stamp()]\] Was gibbed by [user]/[user.ckey]" //One shall not simply gib a mob unnoticed! - user.attack_log += "\[[time_stamp()]\] Gibbed [src.occupant]/[src.occupant.ckey]" + src.occupant.attack_log += "\[[time_stamp()]\] Was gibbed by [key_name(user)]" //One shall not simply gib a mob unnoticed! + user.attack_log += "\[[time_stamp()]\] Gibbed [key_name(occupant)]" if(src.occupant.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] gibbed [src.occupant] ([src.occupant.ckey]) (JMP)") + msg_admin_attack("[key_name_admin(user)] gibbed [key_name_admin(occupant)]") if(!iscarbon(user)) src.occupant.LAssailant = null diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index eda2aeeda99..14c72f6ee9c 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -177,6 +177,10 @@ Class Procs: if(prob(50)) qdel(src) +//sets the use_power var and then forces an area power update +/obj/machinery/proc/update_use_power(var/new_use_power) + use_power = new_use_power + /obj/machinery/proc/auto_use_power() if(!powered(power_channel)) return 0 @@ -220,7 +224,7 @@ Class Procs: var/re_init=0 if("set_tag" in href_list) if(!(href_list["set_tag"] in settagwhitelist))//I see you're trying Href exploits, I see you're failing, I SEE ADMIN WARNING. (seriously though, this is a powerfull HREF, I originally found this loophole, I'm not leaving it in on my PR) - message_admins("set_tag HREF (var attempted to edit: [href_list["set_tag"]]) exploit attempted by [key_name(user, user.client)] (?) on [src] ([x],[y],[z] - JMP)") + message_admins("set_tag HREF (var attempted to edit: [href_list["set_tag"]]) exploit attempted by [key_name_admin(user)] on [src] (JMP)") return 1 if(!(href_list["set_tag"] in vars)) usr << "Something went wrong: Unable to find [href_list["set_tag"]] in vars!" diff --git a/code/game/machinery/podmen.dm b/code/game/machinery/podmen.dm index 58dc6dc7888..6679fd3b580 100644 --- a/code/game/machinery/podmen.dm +++ b/code/game/machinery/podmen.dm @@ -46,7 +46,6 @@ Growing it to term with nothing injected will grab a ghost from the observers. * if(!source.client && source.mind) for(var/mob/O in respawnable_list) if(O.mind == source.mind && config.revival_pod_plants) - message_admins("Found mind, asking for respawn") switch(alert(O,"Your corpse has been placed into a pod plant. Do you want to be resurrected/cloned? Please note if you select 'No', you will still be able to be cloned or borged again this round.","Pod Alert","Yes","No")) if("Yes") source.key = O.key diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 7bb074e03f4..0b7907eb88f 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -352,8 +352,9 @@ var/list/turret_icons if(!emagged) //Emagging the turret makes it go bonkers and stun everyone. It also makes //the turret shoot much, much faster. - user << "You short out [src]'s threat assessment circuits." - visible_message("[src] hums oddly...") + if(user) + user << "You short out [src]'s threat assessment circuits." + visible_message("[src] hums oddly...") emagged = 1 iconholder = 1 controllock = 1 diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 49ea6865f58..37220d43956 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -10,6 +10,7 @@ var/mob/occupant = null var/circuitboard = "/obj/item/weapon/circuitboard/cyborgrecharger" var/recharge_speed + var/recharge_speed_nutrition var/repairs /obj/machinery/recharge_station/New() @@ -35,9 +36,11 @@ /obj/machinery/recharge_station/RefreshParts() recharge_speed = 0 + recharge_speed_nutrition = 0 repairs = 0 for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts) recharge_speed += C.rating * 100 + recharge_speed_nutrition += C.rating * 10 for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) repairs += M.rating - 1 for(var/obj/item/weapon/stock_parts/cell/C in component_parts) @@ -51,6 +54,9 @@ process_occupant() return 1 +/obj/machinery/recharge_station/Bumped(var/mob/AM) + move_inside(AM) + /obj/machinery/recharge_station/allow_drop() return 0 @@ -105,6 +111,14 @@ R.cell.charge = R.cell.maxcharge else R.cell.charge = min(R.cell.charge + recharge_speed, R.cell.maxcharge) + else if(istype(occupant, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = occupant + if(!isnull(H.internal_organs_by_name["cell"]) && H.nutrition < 450) + H.nutrition = min(H.nutrition+recharge_speed_nutrition, 450) + if(repairs) + H.adjustBruteLoss(-(repairs)) + H.adjustFireLoss(-(repairs)) + H.updatehealth() /obj/machinery/recharge_station/proc/go_out() if(!( src.occupant )) @@ -198,34 +212,51 @@ add_fingerprint(usr) return -/obj/machinery/recharge_station/verb/move_inside() +/obj/machinery/recharge_station/verb/move_inside(var/mob/user = usr) set category = "Object" set src in oview(1) - if (usr.stat == 2) - //Whoever had it so that a borg with a dead cell can't enter this thing should be shot. --NEO - return - if (!(istype(usr, /mob/living/silicon/))) - usr << "\blue Only non-organics may enter the recharger!" - return - if (src.occupant) - usr << "\blue The cell is already occupied!" - return - if (!usr:cell) - usr << "\blue Without a powercell, you can't be recharged." - //Make sure they actually HAVE a cell, now that they can get in while powerless. --NEO + + if(!user) return + if (panel_open) - usr << "\blue Close the maintenance panel first." + usr << "Close the maintenance panel first." + return + + var/can_accept_user + if(isrobot(user)) + var/mob/living/silicon/robot/R = user + + if(R.stat == DEAD) + //Whoever had it so that a borg with a dead cell can't enter this thing should be shot. --NEO + return + if(occupant) + R << "The cell is already occupied!" + return + if(!R.cell) + R << "Without a power cell, you can't be recharged." + //Make sure they actually HAVE a cell, now that they can get in while powerless. --NEO + return + can_accept_user = 1 + + else if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(!isnull(H.internal_organs_by_name["cell"])) + can_accept_user = 1 + + if(!can_accept_user) + user << "Only non-organics may enter the recharger!" return - usr.stop_pulling() - if(usr && usr.client) - usr.client.perspective = EYE_PERSPECTIVE - usr.client.eye = src - usr.loc = src - src.occupant = usr - /*for(var/obj/O in src) - O.loc = src.loc*/ - src.add_fingerprint(usr) + + user.stop_pulling() + if(user && user.client) + user.client.perspective = EYE_PERSPECTIVE + user.client.eye = src + user.forceMove(src) + occupant = user + + add_fingerprint(user) build_icon() - src.use_power = 2 - return \ No newline at end of file + update_use_power(1) + return + \ No newline at end of file diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm index 915def6bdda..11ec8837c87 100644 --- a/code/game/machinery/syndicatebeacon.dm +++ b/code/game/machinery/syndicatebeacon.dm @@ -87,7 +87,7 @@ M << "You have joined the ranks of the Syndicate and become a traitor to the station!" - message_admins("[N]/([N.ckey]) has accepted a traitor objective from a syndicate beacon.") + message_admins("[key_name_admin(N)] has accepted a traitor objective from a syndicate beacon.") var/obj_count = 1 for(var/datum/objective/OBJ in M.mind.objectives) diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index 7ad9f121d06..04a5d3e45dd 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -138,7 +138,7 @@ var/turf/bombturf = get_turf(src) var/area/A = get_area(bombturf) if(payload && !istype(payload, /obj/item/weapon/bombcore/training)) - msg_admin_attack("[key_name(user)][isAntag(user) ? "(ANTAG)" : ""]? has primed a [name] ([payload]) for detonation at [A.name] (JMP).") + msg_admin_attack("[key_name_admin(user)] has primed a [name] ([payload]) for detonation at [A.name] (JMP).") log_game("[key_name(user)] has primed a [name] ([payload]) for detonation at [A.name]([bombturf.x],[bombturf.y],[bombturf.z])") payload.adminlog = "The [src.name] that [key_name(user)] had primed detonated!" @@ -311,10 +311,9 @@ var/turf/T = get_turf(src) var/area/A = get_area(T) detonated-- - var/log_str = "[key_name(user)]? has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] (JMP)." - bombers += log_str - message_admins(log_str) - log_game("[key_name(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name]([T.x],[T.y],[T.z])") + message_admins("[key_name_admin(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] (JMP).") + bombers += "[key_name(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] ([T.x],[T.y],[T.z])" + log_game("[key_name(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] ([T.x],[T.y],[T.z])") detonated = 0 existant = 0 cooldown = 1 diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 3657410b400..f3b84e75f89 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -604,8 +604,9 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() if(istext(t)) rawcode = t -/obj/machinery/telecomms/server/proc/compile() +/obj/machinery/telecomms/server/proc/compile(mob/user as mob) if(Compiler) + admin_log(user) return Compiler.Compile(rawcode) /obj/machinery/telecomms/server/proc/update_logs() @@ -627,8 +628,13 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() log_entries.Add(log) update_logs() - - +/obj/machinery/telecomms/server/proc/admin_log(var/mob/mob) + var/msg="[key_name(mob)] has compiled a script to server [src]:" + diary << msg + diary << rawcode + src.investigate_log("[msg]
[rawcode]", "ntsl") + if(length(rawcode)) // Let's not bother the admins for empty code. + message_admins("[key_name_admin(mob)] has compiled and uploaded a NTSL script to [src.id] (JMP)") // Simple log entry datum diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index 90db7efaec9..9882151bb21 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -282,17 +282,22 @@ construction_time = 1200 construction_cost = list("metal"=30000,"plasma"=25000,"silver"=20000,"gold"=20000) var/mode = 0 //0 - deconstruct, 1 - wall or floor, 2 - airlock. - var/disabled = 0 //malf var/canRwall = 0 + + New() + rcd_list += src + ..() + + Destroy() + rcd_list -= src + ..() action(atom/target) - if(istype(target,/area/shuttle)||istype(target, /turf/space/transit))//>implying these are ever made -Sieve - disabled = 1 - else - disabled = 0 + if(istype(target, /turf/space/transit))//>implying these are ever made -Sieve + return if(!istype(target, /turf) && !istype(target, /obj/machinery/door/airlock)) target = get_turf(target) - if(!action_checks(target) || disabled || get_dist(chassis, target)>3) return + if(!action_checks(target) || get_dist(chassis, target)>3) return playsound(chassis, 'sound/machines/click.ogg', 50, 1) //meh switch(mode) @@ -303,7 +308,6 @@ occupant_message("Deconstructing [target]...") set_ready_state(0) if(do_after_cooldown(target)) - if(disabled) return chassis.spark_system.start() target:ChangeTurf(/turf/simulated/floor/plating) playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) @@ -312,7 +316,6 @@ occupant_message("Deconstructing [target]...") set_ready_state(0) if(do_after_cooldown(target)) - if(disabled) return chassis.spark_system.start() target:ChangeTurf(/turf/space) playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) @@ -321,7 +324,6 @@ occupant_message("Deconstructing [target]...") set_ready_state(0) if(do_after_cooldown(target)) - if(disabled) return chassis.spark_system.start() qdel(target) playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) @@ -331,7 +333,6 @@ occupant_message("Building Floor...") set_ready_state(0) if(do_after_cooldown(target)) - if(disabled) return target:ChangeTurf(/turf/simulated/floor/plating) playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) chassis.spark_system.start() @@ -340,7 +341,6 @@ occupant_message("Building Wall...") set_ready_state(0) if(do_after_cooldown(target)) - if(disabled) return target:ChangeTurf(/turf/simulated/wall) playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) chassis.spark_system.start() @@ -350,7 +350,6 @@ occupant_message("Building Airlock...") set_ready_state(0) if(do_after_cooldown(target)) - if(disabled) return chassis.spark_system.start() var/obj/machinery/door/airlock/T = new /obj/machinery/door/airlock(target) T.autoclose = 1 @@ -443,6 +442,8 @@ P.failchance = 0 P.icon_state = "anom" P.name = "wormhole" + message_admins("[key_name_admin(chassis.occupant, chassis.occupant.client)](?) (FLW) used a Wormhole Generator in ([T.x],[T.y],[T.z] - JMP)",0,1) + log_game("[key_name(chassis.occupant)] used a Wormhole Generator in ([T.x],[T.y],[T.z])") do_after_cooldown() src = null spawn(rand(150,300)) diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 1aec90c414f..1727a4f25fa 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -166,6 +166,9 @@ chassis.use_power(energy_drain) log_message("Honked from [src.name]. HONK!") + var/turf/T = get_turf(src) + message_admins("[key_name_admin(chassis.occupant, chassis.occupant.client)](?) (FLW) used a Mecha Honker in ([T.x],[T.y],[T.z] - JMP)",0,1) + log_game("[chassis.occupant.ckey]([chassis.occupant]) used a Mecha Honker in ([T.x],[T.y],[T.z])") do_after_cooldown() return @@ -238,6 +241,9 @@ sleep(2) set_ready_state(0) log_message("Fired from [src.name], targeting [target].") + var/turf/T = get_turf(src) + message_admins("[key_name(chassis.occupant, chassis.occupant.client)](?) fired a [src] in ([T.x],[T.y],[T.z] - JMP)",0,1) + log_game("[key_name(chassis.occupant)] fired a [src] ([T.x],[T.y],[T.z])") do_after_cooldown() return @@ -351,6 +357,9 @@ M.throw_at(target, missile_range, missile_speed, chassis) projectiles-- log_message("Fired from [src.name], targeting [target].") + var/turf/T = get_turf(src) + message_admins("[key_name(chassis.occupant, chassis.occupant.client)](?) (FLW) fired a [src] in ([T.x],[T.y],[T.z] - JMP)",0,1) + log_game("[key_name(chassis.occupant)] fired a [src] ([T.x],[T.y],[T.z])") do_after_cooldown() return diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm index 3f6b92c98ce..42837d06aba 100644 --- a/code/game/mecha/mech_bay.dm +++ b/code/game/mecha/mech_bay.dm @@ -13,8 +13,13 @@ temperature = TCMB /turf/simulated/floor/mech_bay_recharge_floor/Destroy() - recharge_console.recharge_floor = null - recharge_port.recharge_floor = null + if(recharge_console && recharge_console.recharge_floor == src) + recharge_console.recharge_floor = null + recharge_console = null + if(recharge_port && recharge_port.recharge_floor == src) + recharge_port.recharge_floor = null + recharge_port = null + recharging_mecha = null ..() /turf/simulated/floor/mech_bay_recharge_floor/Entered(var/obj/mecha/mecha) @@ -285,4 +290,4 @@ // open the new ui window ui.open() // auto update every Master Controller tick - ui.set_auto_update(1) + ui.set_auto_update(1) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 27fe49e746d..b812cab95bd 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -96,11 +96,6 @@ mechas_list += src //global mech list return -/obj/mecha/Destroy() - src.go_out() - mechas_list -= src //global mech list - return ..() - //////////////////////// ////// Helpers ///////// //////////////////////// @@ -615,50 +610,65 @@ return /obj/mecha/proc/destroy() - spawn() - go_out() - var/turf/T = get_turf(src) - tag = "\ref[src]" //better safe then sorry - if(loc) - loc.Exited(src) - loc = null - if(T) - if(istype(src, /obj/mecha/working/ripley/)) - var/obj/mecha/working/ripley/R = src - if(R.cargo) - for(var/obj/O in R.cargo) //Dump contents of stored cargo - O.loc = T - R.cargo -= O - T.Entered(O) + go_out() + for(var/mob/M in src) //Let's just be ultra sure + if(isAI(M)) + M.gib() //AIs are loaded into the mech computer itself. When the mech dies, so does the AI. Forever. + else + M.Move(loc) + + if(prob(30)) + explosion(get_turf(loc), 0, 0, 1, 3) + + if(istype(src, /obj/mecha/working/ripley/)) + var/obj/mecha/working/ripley/R = src + if(R.cargo) + for(var/obj/O in R.cargo) //Dump contents of stored cargo + O.loc = loc + R.cargo -= O + loc.Entered(O) - if(prob(30)) - explosion(get_turf(loc), 0, 0, 1, 3) - spawn(0) - if(wreckage) - var/obj/effect/decal/mecha_wreckage/WR = new wreckage(T) - for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) - if(E.salvageable && prob(30)) - WR.crowbar_salvage += E - E.forceMove(WR) - E.equip_ready = 1 - E.reliability = round(rand(E.reliability/3,E.reliability)) - else - E.forceMove(T) - E.destroy() - if(cell) - WR.crowbar_salvage += cell - cell.forceMove(WR) - cell.charge = rand(0, cell.charge) - if(internal_tank) - WR.crowbar_salvage += internal_tank - internal_tank.forceMove(WR) - else - for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) - E.forceMove(T) - E.destroy() - spawn(0) - qdel(src) - return + if(wreckage) + var/obj/effect/decal/mecha_wreckage/WR = new wreckage(loc) + for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) + if(E.salvageable && prob(30)) + WR.crowbar_salvage += E + E.forceMove(WR) + E.equip_ready = 1 + E.reliability = round(rand(E.reliability/3,E.reliability)) + else + E.forceMove(loc) + E.destroy() + if(cell) + WR.crowbar_salvage += cell + cell.forceMove(WR) + cell.charge = rand(0, cell.charge) + if(internal_tank) + WR.crowbar_salvage += internal_tank + internal_tank.forceMove(WR) + else + for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) + E.forceMove(loc) + E.destroy() + if(cell) + qdel(cell) + if(internal_tank) + qdel(internal_tank) + equipment.Cut() + cell = null + internal_tank = null + + qdel(pr_int_temp_processor) + qdel(pr_give_air) + qdel(pr_internal_damage) + qdel(spark_system) + pr_int_temp_processor = null + pr_give_air = null + pr_internal_damage = null + spark_system = null + + mechas_list -= src //global mech list + return ..() /obj/mecha/ex_act(severity) src.log_message("Affected by explosion of severity: [severity].",1) @@ -916,16 +926,92 @@ return -/* +///////////////////////////////////// +//////////// AI piloting //////////// +///////////////////////////////////// + /obj/mecha/attack_ai(var/mob/living/silicon/ai/user as mob) - if(!istype(user, /mob/living/silicon/ai)) + if(!isAI(user)) return - var/output = {"Assume direct control over [src]? - Yes
- "} - user << browse(output, "window=mecha_attack_ai") - return -*/ + //Allows the Malf to scan a mech's status and loadout, helping it to decide if it is a worthy chariot. + if(user.can_dominate_mechs) + examine(user) //Get diagnostic information! + var/obj/item/mecha_parts/mecha_tracking/B = locate(/obj/item/mecha_parts/mecha_tracking) in src + if(B) //Beacons give the AI more detailed mech information. + user << "Warning: Tracking Beacon detected. Enter at your own risk. Beacon Data:" + user << "[B.get_mecha_info()]" + //Nothing like a big, red link to make the player feel powerful! + user << "ASSUME DIRECT CONTROL?
" + +/obj/mecha/transfer_ai(var/interaction, mob/user, var/mob/living/silicon/ai/AI, var/obj/item/device/aicard/card) + if(!..()) + return + + //Transfer from core or card to mech. Proc is called by mech. + switch(interaction) + if(AI_TRANS_TO_CARD) //Upload AI from mech to AI card. + if(!maint_access) //Mech must be in maint mode to allow carding. + user << "[name] must have maintenance protocols active in order to allow a transfer." + return + AI = occupant + if(!AI || !isAI(occupant)) //Mech does not have an AI for a pilot + user << "No AI detected in the [name] onboard computer." + return + if (AI.mind.special_role == "malfunction") //Malf AIs cannot leave mechs. Except through death. + user << "ACCESS DENIED." + return + AI.aiRestorePowerRoutine = 0//So the AI initially has power. + AI.control_disabled = 1 + AI.aiRadio.disabledAi = 1 + AI.loc = card + occupant = null + AI.controlled_mech = null + AI.remote_control = null + icon_state = initial(icon_state)+"-open" + AI << "You have been downloaded to a mobile storage device. Wireless connection offline." + user << "Transfer successful: [AI.name] ([rand(1000,9999)].exe) removed from [name] and stored within local memory." + + if(AI_MECH_HACK) //Called by Malf AI mob on the mech. + new /obj/structure/AIcore/deactivated(AI.loc) + if(occupant) //Oh, I am sorry, were you using that? + AI << "Pilot detected! Forced ejection initiated!" + occupant << "You have been forcibly ejected!" + go_out(1) //IT IS MINE, NOW. SUCK IT, RD! + ai_enter_mech(AI, interaction) + + if(AI_TRANS_FROM_CARD) //Using an AI card to upload to a mech. + AI = locate(/mob/living/silicon/ai) in card + if(!AI) + user << "There is no AI currently installed on this device." + return + else if(AI.stat || !AI.client) + user << "[AI.name] is currently unresponsive, and cannot be uploaded." + return + else if(occupant || dna) //Normal AIs cannot steal mechs! + user << "Access denied. [name] is [occupant ? "currently occupied" : "secured with a DNA lock"]." + return + AI.control_disabled = 0 + AI.aiRadio.disabledAi = 0 + user << "Transfer successful: [AI.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed." + ai_enter_mech(AI, interaction) + +//Hack and From Card interactions share some code, so leave that here for both to use. +/obj/mecha/proc/ai_enter_mech(var/mob/living/silicon/ai/AI, var/interaction) + AI.aiRestorePowerRoutine = 0 + AI.loc = src + occupant = AI + icon_state = initial(icon_state) + playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) + if(!hasInternalDamage()) + occupant << sound('sound/mecha/nominal.ogg',volume=50) + AI.cancel_camera() + AI.controlled_mech = src + AI.remote_control = src + AI.canmove = 1 //Much easier than adding AI checks! Be sure to set this back to 0 if you decide to allow an AI to leave a mech somehow. + AI.can_shunt = 0 //ONE AI ENTERS. NO AI LEAVES. + AI << "[interaction == AI_MECH_HACK ? "Takeover of [name] complete! You are now permanently loaded onto the onboard computer. Do not attempt to leave the station sector!" \ + : "You have been uploaded to a mech's onboard computer."]" + AI << "Use Middle-Mouse to activate mech functions and equipment. Click normally for AI interactions." ///////////////////////////////////// //////// Atmospheric stuff //////// @@ -1228,7 +1314,7 @@ return -/obj/mecha/proc/go_out() +/obj/mecha/proc/go_out(var/forced) if(!src.occupant) return var/atom/movable/mob_container if(ishuman(occupant)) @@ -1236,6 +1322,10 @@ else if(istype(occupant, /mob/living/carbon/brain)) var/mob/living/carbon/brain/brain = occupant mob_container = brain.container + else if(isAI(occupant) && forced) //This should only happen if there are multiple AIs in a round, and at least one is Malf. + occupant.gib() //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced. + occupant = null + return else return if(mob_container.forceMove(src.loc))//ejecting mob container @@ -1677,13 +1767,13 @@ user << browse(null,"window=exosuit_add_access") return if(href_list["dna_lock"]) - if(usr != src.occupant) return - if(istype(occupant, /mob/living/carbon/brain)) - occupant_message("You are a brain. No.") + if(usr != src.occupant) return - if(src.occupant) - src.dna = src.occupant.dna.unique_enzymes - src.occupant_message("You feel a prick as the needle takes your DNA sample.") + if(src.occupant && !iscarbon(src.occupant)) + src.occupant << "You do not have any DNA!" + return + src.dna = src.occupant.dna.unique_enzymes + src.occupant_message("You feel a prick as the needle takes your DNA sample.") return if(href_list["reset_dna"]) if(usr != src.occupant) return @@ -1712,54 +1802,6 @@ return */ - - -/* - - if (href_list["ai_take_control"]) - var/mob/living/silicon/ai/AI = locate(href_list["ai_take_control"]) - var/duration = text2num(href_list["duration"]) - var/mob/living/silicon/ai/O = new /mob/living/silicon/ai(src) - var/cur_occupant = src.occupant - O.invisibility = 0 - O.canmove = 1 - O.name = AI.name - O.real_name = AI.real_name - O.anchored = 1 - O.aiRestorePowerRoutine = 0 - O.control_disabled = 1 // Can't control things remotely if you're stuck in a card! - O.laws = AI.laws - O.stat = AI.stat - O.oxyloss = AI.getOxyLoss() - O.fireloss = AI.getFireLoss() - O.bruteloss = AI.getBruteLoss() - O.toxloss = AI.toxloss - O.updatehealth() - src.occupant = O - if(AI.mind) - AI.mind.transfer_to(O) - AI.name = "Inactive AI" - AI.real_name = "Inactive AI" - AI.icon_state = "ai-empty" - spawn(duration) - AI.name = O.name - AI.real_name = O.real_name - if(O.mind) - O.mind.transfer_to(AI) - AI.control_disabled = 0 - AI.laws = O.laws - AI.oxyloss = O.getOxyLoss() - AI.fireloss = O.getFireLoss() - AI.bruteloss = O.getBruteLoss() - AI.toxloss = O.toxloss - AI.updatehealth() - del(O) - if (!AI.stat) - AI.icon_state = "ai" - else - AI.icon_state = "ai-crash" - src.occupant = cur_occupant -*/ return /////////////////////// diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm index 036872780b2..ce44f2e59b1 100644 --- a/code/game/mecha/mecha_control_console.dm +++ b/code/game/mecha/mecha_control_console.dm @@ -5,64 +5,66 @@ icon_screen = "mecha" light_color = LIGHT_COLOR_FADEDPURPLE req_access = list(access_robotics) - circuit = "/obj/item/weapon/circuitboard/mecha_control" + circuit = /obj/item/weapon/circuitboard/mecha_control var/list/located = list() var/screen = 0 var/stored_data - attack_ai(var/mob/user as mob) - return src.attack_hand(user) +/obj/machinery/computer/mecha/attack_ai(var/mob/user as mob) + return attack_hand(user) - attack_hand(var/mob/user as mob) - if(..()) - return - user.set_machine(src) - var/dat = "[src.name]" - if(screen == 0) - dat += "

Tracking beacons data

" - for(var/obj/item/mecha_parts/mecha_tracking/TR in world) - var/answer = TR.get_mecha_info() - if(answer) - dat += {"
[answer]
- Send message
- Show exosuit log | (EMP pulse)
"} +/obj/machinery/computer/mecha/attack_hand(var/mob/user as mob) + ui_interact(user) + +/obj/machinery/computer/mecha/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["screen"] = screen + if(screen == 0) + var/list/mechas[0] + for(var/obj/item/mecha_parts/mecha_tracking/TR in world) + var/answer = TR.get_mecha_info() + if(answer) + mechas[++mechas.len] = answer + data["mechas"] = mechas + if(screen == 1) + data["log"] = stored_data - if(screen==1) - dat += "

Log contents

" - dat += "Return
" - dat += "[stored_data]" - - dat += "(Refresh)
" - dat += "" - - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") - return - - Topic(href, href_list) - if(..()) - return - var/datum/topic_input/filter = new /datum/topic_input(href,href_list) - if(href_list["send_message"]) - var/obj/item/mecha_parts/mecha_tracking/MT = filter.getObj("send_message") - var/message = strip_html_simple(input(usr,"Input message","Transmit message") as text) - var/obj/mecha/M = MT.in_mecha() - if(trim(message) && M) - M.occupant_message(message) - return - if(href_list["shock"]) - var/obj/item/mecha_parts/mecha_tracking/MT = filter.getObj("shock") - MT.shock() - if(href_list["get_log"]) - var/obj/item/mecha_parts/mecha_tracking/MT = filter.getObj("get_log") - stored_data = MT.get_mecha_log() - screen = 1 - if(href_list["return"]) - screen = 0 - src.updateUsrDialog() - return + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "exosuit_control.tmpl", "Exosuit Control Console", 420, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) +/obj/machinery/computer/mecha/Topic(href, href_list) + if(..()) + return 1 + + var/datum/topic_input/filter = new /datum/topic_input(href,href_list) + if(href_list["send_message"]) + var/obj/item/mecha_parts/mecha_tracking/MT = filter.getObj("send_message") + var/message = strip_html_simple(input(usr,"Input message","Transmit message") as text) + if(!trim(message) || ..()) + return 1 + var/obj/mecha/M = MT.in_mecha() + if(M) + M.occupant_message(message) + + if(href_list["shock"]) + var/obj/item/mecha_parts/mecha_tracking/MT = filter.getObj("shock") + MT.shock() + + if(href_list["get_log"]) + var/obj/item/mecha_parts/mecha_tracking/MT = filter.getObj("get_log") + stored_data = MT.get_mecha_log() + screen = 1 + + if(href_list["return"]) + screen = 0 + + nanomanager.update_uis(src) + return /obj/item/mecha_parts/mecha_tracking name = "Exosuit tracking beacon" @@ -73,49 +75,57 @@ construction_time = 50 construction_cost = list("metal"=500) - proc/get_mecha_info() - if(!in_mecha()) - return 0 - var/obj/mecha/M = src.loc - var/cell_charge = M.get_charge() - var/answer = {"Name: [M.name]
- Integrity: [M.health/initial(M.health)*100]%
- Cell charge: [isnull(cell_charge)?"Not found":"[M.cell.percent()]%"]
- Airtank: [M.return_pressure()]kPa
- Pilot: [M.occupant||"None"]
- Location: [get_area(M)||"Unknown"]
- Active equipment: [M.selected||"None"]"} - if(istype(M, /obj/mecha/working/ripley)) - var/obj/mecha/working/ripley/RM = M - answer += "Used cargo space: [RM.cargo.len/RM.cargo_capacity*100]%
" - - return answer - - emp_act() - qdel(src) - return - - ex_act() - qdel(src) - return - - proc/in_mecha() - if(istype(src.loc, /obj/mecha)) - return src.loc +/obj/item/mecha_parts/mecha_tracking/proc/get_mecha_info() + if(!in_mecha()) return 0 + var/obj/mecha/M = src.loc + var/list/answer[0] + answer["reference"] = "\ref[src]" + answer["name"] = sanitize(replacetext(M.name,"\"","'")) // Double apostrophes break JSON + if(M.cell) + answer["cell"] = 1 + answer["cell_capacity"] = M.cell.maxcharge + answer["cell_current"] = M.get_charge() + answer["cell_percentage"] = round(M.cell.percent()) + else + answer["cell"] = 0 + answer["integrity"] = M.health/initial(M.health)*100 + answer["airtank"] = M.return_pressure() + answer["pilot"] = "[M.occupant||"None"]" + var/area/area = get_area(M) + answer["location"] = "[sanitize(area.name)||"Unknown"]" + answer["equipment"] = "[M.selected||"None"]" + if(istype(M, /obj/mecha/working/ripley)) + var/obj/mecha/working/ripley/RM = M + answer["hascargo"] = 1 + answer["cargo"] = RM.cargo.len/RM.cargo_capacity*100 + + return answer - proc/shock() - var/obj/mecha/M = in_mecha() - if(M) - M.emp_act(2) - qdel(src) +/obj/item/mecha_parts/mecha_tracking/emp_act() + qdel(src) + return - proc/get_mecha_log() - if(!src.in_mecha()) - return 0 - var/obj/mecha/M = src.loc - return M.get_log_html() +/obj/item/mecha_parts/mecha_tracking/ex_act() + qdel(src) + return +/obj/item/mecha_parts/mecha_tracking/proc/in_mecha() + if(istype(src.loc, /obj/mecha)) + return src.loc + return 0 + +/obj/item/mecha_parts/mecha_tracking/proc/shock() + var/obj/mecha/M = in_mecha() + if(M) + M.emp_act(2) + qdel(src) + +/obj/item/mecha_parts/mecha_tracking/proc/get_mecha_log() + if(!src.in_mecha()) + return 0 + var/obj/mecha/M = src.loc + return M.get_log_html() /obj/item/weapon/storage/box/mechabeacons name = "Exosuit Tracking Beacons" diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index 6d01d970b31..329cbe8c152 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -483,7 +483,7 @@ steam.start() -- spawns the effect var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) var/more = "" if(M) - more = "(?)" + more = " " msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1) log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") else diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 6e8df50c0e7..842fa1edb45 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -599,10 +599,10 @@ user << "\red You cannot locate any eyes on this creature!" return - user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" - M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" + user.attack_log += "\[[time_stamp()]\] Attacked [key_name(M)] with [src.name] (INTENT: [uppertext(user.a_intent)])" + M.attack_log += "\[[time_stamp()]\] Attacked by [key_name(user)] with [src.name] (INTENT: [uppertext(user.a_intent)])" if(M.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") //BS12 EDIT ALG + msg_admin_attack("[key_name_admin(user)] attacked [key_name_admin(M)] with [src.name] (INTENT: [uppertext(user.a_intent)])") //BS12 EDIT ALG if(!iscarbon(user)) M.LAssailant = null diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index ff16cf9e43c..e2c0ddf1df0 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -5,129 +5,138 @@ item_state = "electronic" w_class = 2.0 slot_flags = SLOT_BELT + flags = NOBLUDGEON var/flush = null origin_tech = "programming=4;materials=4" - attack(mob/living/silicon/ai/M as mob, mob/user as mob) - if(!istype(M, /mob/living/silicon/ai))//If target is not an AI. - return ..() - - M.attack_log += text("\[[time_stamp()]\] Has been carded with [src.name] by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to card [M.name] ([M.ckey])") - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] used the [src.name] to card [M.name] ([M.ckey]) (JMP)") - - transfer_ai("AICORE", "AICARD", M, user) +/obj/item/device/aicard/afterattack(atom/target, mob/user, proximity) + ..() + if(!proximity || !target) return + var/mob/living/silicon/ai/AI = locate(/mob/living/silicon/ai) in src + if(AI) //AI is on the card, implies user wants to upload it. + target.transfer_ai(AI_TRANS_FROM_CARD, user, AI, src) + add_logs(AI,user, "carded", object="[name]") + else //No AI on the card, therefore the user wants to download one. + target.transfer_ai(AI_TRANS_TO_CARD, user, null, src) + update_state() //Whatever happened, update the card's state (icon, name) to match. - attack(mob/living/silicon/decoy/M as mob, mob/user as mob) - if (!istype (M, /mob/living/silicon/decoy)) - return ..() +/obj/item/device/aicard/proc/update_state() + var/mob/living/silicon/ai/AI = locate(/mob/living/silicon/ai) in src //AI is inside. + if(AI) + name = "intelliCard - [AI.name]" + if (AI.stat == DEAD) + icon_state = "aicard-404" else - M.death() - user << "ERROR ERROR ERROR" + icon_state = "aicard-full" + AI.cancel_camera() //AI are forced to move when transferred, so do this whenver one is downloaded. + else + icon_state = "aicard" + name = "intelliCard" + overlays.Cut() + +/obj/item/device/aicard/attack_self(mob/user) + if (!in_range(src, user)) + return + user.set_machine(src) + var/dat = "Intelicard
" + var/laws + for(var/mob/living/silicon/ai/A in src) + dat += "Stored AI: [A.name]
System integrity: [(A.health+100)/2]%
" - attack_self(mob/user) - if (!in_range(src, user)) - return - user.set_machine(src) - var/dat = "Intelicard
" - var/laws - for(var/mob/living/silicon/ai/A in src) - dat += "Stored AI: [A.name]
System integrity: [(A.health+100)/2]%
" + for (var/index = 1, index <= A.laws.ion.len, index++) + var/law = A.laws.ion[index] + if (length(law) > 0) + var/num = ionnum() + laws += "[num]. [law]" - for (var/index = 1, index <= A.laws.ion.len, index++) - var/law = A.laws.ion[index] - if (length(law) > 0) - var/num = ionnum() - laws += "[num]. [law]" + if (A.laws.zeroth) + laws += "0: [A.laws.zeroth]
" - if (A.laws.zeroth) - laws += "0: [A.laws.zeroth]
" + var/number = 1 + for (var/index = 1, index <= A.laws.inherent.len, index++) + var/law = A.laws.inherent[index] + if (length(law) > 0) + laws += "[number]: [law]
" + number++ - var/number = 1 - for (var/index = 1, index <= A.laws.inherent.len, index++) - var/law = A.laws.inherent[index] - if (length(law) > 0) - laws += "[number]: [law]
" - number++ + for (var/index = 1, index <= A.laws.supplied.len, index++) + var/law = A.laws.supplied[index] + if (length(law) > 0) + laws += "[number]: [law]
" + number++ - for (var/index = 1, index <= A.laws.supplied.len, index++) - var/law = A.laws.supplied[index] - if (length(law) > 0) - laws += "[number]: [law]
" - number++ + dat += "Laws:
[laws]
" - dat += "Laws:
[laws]
" - - if (A.stat == 2) - dat += "AI nonfunctional" + if (A.stat == 2) + dat += "AI nonfunctional" + else + if (!src.flush) + dat += {"Wipe AI"} else - if (!src.flush) - dat += {"Wipe AI"} - else - dat += "Wipe in progress" - dat += "
" - dat += {"[A.control_disabled ? "Enable" : "Disable"] Wireless Activity"} - dat += "
" - dat += "Subspace Transceiver is: [A.aiRadio.disabledAi ? "Disabled" : "Enabled"]" - dat += "
" - dat += {"[A.aiRadio.disabledAi ? "Enable" : "Disable"] Subspace Transceiver"} - dat += "
" - dat += {" Close"} - user << browse(dat, "window=aicard") - onclose(user, "aicard") + dat += "Wipe in progress" + dat += "
" + dat += {"[A.control_disabled ? "Enable" : "Disable"] Wireless Activity"} + dat += "
" + dat += "Subspace Transceiver is: [A.aiRadio.disabledAi ? "Disabled" : "Enabled"]" + dat += "
" + dat += {"[A.aiRadio.disabledAi ? "Enable" : "Disable"] Subspace Transceiver"} + dat += "
" + dat += {" Close"} + user << browse(dat, "window=aicard") + onclose(user, "aicard") + return + +/obj/item/device/aicard/Topic(href, href_list) + var/mob/U = usr + if (!in_range(src, U)||U.machine!=src)//If they are not in range of 1 or less or their machine is not the card (ie, clicked on something else). + U << browse(null, "window=aicard") + U.unset_machine() return - Topic(href, href_list) - var/mob/U = usr - if (!in_range(src, U)||U.machine!=src)//If they are not in range of 1 or less or their machine is not the card (ie, clicked on something else). + add_fingerprint(U) + U.set_machine(src) + + switch(href_list["choice"])//Now we switch based on choice. + if ("Close") U << browse(null, "window=aicard") U.unset_machine() return - add_fingerprint(U) - U.set_machine(src) + if ("Wipe") + var/confirm = alert("Are you sure you want to wipe this card's memory? This cannot be undone once started.", "Confirm Wipe", "Yes", "No") + if(confirm == "Yes") + if(isnull(src)||!in_range(src, U)||U.machine!=src) + U << browse(null, "window=aicard") + U.unset_machine() + return + else + flush = 1 + for(var/mob/living/silicon/ai/A in src) + A.suiciding = 1 + A << "Your core files are being wiped!" + while (A.stat != 2) + A.adjustOxyLoss(2) + A.updatehealth() + sleep(10) + flush = 0 - switch(href_list["choice"])//Now we switch based on choice. - if ("Close") - U << browse(null, "window=aicard") - U.unset_machine() - return + if ("Radio") + for(var/mob/living/silicon/ai/A in src) + A.aiRadio.disabledAi = !A.aiRadio.disabledAi + A << "Your Subspace Transceiver has been: [A.aiRadio.disabledAi ? "disabled" : "enabled"]" + U << "You [A.aiRadio.disabledAi ? "Disable" : "Enable"] the AI's Subspace Transceiver" - if ("Wipe") - var/confirm = alert("Are you sure you want to wipe this card's memory? This cannot be undone once started.", "Confirm Wipe", "Yes", "No") - if(confirm == "Yes") - if(isnull(src)||!in_range(src, U)||U.machine!=src) - U << browse(null, "window=aicard") - U.unset_machine() - return - else - flush = 1 - for(var/mob/living/silicon/ai/A in src) - A.suiciding = 1 - A << "Your core files are being wiped!" - while (A.stat != 2) - A.adjustOxyLoss(2) - A.updatehealth() - sleep(10) - flush = 0 - - if ("Radio") - for(var/mob/living/silicon/ai/A in src) - A.aiRadio.disabledAi = !A.aiRadio.disabledAi - A << "Your Subspace Transceiver has been: [A.aiRadio.disabledAi ? "disabled" : "enabled"]" - U << "You [A.aiRadio.disabledAi ? "Disable" : "Enable"] the AI's Subspace Transceiver" - - if ("Wireless") - for(var/mob/living/silicon/ai/A in src) - A.control_disabled = !A.control_disabled - A << "The intelicard's wireless port has been [A.control_disabled ? "disabled" : "enabled"]!" - if (A.control_disabled) - overlays -= image('icons/obj/aicards.dmi', "aicard-on") - else - overlays += image('icons/obj/aicards.dmi', "aicard-on") - attack_self(U) + if ("Wireless") + for(var/mob/living/silicon/ai/A in src) + A.control_disabled = !A.control_disabled + A << "The intelicard's wireless port has been [A.control_disabled ? "disabled" : "enabled"]!" + if (A.control_disabled) + overlays -= image('icons/obj/aicards.dmi', "aicard-on") + else + overlays += image('icons/obj/aicards.dmi', "aicard-on") + attack_self(U) /obj/item/device/aicard/ex_act(severity) switch(severity) diff --git a/code/game/objects/items/devices/pizza_bomb.dm b/code/game/objects/items/devices/pizza_bomb.dm index 9a3180a15e8..1f1b362078d 100644 --- a/code/game/objects/items/devices/pizza_bomb.dm +++ b/code/game/objects/items/devices/pizza_bomb.dm @@ -30,7 +30,7 @@ timer = Clamp(timer, 10, 100) icon_state = "pizzabox1" user << "You set the timer to [timer / 10] before activating the payload and closing \the [src]." - message_admins("[key_name(usr)]? has set a timer on a pizza bomb to [timer/10] seconds at (JMP).") + message_admins("[key_name_admin(usr)] has set a timer on a pizza bomb to [timer/10] seconds at (JMP).") log_game("[key_name(usr)] has set the timer on a pizza bomb to [timer/10] seconds ([loc.x],[loc.y],[loc.z]).") armer = usr name = "pizza box" @@ -42,7 +42,7 @@ icon_state = "pizzabox_bomb" audible_message("\icon[src] *beep* *beep*") user << "That's no pizza! That's a bomb!" - message_admins("[key_name(usr)]? has triggered a pizza bomb armed by [armer] at (JMP).") + message_admins("[key_name_admin(usr)] has triggered a pizza bomb armed by [armer] at (JMP).") log_game("[key_name(usr)] has triggered a pizza bomb armed by [armer] ([loc.x],[loc.y],[loc.z]).") primed = 1 sleep(timer) diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 7db62612994..ab61e766c91 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -42,6 +42,8 @@ anchored = 1 mode = 1 src.visible_message("[user] attaches [src] to the cable!") + message_admins("Power sink activated by [key_name_admin(user)] at ([x],[y],[z] - JMP)") + log_game("Power sink activated by [key_name(user)] at ([x],[y],[z])") return else user << "Device must be placed over an exposed cable to attach to it." diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 2f23f8d47ba..82402e273c9 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -72,7 +72,7 @@ REAGENT SCANNER spawn(pulse_duration) if(O) var/turf/U = O.loc - if(U.intact) + if(U && U.intact) O.invisibility = 101 O.alpha = 255 for(var/mob/living/M in T.contents) @@ -137,12 +137,9 @@ REAGENT SCANNER user.show_message("\blue Key: Suffocation/Toxin/Burns/Brute", 1) user.show_message("\blue Body Temperature: ???", 1) return - if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - usr << "\red You don't have the dexterity to do this!" - return - user.visible_message(" [user] has analyzed [M]'s vitals."," You have analyzed [M]'s vitals.") + user.visible_message("[user] has analyzed [M]'s vitals."," You have analyzed [M]'s vitals.") - if (!istype(M, /mob/living/carbon) || (ishuman(M) && (M:species.flags & IS_SYNTHETIC))) + if (!istype(M,/mob/living/carbon/human) || M.isSynthetic()) //these sensors are designed for organic life user.show_message("\blue Analyzing Results for ERROR:\n\t Overall Status: ERROR") user.show_message("\t Key: Suffocation/Toxin/Burns/Brute", 1) diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index ee4f96b9230..a533efe0a58 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -51,7 +51,7 @@ A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb). bombers += "[key_name(user)] attached a [item] to a transfer valve." - msg_admin_attack("[key_name_admin(user)][isAntag(user) ? "(ANTAG)" : ""] attached [item] to a transfer valve.") + msg_admin_attack("[key_name_admin(user)]attached [item] to a transfer valve.") log_game("[key_name_admin(user)] attached [item] to a transfer valve.") attacher = user nanomanager.update_uis(src) // update all UIs attached to src @@ -179,23 +179,13 @@ if(!attacher) attacher_name = "Unknown" else - attacher_name = "[attacher.name]([attacher.ckey])" - - var/log_str = "Bomb valve opened in [A.name] " - log_str += "with [attached_device ? attached_device : "no device"] attacher: [attacher_name]" - - if(attacher) - log_str += "(?)" + attacher_name = "[key_name_admin(attacher)]" var/mob/mob = get_mob_by_key(src.fingerprintslast) - var/last_touch_info = "" - if(mob) - last_touch_info = "(?)" - - log_str += " Last touched by: [src.fingerprintslast][last_touch_info]" - bombers += log_str - msg_admin_attack(log_str, 0, 1) - log_game(log_str) + + bombers += "Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]" + message_admins("Bomb valve opened at [A.name] (JMP) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name_admin(mob)]") + log_game("Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]") merge_gases() spawn(20) // In case one tank bursts for (var/i=0,i<5,i++) diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm index 4efc8bdc2ee..28c573be0bb 100644 --- a/code/game/objects/items/devices/uplinks.dm +++ b/code/game/objects/items/devices/uplinks.dm @@ -50,10 +50,10 @@ var/list/world_uplinks = list() job = user.mind.assigned_role var/dat = "[src.welcome]
" - dat += "Tele-Crystals left: [src.uses]
" + dat += "Telecrystals left: [src.uses]
" dat += "
" dat += "Request item:
" - dat += "Each item costs a number of tele-crystals as indicated by the number following their name.
" + dat += "Each item costs a number of telecrystals as indicated by the number following their name.
" var/category_items = 1 for(var/category in ItemsCategory) @@ -262,10 +262,6 @@ var/list/world_uplinks = list() for(var/datum/data/record/L in data_core.general) if(L.fields["id"] == id) nanoui_data["exploit"] = list() // Setting this to equal L.fields passes it's variables that are lists as reference instead of value. - // We trade off being able to automatically add shit for more control over what gets passed to json - // and if it's sanitized for html. - nanoui_data["exploit"]["nanoui_exploit_record"] = html_encode(L.fields["exploit_record"]) // Change stuff into html - nanoui_data["exploit"]["nanoui_exploit_record"] = replacetext(nanoui_data["exploit"]["nanoui_exploit_record"], "\n", "
") // change line breaks into
nanoui_data["exploit"]["name"] = html_encode(L.fields["name"]) nanoui_data["exploit"]["sex"] = html_encode(L.fields["sex"]) nanoui_data["exploit"]["age"] = html_encode(L.fields["age"]) diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index d8baba60d41..3d496ca3b86 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -10,10 +10,10 @@ icon_state = "shock" attack(mob/M as mob, mob/living/silicon/robot/user as mob) - 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])") + M.attack_log += text("\[[time_stamp()]\] Has been attacked with [src.name] by [key_name(user)]") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to attack [key_name(M)]") if(M.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] used the [src.name] to attack [M.name] ([M.ckey]) (JMP)") + msg_admin_attack("[key_name_admin(user)] used the [src.name] to attack [key_name_admin(M)]") if(!iscarbon(user)) M.LAssailant = null diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index fd8963f9b02..79cbe026503 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -66,6 +66,7 @@ name = "torso" desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell." icon_state = "chest" + part = list("groin","chest") construction_time = 350 construction_cost = list("metal"=40000) var/wires = 0.0 @@ -75,6 +76,7 @@ name = "head" desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals." icon_state = "head" + part = list("head") construction_time = 350 construction_cost = list("metal"=5000) var/obj/item/device/flash/flash1 = null diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index b6bc04227a7..9b7888c9bcb 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -1057,7 +1057,7 @@ obj/item/toy/cards/deck/syndicate/black /obj/item/toy/minimeteor name = "Mini-Meteor" - desc = "Relive the excitement of a meteor shower! SweetMeat-eor. Co is not responsible for any injuries, headaches or hearing loss caused by Mini-Meteor™" + desc = "Relive the excitement of a meteor shower! SweetMeat-eor. Co is not responsible for any injuries, headaches or hearing loss caused by Mini-Meteor™" icon = 'icons/obj/toy.dmi' icon_state = "minimeteor" w_class = 2.0 @@ -1183,7 +1183,7 @@ obj/item/toy/cards/deck/syndicate/black if(!cooldown) //for the sanity of everyone var/message = pick("You won't get away this time, Griffin!", "Stop right there, criminal!", "Hoot! Hoot!", "I am the night!") user << "You pull the string on the [src]." - playsound(user, 'sound/machines/click.ogg', 20, 1) + playsound(user, 'sound/misc/hoot.ogg', 25, 1) src.loc.visible_message("\icon[src] [message]") cooldown = 1 spawn(30) cooldown = 0 @@ -1202,7 +1202,7 @@ obj/item/toy/cards/deck/syndicate/black if(!cooldown) //for the sanity of everyone var/message = pick("You can't stop me, Owl!", "My plan is flawless! The vault is mine!", "Caaaawwww!", "You will never catch me!") user << "You pull the string on the [src]." - playsound(user, 'sound/machines/click.ogg', 20, 1) + playsound(user, 'sound/misc/caw.ogg', 25, 1) src.loc.visible_message("\icon[src] [message]") cooldown = 1 spawn(30) cooldown = 0 @@ -1319,4 +1319,4 @@ obj/item/toy/cards/deck/syndicate/black stored_minature = O else user << "You stop feeding \the [O] into \the [src]'s mini-input." - else ..() \ No newline at end of file + else ..() diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index 24788c42a0e..2d788e219a4 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -26,16 +26,20 @@ RCD var/working = 0 var/mode = 1 var/canRwall = 0 - var/disabled = 0 - New() desc = "A RCD. It currently holds [matter]/[max_matter] matter-units." src.spark_system = new /datum/effect/effect/system/spark_spread spark_system.set_up(5, 0, src) spark_system.attach(src) + rcd_list += src return - + + Destroy() + qdel(spark_system) + spark_system = null + rcd_list -= src + return ..() attackby(obj/item/weapon/W, mob/user, params) ..() @@ -82,8 +86,6 @@ RCD afterattack(atom/A, mob/user, proximity) if(!proximity) return - if(disabled && !isrobot(user)) - return 0 if(istype(A,/area/shuttle)||istype(A,/turf/space/transit)) return 0 if(!(istype(A, /turf) || istype(A, /obj/machinery/door/airlock))) diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index b092d31e6d9..c698dc70c10 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -88,6 +88,7 @@ var/access = list() var/registered_name = "Unknown" // The name registered_name on the card slot_flags = SLOT_ID + var/untrackable // Can not be tracked by AI's var/blood_type = "\[UNSET\]" var/dna_hash = "\[UNSET\]" @@ -172,6 +173,9 @@ /obj/item/weapon/card/id/GetID() return src + +/obj/item/weapon/card/id/proc/is_untrackable() + return untrackable /obj/item/weapon/card/id/attackby(obj/item/weapon/W as obj, mob/user as mob, params) ..() @@ -213,6 +217,7 @@ var/list/initial_access = list(access_maint_tunnels, access_syndicate, access_external_airlocks) origin_tech = "syndicate=3" var/registered_user = null + untrackable = 1 /obj/item/weapon/card/id/syndicate/New() access = initial_access.Copy() @@ -429,6 +434,7 @@ registered_name = "Syndicate" icon_state = "syndie" assignment = "Syndicate Overlord" + untrackable = 1 access = list(access_syndicate, access_external_airlocks) /obj/item/weapon/card/id/captains_spare @@ -450,6 +456,7 @@ item_state = "gold_id" registered_name = "Admin" assignment = "Testing Shit" + untrackable = 1 /obj/item/weapon/card/id/admin/New() access = get_absolutely_all_accesses() diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm index 9fadc35d668..7e49a4465b9 100644 --- a/code/game/objects/items/weapons/dna_injector.dm +++ b/code/game/objects/items/weapons/dna_injector.dm @@ -62,7 +62,7 @@ /obj/item/weapon/dnainjector/proc/inject(mob/living/M as mob, mob/user as mob) if(istype(M,/mob/living)) - M.apply_effect(rand(5,20),IRRADIATE,0) + M.apply_effect(rand(10,25),IRRADIATE,0) if (!(NOCLONE in M.mutations)) // prevents drained people from having their DNA changed // UI in syringe. @@ -85,8 +85,6 @@ M.dna.SetSEValue(block,src.GetValue()) domutcheck(M, null, block!=null) uses-- - if(prob(5)) - trigger_side_effect(M) spawn(0)//this prevents the collapse of space-time continuum if (user) @@ -97,7 +95,7 @@ /obj/item/weapon/dnainjector/attack(mob/M as mob, mob/user as mob) if(ishuman(M)) // Would've done this via species instead of type, but the basic mob doesn't have a species, go figure. var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) + if(H.species.flags & NO_DNA_RAD) return if (!usr.IsAdvancedToolUser()) return diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm index 8c2bb4fe51e..45ed9da7217 100644 --- a/code/game/objects/items/weapons/explosives.dm +++ b/code/game/objects/items/weapons/explosives.dm @@ -41,6 +41,8 @@ user.say(message_say) target = user + message_admins("[key_name_admin(user)] suicided with [src.name] at ([x],[y],[z] - JMP)",0,1) + message_admins("[key_name(user)] suicided with [src.name] at ([x],[y],[z])") explode(get_turf(user)) return . @@ -78,12 +80,12 @@ if (ismob(target)) add_logs(target, user, "planted [name] on") user.visible_message("\red [user.name] finished planting an explosive on [target.name]!") - message_admins("[key_name(user, user.client)](?) planted C4 on [key_name(target)](?) with [timer] second fuse",0,1) - log_game("[key_name(user)] planted C4 on [key_name(target)] with [timer] second fuse") + message_admins("[key_name_admin(user)] planted [src.name] on [key_name_admin(target)] with [timer] second fuse",0,1) + log_game("[key_name(user)] planted [src.name] on [key_name(target)] with [timer] second fuse") else - message_admins("[key_name(user, user.client)](?) planted C4 on [target.name] at ([target.x],[target.y],[target.z] - JMP) with [timer] second fuse",0,1) - log_game("[key_name(user)] planted C4 on [target.name] at ([target.x],[target.y],[target.z]) with [timer] second fuse") + message_admins("[key_name_admin(user)] planted [src.name] on [target.name] at ([target.x],[target.y],[target.z] - JMP) with [timer] second fuse",0,1) + log_game("[key_name(user)] planted [src.name] on [target.name] at ([target.x],[target.y],[target.z]) with [timer] second fuse") target.overlays += image('icons/obj/assemblies.dmi', "plastic-explosive2") user << "Bomb has been planted. Timer counting down from [timer]." diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm index 9e81b02d31c..57aec40f09e 100644 --- a/code/game/objects/items/weapons/flamethrower.dm +++ b/code/game/objects/items/weapons/flamethrower.dm @@ -66,6 +66,7 @@ var/turf/target_turf = get_turf(target) if(target_turf) var/turflist = getline(user, target_turf) + add_logs(user, target, "flamethrowered", addition="at [target.x],[target.y],[target.z]") flame_turf(turflist) /obj/item/weapon/flamethrower/attackby(obj/item/W as obj, mob/user as mob, params) diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 28bea3240a3..c5705d31069 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -18,7 +18,7 @@ var/affected_area = 3 var/obj/item/device/assembly_holder/nadeassembly = null var/label = null - + var/assemblyattacher /obj/item/weapon/grenade/chem_grenade/New() create_reagents(1000) @@ -90,10 +90,9 @@ update_icon() else if(clown_check(user)) // This used to go before the assembly check, but that has absolutely zero to do with priming the damn thing. You could spam the admins with it. - var/log_str = "[key_name(usr)][isAntag(usr) ? "(ANTAG)" : ""]? has primed a [name] for detonation at [A.name] (JMP)." - msg_admin_attack(log_str) - log_game(log_str) - bombers += "[log_str]" + message_admins("[key_name_admin(usr)] has primed a [name] for detonation at [A.name] (JMP)") + log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])") + bombers += "[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])" user << "You prime the [name]! [det_time / 10] second\s!" active = 1 update_icon() @@ -138,9 +137,8 @@ contained = "\[[contained]\]" var/turf/bombturf = get_turf(loc) var/area/A = bombturf.loc - var/log_str = "[key_name(usr)][isAntag(usr) ? "(ANTAG)" : ""]? has completed [name] at [A.name] (JMP) [contained]." - msg_admin_attack(log_str) - log_game(log_str) + message_admins("[key_name_admin(usr)] has completed [name] at [A.name] (JMP) [contained].") + log_game("[key_name(usr)] has completed [name] at [bombturf.x], [bombturf.y], [bombturf.z].") else user << "You need to add at least one beaker before locking the assembly." else if(stage == READY && !nadeassembly) @@ -173,7 +171,7 @@ nadeassembly = A A.master = src A.loc = src - + assemblyattacher = user.ckey stage = WIRED user << "You add [A] to [src]!" update_icon() @@ -259,7 +257,15 @@ if(!has_reagents) playsound(loc, 'sound/items/Screwdriver2.ogg', 50, 1) - return + return + + if(nadeassembly) + var/mob/M = get_mob_by_ckey(assemblyattacher) + var/mob/last = get_mob_by_ckey(nadeassembly.fingerprintslast) + var/turf/T = get_turf(src) + var/area/A = get_area(T) + message_admins("grenade primed by an assembly, attached by [key_name_admin(M)](?) ([admin_jump_link(M, "holder")]) and last touched by [key_name_admin(last)](?) ([admin_jump_link(last, "holder")]) ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [A.name] (JMP).") + log_game("grenade primed by an assembly, attached by [key_name(M)] and last touched by [key_name(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [A.name] ([T.x], [T.y], [T.z])") playsound(loc, 'sound/effects/bamf.ogg', 50, 1) diff --git a/code/game/objects/items/weapons/grenades/ghettobomb.dm b/code/game/objects/items/weapons/grenades/ghettobomb.dm index bdbfd1fd4ea..d7d3dfb88e2 100644 --- a/code/game/objects/items/weapons/grenades/ghettobomb.dm +++ b/code/game/objects/items/weapons/grenades/ghettobomb.dm @@ -112,8 +112,8 @@ var/turf/bombturf = get_turf(src) var/area/A = get_area(bombturf) - message_admins("[key_name(usr)]? has primed a [name] for detonation at [A.name] (JMP).") - log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).") + message_admins("[key_name_admin(usr)] has primed a [name] for detonation at [A.name] (JMP)") + log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])") if(iscarbon(user)) var/mob/living/carbon/C = user C.throw_mode_on() diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm index 2d5f6ac0d90..a2b5dccd963 100644 --- a/code/game/objects/items/weapons/grenades/grenade.dm +++ b/code/game/objects/items/weapons/grenades/grenade.dm @@ -63,10 +63,9 @@ add_fingerprint(user) var/turf/bombturf = get_turf(src) var/area/A = get_area(bombturf) - var/log_str = "[key_name(usr)][isAntag(usr) ? "(ANTAG)" : ""]? has primed a [name] for detonation at [A.name] (JMP)." - msg_admin_attack(log_str) - log_game(log_str) - bombers += "[log_str]" + message_admins("[key_name_admin(usr)] has primed a [name] for detonation at [A.name] (JMP)") + log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])") + bombers += "[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])" if(iscarbon(user)) var/mob/living/carbon/C = user C.throw_mode_on() diff --git a/code/game/objects/items/weapons/hydroponics.dm b/code/game/objects/items/weapons/hydroponics.dm index 9b34938d480..f622a516b82 100644 --- a/code/game/objects/items/weapons/hydroponics.dm +++ b/code/game/objects/items/weapons/hydroponics.dm @@ -196,9 +196,9 @@ if(istype(M, /mob/living)) M << "\red You are stunned by the powerful acid of the Deathnettle!" - M.attack_log += text("\[[time_stamp()]\] Had the [src.name] used on them by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] on [M.name] ([M.ckey])") - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] used the [src.name] on [M.name] ([M.ckey]) (JMP)") + M.attack_log += text("\[[time_stamp()]\] Had the [src.name] used on them by [key_name(user)]") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] on [key_name(M)]") + msg_admin_attack("[key_name_admin(user)] used the [src.name] on [key_name_admin(M)]") if(!iscarbon(user)) M.LAssailant = null diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index e9a58e5307d..c964dd1e0b4 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -162,8 +162,8 @@ Implant Specifics:
"} var/need_gib = null if(istype(imp_in, /mob/)) var/mob/T = imp_in - message_admins("Explosive implant triggered in [T] ([T.key]). (JMP) ") - log_game("Explosive implant triggered in [T] ([T.key]).") + message_admins("Explosive implant triggered in [key_name_admin(T)]") + log_game("Explosive implant triggered in [key_name(T)].") need_gib = 1 if(ishuman(imp_in)) @@ -369,7 +369,8 @@ the implant may become unstable and either pre-maturely inject the subject or si if(M == user) user << "Making yourself loyal to yourself was a great idea! Perhaps even the best idea ever! Actually, you just feel like an idiot." if(isliving(user)) - user:brainloss += 20 + var/mob/living/L = user + L.adjustBrainLoss(20) return if(locate(/obj/item/weapon/implant/loyalty) in H.contents) H.visible_message("[H] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index 7e9b207ea4b..4de580b70de 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -32,9 +32,9 @@ for (var/mob/O in viewers(M, null)) O.show_message("\red [M] has been implanted by [user].", 1) - M.attack_log += text("\[[time_stamp()]\] Implanted with [src.name] ([src.imp.name]) by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] ([src.imp.name]) to implant [M.name] ([M.ckey])") - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] implanted [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") + M.attack_log += text("\[[time_stamp()]\] Implanted with [src.name] ([src.imp.name]) by [key_name(user)]") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] ([src.imp.name]) to implant [key_name(M)]") + msg_admin_attack("[key_name_admin(user)] implanted [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])") user.show_message("\red You implanted the implant into [M].") if(src.imp.implanted(M, user)) diff --git a/code/game/objects/items/weapons/legcuffs.dm b/code/game/objects/items/weapons/legcuffs.dm index 207deb0bfc7..1925455529c 100644 --- a/code/game/objects/items/weapons/legcuffs.dm +++ b/code/game/objects/items/weapons/legcuffs.dm @@ -44,11 +44,8 @@ if(2,3) user.drop_item(src) I.loc = src - var/turf/bombturf = get_turf(src) - var/area/A = get_area(bombturf) - var/log_str = "[key_name(usr)]? has rigged a beartrap with an IED at [A.name] (JMP)." - message_admins(log_str) - log_game(log_str) + 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.") user << "You sneak the [IED] underneath the pressure plate and connect the trigger wire." desc = "A trap used to catch bears and other legged creatures. There is an IED hooked up to it." else @@ -70,11 +67,8 @@ IED.overlays -= image('icons/obj/grenade.dmi', icon_state = "improvised_grenade_filled") IED.icon_state = initial(icon_state) + "_active" IED.assembled = 3 - var/turf/bombturf = get_turf(src) - var/area/A = get_area(bombturf) - var/log_str = "[key_name(usr)]? has triggered an IED-rigged [name] at [A.name] (JMP)." - message_admins(log_str) - log_game(log_str) + message_admins("[key_name_admin(usr)] has triggered an IED-rigged [name].") + log_game("[key_name(usr)] has triggered an IED-rigged [name].") spawn(IED.det_time) IED.prime() if(ishuman(AM)) @@ -95,7 +89,7 @@ H.update_inv_legcuffed() H << "You step on \the [src]!" if(IED && IED.active) - H << "The [src]'s IED has been activated!" + H << "\The [src]'s IED has been activated!" feedback_add_details("handcuffs","B") //Yes, I know they're legcuffs. Don't change this, no need for an extra variable. The "B" is used to tell them apart. for(var/mob/O in viewers(H, null)) if(O == H) diff --git a/code/game/objects/items/weapons/shards.dm b/code/game/objects/items/weapons/shards.dm index bc7c6dca09a..d73281a46ed 100644 --- a/code/game/objects/items/weapons/shards.dm +++ b/code/game/objects/items/weapons/shards.dm @@ -62,9 +62,6 @@ if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) - return - if( !H.shoes && ( !H.wear_suit || !(H.wear_suit.body_parts_covered & FEET) ) ) var/obj/item/organ/external/affecting = H.get_organ(pick("l_foot", "r_foot")) if(!affecting) diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 5fb04ffbafb..8e2f2d62b92 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -213,8 +213,8 @@ var/pressure = air_contents.return_pressure() if(pressure > TANK_FRAGMENT_PRESSURE) if(!istype(src.loc,/obj/item/device/transfer_valve)) - message_admins("Explosive tank rupture! last key to touch the tank was [src.fingerprintslast].") - log_game("Explosive tank rupture! last key to touch the tank was [src.fingerprintslast].") + message_admins("Explosive tank rupture! last key to touch the tank was [src.fingerprintslast] (JMP)") + log_game("Explosive tank rupture! last key to touch the tank was [src.fingerprintslast] at [x], [y], [z]") //world << "\blue[x],[y] tank is exploding: [pressure] kPa" //Give the gas a chance to build up more pressure through reacting air_contents.react() diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 4d3563b1ba6..b94337a118c 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -84,7 +84,8 @@ return /obj/item/weapon/screwdriver/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(!istype(M)) return ..() + if(!istype(M) || user.a_intent == "help") + return ..() if(user.zone_sel.selecting != "eyes" && user.zone_sel.selecting != "head") return ..() if((CLUMSY in user.mutations) && prob(50)) @@ -257,7 +258,7 @@ playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) return else if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1 && src.welding) - msg_admin_attack("[key_name_admin(user)][isAntag(user) ? "(ANTAG)" : ""] triggered a fueltank explosion.") + msg_admin_attack("[key_name_admin(user)] triggered a fueltank explosion.") log_game("[key_name(user)] triggered a fueltank explosion.") user << "\red That was stupid of you." var/obj/structure/reagent_dispensers/fueltank/tank = O @@ -307,7 +308,7 @@ /obj/item/weapon/weldingtool/proc/setWelding(var/temp_welding) //If we're turning it on if(temp_welding > 0) - if (remove_fuel(1)) + if (get_fuel() > 0) usr << "\blue The [src] switches on." src.force = 15 src.damtype = "fire" @@ -370,8 +371,6 @@ if(istype(user, /mob/living/carbon/human)) var/mob/living/carbon/human/H = user var/obj/item/organ/eyes/E = H.internal_organs_by_name["eyes"] - if(H.species.flags & IS_SYNTHETIC) - return if(!E) // No eyes? No problem! return switch(safety) @@ -475,37 +474,29 @@ icon_state = "crowbar_large" /obj/item/weapon/weldingtool/attack(mob/M as mob, mob/user as mob) - if(hasorgans(M)) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/S = H.organs_by_name[user.zone_sel.selecting] - var/obj/item/organ/external/S = M:organs_by_name[user.zone_sel.selecting] - - if (!S) return - if(!(S.status & ORGAN_ROBOT) || user.a_intent != "help") + if (!S) + return + if(!(S.status & ORGAN_ROBOT) || user.a_intent != "help" || S.open == 2) return ..() - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) - if(M == user) - user << "\red You can't repair damage to your own body - it's against OH&S." - return - if(S.brute_dam) - var/obj/item/weapon/weldingtool/WT = src - if (WT.remove_fuel(0,null)) - playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) - S.heal_damage(15,0,0,1) - user.visible_message("\red \The [user] patches some dents on \the [M]'s [S.name] with \the [src].") - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - H.updatehealth() - return + if(S.brute_dam < ROBOLIMB_SELF_REPAIR_CAP) + if (remove_fuel(0,null)) + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + S.heal_damage(15,0,0,1) + user.visible_message("\The [user] patches some dents on \the [M]'s [S.name] with \the [src].") + else if(S.open != 2) + user << "Need more welding fuel!" + return 1 else - user << "\red You need more welding fuel to complete this task." - return - else - user << "Nothing to fix!" - return + user << "The damage is far too severe to patch over externally." + return 1 + else if(S.open != 2) + user << "Nothing to fix!" else return ..() diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index 56a31ed5284..ee6fb876f05 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -41,11 +41,7 @@ else M.LAssailant = user - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") - - if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - user << "\red You don't have the dexterity to do this!" - return + 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)) user << "\red The rod slips out of your hand and hits your head." diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index 6a773177c59..10898e80a47 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -6,47 +6,26 @@ density = 1 anchored = 1 -/obj/structure/dresser/proc/convUnM(mund) - return underwear_m.Find(mund) - -/obj/structure/dresser/proc/convUnF(fund) - return underwear_f.Find(fund) - -/obj/structure/dresser/proc/convUs(us) - return undershirt_list.Find(us) - /obj/structure/dresser/attack_hand(mob/user as mob) if(!Adjacent(user))//no tele-grooming return if(ishuman(user)) var/mob/living/carbon/human/H = user - var/choice = input(user, "Underwear, or Undershirt?", "Changing") as null|anything in list("Underwear","Undershirt") + var/choice = input(user, "Underwear or Undershirt?", "Changing") as null|anything in list("Underwear","Undershirt") if(!Adjacent(user)) return switch(choice) if("Underwear") - if(H.gender == FEMALE) - var/new_undies = input(user, "Select your underwear", "Changing") as null|anything in underwear_f - if(new_undies) - H << "\red You selected [new_undies]." - var/freturn = convUnF(new_undies) - H.underwear = freturn - - else - var/new_undies = input(user, "Select your underwear", "Changing") as null|anything in underwear_m - if(new_undies) - H << "\red You selected [new_undies]." - var/mreturn = convUnM(new_undies) - H.underwear = mreturn + var/new_undies = input(user, "Select your underwear", "Changing") as null|anything in underwear_list + if(new_undies) + H.underwear = new_undies if("Undershirt") var/new_undershirt = input(user, "Select your undershirt", "Changing") as null|anything in undershirt_list if(new_undershirt) - H << "\red You selected [new_undershirt]" - var/usreturn = convUs(new_undershirt) - H.undershirt = usreturn + H.undershirt = new_undershirt add_fingerprint(H) H.update_body() \ No newline at end of file diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index 967b96d2c05..21208b26ca6 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -221,6 +221,14 @@ icon_state = "" mineral = "plasma" walltype = "plasma" + +/obj/structure/falsewall/plasma/attackby(obj/item/weapon/W, mob/user, params) + if(is_hot(W) > 300) + message_admins("Plasma falsewall ignited by [key_name_admin(user)] in ([x],[y],[z] - JMP)",0,1) + log_game("Plasma falsewall ignited by [key_name(user)] in ([x],[y],[z])") + burnbabyburn() + return + ..() /obj/structure/falsewall/plasma/proc/burnbabyburn(user) playsound(src, 'sound/items/Welder.ogg', 100, 1) diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 69508a41940..3a792030371 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -194,10 +194,10 @@ mineralType = "plasma" attackby(obj/item/weapon/W as obj, mob/user as mob) - if(istype(W,/obj/item/weapon/weldingtool)) - var/obj/item/weapon/weldingtool/WT = W - if(WT.remove_fuel(0, user)) - TemperatureAct(100) + if(is_hot(W)) + message_admins("Plasma mineral door ignited by [key_name_admin(user)] in ([x],[y],[z] - JMP)",0,1) + log_game("Plasma mineral door ignited by [key_name(user)] in ([x],[y],[z])") + TemperatureAct(100) ..() temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 35c57a0f9f8..ee2b57d19d7 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -417,3 +417,51 @@ usr << "\red Access denied." return +/hook/Login/proc/update_morgue(var/client/client, var/mob/L) + //Update morgues on login/logout + if (L.stat == DEAD) + var/obj/structure/morgue/Morgue = null + var/mob/living/carbon/human/C = null + if (istype(L,/mob/dead/observer)) //We're a ghost, let's find our corpse + var/mob/dead/observer/G = L + if(!G.mind) //This'll probably break morgue sprites, but the line under the next If statement causes runtimes with Assume Direct Control. + return + if (G.can_reenter_corpse && G.mind.current) + C = G.mind.current + else if (istype(L,/mob/living/carbon/human)) + C = L + + if (C) //We found our corpse, is it inside a morgue? + if (istype(C.loc,/obj/structure/morgue)) + Morgue = C.loc + else if (istype(C.loc,/obj/structure/closet/body_bag)) + var/obj/structure/closet/body_bag/B = C.loc + if (istype(B.loc,/obj/structure/morgue)) + Morgue = B.loc + if (Morgue) + Morgue.update() + +/hook/Logout/proc/update_morgue(var/client/client, var/mob/L) + //Update morgues on login/logout + if (L.stat == DEAD) + var/obj/structure/morgue/Morgue = null + var/mob/living/carbon/human/C = null + if (istype(L,/mob/dead/observer)) //We're a ghost, let's find our corpse + var/mob/dead/observer/G = L + if(!G.mind) //This'll probably break morgue sprites, but the line under the next If statement causes runtimes with Assume Direct Control. + return 1 + if (G.can_reenter_corpse && G.mind.current) + C = G.mind.current + else if (istype(L,/mob/living/carbon/human)) + C = L + + if (C) //We found our corpse, is it inside a morgue? + if (istype(C.loc,/obj/structure/morgue)) + Morgue = C.loc + else if (istype(C.loc,/obj/structure/closet/body_bag)) + var/obj/structure/closet/body_bag/B = C.loc + if (istype(B.loc,/obj/structure/morgue)) + Morgue = B.loc + if (Morgue) + Morgue.update() + diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index 334086d5f36..956bc6d7d07 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -155,9 +155,9 @@ if(pulling) occupant.visible_message("[pulling] has thrusted \the [name] into \the [A], throwing \the [occupant] out of it!") - pulling.attack_log += "\[[time_stamp()]\] Crashed [occupant.name]'s ([occupant.ckey]) [name] into \a [A]" - occupant.attack_log += "\[[time_stamp()]\] Thrusted into \a [A] by [pulling.name] ([pulling.ckey]) with \the [name]" - msg_admin_attack("[pulling.name] ([pulling.ckey])[isAntag(pulling) ? "(ANTAG)" : ""] has thrusted [occupant.name]'s ([occupant.ckey]) [name] into \a [A] (JMP)") + pulling.attack_log += "\[[time_stamp()]\] Crashed [key_name(occupant)] [name] into \a [A]" + occupant.attack_log += "\[[time_stamp()]\] Thrusted into \a [A] by [key_name(pulling)] with \the [name]" + msg_admin_attack("[key_name_admin(pulling)] has thrusted [key_name_admin(occupant)] [name] into \a [A]") else occupant.visible_message("[occupant] crashed into \the [A]!") diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 06e878f5d2f..a0255e1344f 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -299,6 +299,10 @@ user.do_attack_animation(src) visible_message("[user] slices [src] apart!") destroy() + +/obj/structure/table/mech_melee_attack(obj/mecha/M) + visible_message("[M] smashes [src] apart!") + destroy() /obj/structure/table/attack_animal(mob/living/simple_animal/user) if(user.environment_smash) @@ -905,13 +909,15 @@ W.Move(loc) return -/obj/structure/table/attack_hand(mob/user) +/obj/structure/rack/attack_hand(mob/user) if(HULK in user.mutations) visible_message("[user] smashes [src] apart!") user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) destroy() - - + +/obj/structure/rack/mech_melee_attack(obj/mecha/M) + visible_message("[M] smashes [src] apart!") + destroy() /obj/structure/rack/attack_alien(mob/living/user) user.do_attack_animation(src) diff --git a/code/game/response_team.dm b/code/game/response_team.dm index 03efff51ffe..09871374089 100644 --- a/code/game/response_team.dm +++ b/code/game/response_team.dm @@ -251,7 +251,7 @@ var/send_emergency_team if("Engineer") engineer_slots -= 1 M.equip_to_slot_or_del(new /obj/item/clothing/under/rank/engineer(M), slot_w_uniform) - M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/industrial(M), slot_back) + M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/ert/engineer(M), slot_back) M.equip_to_slot_or_del(new /obj/item/weapon/storage/box/responseteam(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/weapon/storage/belt/utility/full/multitool(M), slot_belt) @@ -275,7 +275,7 @@ var/send_emergency_team if("Security") security_slots -= 1 M.equip_to_slot_or_del(new /obj/item/clothing/under/rank/security(M), slot_w_uniform) - M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/security(M), slot_back) + M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/ert/security(M), slot_back) M.equip_to_slot_or_del(new /obj/item/weapon/storage/box/responseteam(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/weapon/storage/belt/security/response_team(M), slot_belt) @@ -299,7 +299,7 @@ var/send_emergency_team if("Medic") medical_slots -= 1 M.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical(M), slot_w_uniform) - M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/medic(M), slot_back) + M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/ert/medical(M), slot_back) M.equip_to_slot_or_del(new /obj/item/weapon/storage/box/responseteam(M), slot_in_backpack) var/obj/item/weapon/card/id/W = new(src) @@ -321,7 +321,7 @@ var/send_emergency_team if("Commander") command_slots = 0 M.equip_to_slot_or_del(new /obj/item/clothing/under/rank/centcom_officer(M), slot_w_uniform) - M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/captain(M), slot_back) + M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/ert/commander(M), slot_back) M.equip_to_slot_or_del(new /obj/item/weapon/storage/box/responseteam(M), slot_in_backpack) var/obj/item/weapon/card/id/W = new(src) diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm index d40539cdbf7..847c4179d8f 100644 --- a/code/game/supplyshuttle.dm +++ b/code/game/supplyshuttle.dm @@ -676,11 +676,10 @@ var/list/mechtoys = list( supply_controller.points -= P.cost supply_controller.shoppinglist += O temp = "Thanks for your order.
" - temp += "
Back Main Menu" else temp = "Not enough supply points.
" - temp += "
Back Main Menu" break + temp += "
Back Main Menu" else if (href_list["vieworders"]) temp = "Current approved orders:

" diff --git a/code/game/turfs/simulated/walls_mineral.dm b/code/game/turfs/simulated/walls_mineral.dm index 20d476238cb..1c2605238e0 100644 --- a/code/game/turfs/simulated/walls_mineral.dm +++ b/code/game/turfs/simulated/walls_mineral.dm @@ -89,6 +89,8 @@ /turf/simulated/wall/mineral/plasma/attackby(obj/item/weapon/W as obj, mob/user as mob) if(is_hot(W) > 300)//If the temperature of the object is over 300, then ignite + message_admins("Plasma wall ignited by [key_name_admin(user)] in ([x],[y],[z] - JMP)",0,1) + log_game("Plasma wall ignited by [key_name(user)] in ([x],[y],[z])") ignite(is_hot(W)) return ..() diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index 1cf5e73bc19..afbb84847f5 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -17,7 +17,7 @@ var/global/normal_ooc_colour = "#002eb8" src << "\red You have OOC muted." return - if(!(holder && holder.rights && (holder.rights & R_MOD))) + if(!check_rights(R_MOD,0)) if(!ooc_allowed) src << "\red OOC is globally muted" return @@ -141,9 +141,8 @@ var/global/normal_ooc_colour = "#002eb8" if(!M.client) continue var/client/C = M.client - if(C in admins) - if(C.holder.rights | R_MENTOR) - continue //they are handled after that + if(check_rights(R_MENTOR,0)) + continue //they are handled after that if(C.prefs.toggles & CHAT_LOOC) if(holder) @@ -160,7 +159,7 @@ var/global/normal_ooc_colour = "#002eb8" display_name = "[S.name]/([S.key])" for(var/client/C in admins) - if(C.holder.rights | R_MENTOR) + if(check_rights(R_MENTOR,0)) if(C.prefs.toggles & CHAT_LOOC) var/prefix = "(R)LOOC" if (C.mob in heard) diff --git a/code/modules/DetectiveWork/scanner.dm b/code/modules/DetectiveWork/scanner.dm index d694e4c1645..5aec21ac94e 100644 --- a/code/modules/DetectiveWork/scanner.dm +++ b/code/modules/DetectiveWork/scanner.dm @@ -10,6 +10,7 @@ item_state = "electronic" flags = CONDUCT | NOBLUDGEON slot_flags = SLOT_BELT + origin_tech = "magnets=4;biotech=2" var/scanning = 0 var/list/log = list() diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index da0c6d64e60..8cd511a3c9a 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -48,7 +48,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = computerid = bancid ip = banip - var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_player WHERE ckey = '[ckey]'") + var/DBQuery/query = dbcon.NewQuery("SELECT id FROM [format_table_name("player")] WHERE ckey = '[ckey]'") query.Execute() var/validckey = 0 if(query.NextRow()) @@ -83,7 +83,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = reason = sql_sanitize_text(reason) - var/sql = "INSERT INTO erro_ban (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`) VALUES (null, Now(), '[serverip]', '[bantype_str]', '[reason]', '[job]', [(duration)?"[duration]":"0"], [(rounds)?"[rounds]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[ckey]', '[computerid]', '[ip]', '[a_ckey]', '[a_computerid]', '[a_ip]', '[who]', '[adminwho]', '', null, null, null, null, null)" + var/sql = "INSERT INTO [format_table_name("ban")] (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`) VALUES (null, Now(), '[serverip]', '[bantype_str]', '[reason]', '[job]', [(duration)?"[duration]":"0"], [(rounds)?"[rounds]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[ckey]', '[computerid]', '[ip]', '[a_ckey]', '[a_computerid]', '[a_ip]', '[who]', '[adminwho]', '', null, null, null, null, null)" var/DBQuery/query_insert = dbcon.NewQuery(sql) query_insert.Execute() usr << "\blue Ban saved to database." @@ -125,7 +125,7 @@ datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") else bantype_sql = "bantype = '[bantype_str]'" - var/sql = "SELECT id FROM erro_ban WHERE ckey = '[ckey]' AND [bantype_sql] AND (unbanned is null OR unbanned = false)" + var/sql = "SELECT id FROM [format_table_name("ban")] WHERE ckey = '[ckey]' AND [bantype_sql] AND (unbanned is null OR unbanned = false)" if(job) sql += " AND job = '[job]'" @@ -166,7 +166,7 @@ datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) usr << "Cancelled" return - var/DBQuery/query = dbcon.NewQuery("SELECT ckey, duration, reason FROM erro_ban WHERE id = [banid]") + var/DBQuery/query = dbcon.NewQuery("SELECT ckey, duration, reason FROM [format_table_name("ban")] WHERE id = [banid]") query.Execute() var/eckey = usr.ckey //Editing admin ckey @@ -194,7 +194,7 @@ datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) usr << "Cancelled" return - var/DBQuery/update_query = dbcon.NewQuery("UPDATE erro_ban SET reason = '[value]', edits = CONCAT(edits,'- [eckey] changed ban reason from \\\"[reason]\\\" to \\\"[value]\\\"
') WHERE id = [banid]") + var/DBQuery/update_query = dbcon.NewQuery("UPDATE [format_table_name("ban")] SET reason = '[value]', edits = CONCAT(edits,'- [eckey] changed ban reason from \\\"[reason]\\\" to \\\"[value]\\\"
') WHERE id = [banid]") update_query.Execute() message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s reason from [reason] to [value]",1) if("duration") @@ -204,7 +204,7 @@ datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) usr << "Cancelled" return - var/DBQuery/update_query = dbcon.NewQuery("UPDATE erro_ban SET duration = [value], edits = CONCAT(edits,'- [eckey] changed ban duration from [duration] to [value]
'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]") + var/DBQuery/update_query = dbcon.NewQuery("UPDATE [format_table_name("ban")] SET duration = [value], edits = CONCAT(edits,'- [eckey] changed ban duration from [duration] to [value]
'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]") message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s duration from [duration] to [value]",1) update_query.Execute() if("unban") @@ -222,7 +222,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) if(!check_rights(R_BAN)) return - var/sql = "SELECT ckey FROM erro_ban WHERE id = [id]" + var/sql = "SELECT ckey FROM [format_table_name("ban")] WHERE id = [id]" establish_db_connection() if(!dbcon.IsConnected()) @@ -252,7 +252,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) var/unban_computerid = src.owner:computer_id var/unban_ip = src.owner:address - var/sql_update = "UPDATE erro_ban SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = '[unban_ckey]', unbanned_computerid = '[unban_computerid]', unbanned_ip = '[unban_ip]' WHERE id = [id]" + var/sql_update = "UPDATE [format_table_name("ban")] SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = '[unban_ckey]', unbanned_computerid = '[unban_computerid]', unbanned_ip = '[unban_ip]' WHERE id = [id]" message_admins("[key_name_admin(usr)] has lifted [pckey]'s ban.",1) var/DBQuery/query_update = dbcon.NewQuery(sql_update) @@ -410,7 +410,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) bantypesearch += "'PERMABAN' " - var/DBQuery/select_query = dbcon.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid FROM erro_ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100") + var/DBQuery/select_query = dbcon.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid FROM [format_table_name("ban")] WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100") select_query.Execute() while(select_query.NextRow()) diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index a670e9805bb..6f843bc148b 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -6,7 +6,7 @@ world/IsBanned(key,address,computer_id) //Guest Checking if(!guests_allowed && IsGuestKey(key)) log_access("Failed Login: [key] - Guests not allowed") - message_admins("\blue Failed Login: [key] - Guests not allowed") + // message_admins("\blue Failed Login: [key] - Guests not allowed") return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.") //check if the IP address is a known TOR node @@ -51,7 +51,7 @@ world/IsBanned(key,address,computer_id) failedcid = 0 cidquery = " OR computerid = '[computer_id]' " - var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM erro_ban WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)") + var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM [format_table_name("ban")] WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)") query.Execute() diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 050e21a8e17..060518108a1 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -44,7 +44,7 @@ var/global/nologevent = 0 body += "Options panel for [M]" if(M.client) body += " played by [M.client] " - body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" + body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" if(istype(M, /mob/new_player)) body += " Hasn't Entered Game " @@ -64,7 +64,8 @@ var/global/nologevent = 0 Ban | Jobban | Appearance Ban | - Notes + Notes | + Watchlist Flag "} if(M.client) @@ -121,7 +122,7 @@ var/global/nologevent = 0 Make Mask | Make Robot | Make Alien | - Make slime + Make Slime | Make Superhero "} @@ -1006,7 +1007,6 @@ proc/formatPlayerPanel(var/mob/U,var/text="PP") if (!frommob.ckey) return 0 - var/question = "" if (tomob.ckey) question = "This mob already has a user ([tomob.key]) in control of it! " @@ -1029,4 +1029,5 @@ proc/formatPlayerPanel(var/mob/U,var/text="PP") tomob.ckey = frommob.ckey qdel(frommob) - return 1 \ No newline at end of file + return 1 + \ No newline at end of file diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index 4323644b480..aea9f51f715 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -23,10 +23,10 @@ if(!message) return var/F = investigate_subject2file(subject) if(!F) return - F << "[time2text(world.timeofday,"hh:mm")] \ref[src] ([x],[y],[z]) || [src] [message]
" + F << "[time_stamp()] \ref[src] ([x],[y],[z]) || [src] [message]
" //ADMINVERBS -/client/proc/investigate_show( subject in list("hrefs","pda","singulo","gold core","cult") ) +/client/proc/investigate_show( subject in list("hrefs","pda","singulo","atmos","ntsl","gold core","cult") ) set name = "Investigate" set category = "Admin" if(!holder) return @@ -57,6 +57,20 @@ src << browse(F,"window=investigate[subject];size=800x300") if("cult") + var/F = investigate_subject2file(subject) + if(!F) + src << "Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed." + return + src << browse(F,"window=investigate[subject];size=800x300") + + if("atmos") + var/F = investigate_subject2file(subject) + if(!F) + src << "Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed." + return + src << browse(F,"window=investigate[subject];size=800x300") + + if("ntsl") var/F = investigate_subject2file(subject) if(!F) src << "Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed." diff --git a/code/modules/admin/admin_memo.dm b/code/modules/admin/admin_memo.dm index 133f6d10e90..4a5f2eac73a 100644 --- a/code/modules/admin/admin_memo.dm +++ b/code/modules/admin/admin_memo.dm @@ -27,7 +27,8 @@ if( findtext(memo,"[memo]" - message_admins("[key] set an admin memo:
[memo]") + log_admin("[key_name(usr)] set an admin memo:
[memo]") + message_admins("[key_name_admin(usr)] set an admin memo:
[memo]") //show all memos /client/proc/admin_memo_show() diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index 606e91830af..236fbe42779 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -61,6 +61,7 @@ var/list/admin_ranks = list() //list of all ranks with associated rights //clear the datums references admin_datums.Cut() for(var/client/C in admins) + C.remove_admin_verbs() C.holder = null admins.Cut() @@ -108,7 +109,7 @@ var/list/admin_ranks = list() //list of all ranks with associated rights load_admins() return - var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, level, flags FROM erro_admin") + var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, level, flags FROM [format_table_name("admin")]") query.Execute() while(query.NextRow()) var/ckey = query.item[1] diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 71990e49d55..e004a7b0d83 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -2,6 +2,7 @@ var/list/admin_verbs_default = list( // /datum/admins/proc/show_player_panel, /*shows an interface for individual players, with various links (links require additional flags*/ /client/proc/deadmin_self, /*destroys our own admin datum so we can play as a regular player*/ + /client/proc/hide_verbs, /*hides all our adminverbs*/ // /client/proc/check_antagonists, /*shows all antags*/ // /client/proc/deadchat /*toggles deadchat on/off*/ /client/proc/cmd_mentor_check_new_players @@ -202,6 +203,48 @@ var/list/admin_verbs_mentor = list( if(holder.rights & R_SPAWN) verbs += admin_verbs_spawn if(holder.rights & R_MOD) verbs += admin_verbs_mod if(holder.rights & R_MENTOR) verbs += admin_verbs_mentor + +/client/proc/remove_admin_verbs() + verbs.Remove( + admin_verbs_default, + /client/proc/togglebuildmodeself, + admin_verbs_admin, + admin_verbs_ban, + admin_verbs_event, + admin_verbs_server, + admin_verbs_debug, + admin_verbs_possess, + admin_verbs_permissions, + /client/proc/stealth, + admin_verbs_rejuv, + admin_verbs_sounds, + admin_verbs_spawn, + admin_verbs_mod, + admin_verbs_mentor, + admin_verbs_show_debug_verbs, + /client/proc/readmin, + ) + +/client/proc/hide_verbs() + set name = "Adminverbs - Hide All" + set category = "Admin" + + remove_admin_verbs() + verbs += /client/proc/show_verbs + + src << "Almost all of your adminverbs have been hidden." + feedback_add_details("admin_verb","TAVVH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + +/client/proc/show_verbs() + set name = "Adminverbs - Show" + set category = "Admin" + + verbs -= /client/proc/show_verbs + add_admin_verbs() + + src << "All of your adminverbs are now visible." + feedback_add_details("admin_verb","TAVVS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/admin_ghost() set category = "Admin" @@ -401,7 +444,7 @@ var/list/admin_verbs_mentor = list( if(flash_range == null) return explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, 1, 1) - message_admins("[ckey] creating an admin explosion at [epicenter.loc].") + message_admins("[key_name_admin(usr)] creating an admin explosion at [epicenter.loc].") feedback_add_details("admin_verb","DB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/give_spell(mob/T as mob in mob_list) // -- Urist @@ -526,12 +569,61 @@ var/list/admin_verbs_mentor = list( set category = "Admin" if(holder) - if(alert("Confirm self-deadmin for the round? You can't re-admin yourself without someont promoting you.",,"Yes","No") == "Yes") - log_admin("[src] deadmined themself.") - message_admins("[src] deadmined themself.", 1) - deadmin() - src << "You are now a normal player." + log_admin("[key_name(usr)] deadmined themself.") + message_admins("[key_name_admin(usr)] deadmined themself.") + deadmin() + verbs += /client/proc/readmin + deadmins += ckey + src << "You are now a normal player." feedback_add_details("admin_verb","DAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/readmin() + set name = "Re-admin self" + set category = "Admin" + set desc = "Regain your admin powers." + var/datum/admins/D = admin_datums[ckey] + var/rank = null + if(config.admin_legacy_system) + //load text from file + var/list/Lines = file2list("config/admins.txt") + for(var/line in Lines) + var/list/splitline = text2list(line, " - ") + if(n_lower(splitline[1]) == ckey) + if(splitline.len >= 2) + rank = ckeyEx(splitline[2]) + break + continue + else + if(!dbcon.IsConnected()) + message_admins("Warning, mysql database is not connected.") + src << "Warning, mysql database is not connected." + return + var/sql_ckey = sanitizeSQL(ckey) + var/DBQuery/query = dbcon.NewQuery("SELECT rank FROM [format_table_name("admin")] WHERE ckey = '[sql_ckey]'") + query.Execute() + while(query.NextRow()) + rank = ckeyEx(query.item[1]) + if(!D) + if(admin_ranks[rank] == null) + var/error_extra = "" + if(!config.admin_legacy_system) + error_extra = " Check mysql DB connection." + error("Error while re-adminning [src], admin rank ([rank]) does not exist.[error_extra]") + src << "Error while re-adminning, admin rank ([rank]) does not exist.[error_extra]" + return + D = new(rank,admin_ranks[rank],ckey) + var/client/C = directory[ckey] + D.associate(C) + message_admins("[key_name_admin(usr)] re-adminned themselves.") + log_admin("[key_name(usr)] re-adminned themselves.") + deadmins -= ckey + feedback_add_details("admin_verb","RAS") + return + else + src << "You are already an admin." + verbs -= /client/proc/readmin + deadmins -= ckey + return /client/proc/toggle_log_hrefs() set name = "Toggle href logging" diff --git a/code/modules/admin/banappearance.dm b/code/modules/admin/banappearance.dm index 5e390c249b6..7ecbde4c3fb 100644 --- a/code/modules/admin/banappearance.dm +++ b/code/modules/admin/banappearance.dm @@ -59,7 +59,7 @@ DEBUG return //appearance bans - var/DBQuery/query = dbcon.NewQuery("SELECT ckey FROM erro_ban WHERE bantype = 'APPEARANCE_BAN' AND NOT unbanned = 1") + var/DBQuery/query = dbcon.NewQuery("SELECT ckey FROM [format_table_name("ban")] WHERE bantype = 'APPEARANCE_BAN' AND NOT unbanned = 1") query.Execute() while(query.NextRow()) @@ -101,7 +101,7 @@ proc/DB_ban_isappearancebanned(var/playerckey) var/sqlplayerckey = sql_sanitize_text(ckey(playerckey)) - var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_ban WHERE CKEY = '[sqlplayerckey]' AND ((bantype = 'APPEARANCE_BAN') OR (bantype = 'APPEARANCE_TEMPBAN' AND expiration_time > Now())) AND unbanned != 1") + var/DBQuery/query = dbcon.NewQuery("SELECT id FROM [format_table_name("ban")] WHERE CKEY = '[sqlplayerckey]' AND ((bantype = 'APPEARANCE_BAN') OR (bantype = 'APPEARANCE_TEMPBAN' AND expiration_time > Now())) AND unbanned != 1") query.Execute() while(query.NextRow()) return 1 diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm index c97b4fc66b3..a28de25ee39 100644 --- a/code/modules/admin/banjob.dm +++ b/code/modules/admin/banjob.dm @@ -71,7 +71,7 @@ DEBUG return //Job permabans - var/DBQuery/query = dbcon.NewQuery("SELECT ckey, job FROM erro_ban WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)") + var/DBQuery/query = dbcon.NewQuery("SELECT ckey, job FROM [format_table_name("ban")] WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)") query.Execute() while(query.NextRow()) @@ -81,7 +81,7 @@ DEBUG jobban_keylist.Add("[ckey] - [job]") //Job tempbans - var/DBQuery/query1 = dbcon.NewQuery("SELECT ckey, job FROM erro_ban WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()") + var/DBQuery/query1 = dbcon.NewQuery("SELECT ckey, job FROM [format_table_name("ban")] WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()") query1.Execute() while(query1.NextRow()) diff --git a/code/modules/admin/buildmode.dm b/code/modules/admin/buildmode.dm index cb2b79b9171..88077425c67 100644 --- a/code/modules/admin/buildmode.dm +++ b/code/modules/admin/buildmode.dm @@ -17,7 +17,7 @@ if(H.cl == M.client) qdel(H) else - message_admins("[key_name(usr)] has entered build mode.") + message_admins("[key_name_admin(usr)] has entered build mode.") log_admin("[key_name(usr)] has entered build mode.") M.client.buildmode = 1 M.client.show_popup_menus = 0 diff --git a/code/modules/admin/create_object.dm b/code/modules/admin/create_object.dm index 5b5ee047852..584dd9331b6 100644 --- a/code/modules/admin/create_object.dm +++ b/code/modules/admin/create_object.dm @@ -1,4 +1,5 @@ -/var/create_object_html = null +var/create_object_html = null +var/list/create_object_forms = list(/obj, /obj/structure, /obj/machinery, /obj/effect, /obj/item, /obj/mecha, /obj/item/weapon, /obj/item/clothing, /obj/item/stack, /obj/item/device, /obj/item/weapon/reagent_containers, /obj/item/weapon/gun) /datum/admins/proc/create_object(var/mob/user) if (!create_object_html) @@ -9,20 +10,14 @@ user << browse(replacetext(create_object_html, "/* ref src */", "\ref[src]"), "window=create_object;size=425x475") - /datum/admins/proc/quick_create_object(var/mob/user) + var/path = input("Select the path of the object you wish to create.", "Path", /obj) in create_object_forms + var/html_form = create_object_forms[path] - var/quick_create_object_html = null - var/pathtext = null + if (!html_form) + var/objectjs = list2text(typesof(path), ";") + html_form = file2text('html/create_object.html') + html_form = replacetext(html_form, "null /* object types */", "\"[objectjs]\"") + create_object_forms[path] = html_form - pathtext = input("Select the path of the object you wish to create.", "Path", "/obj") in list("/obj","/obj/structure","/obj/item","/obj/item/weapon","/obj/item/clothing","/obj/machinery","/obj/mecha") - - var path = text2path(pathtext) - - if (!quick_create_object_html) - var/objectjs = null - objectjs = list2text(typesof(path), ";") - quick_create_object_html = file2text('html/create_object.html') - quick_create_object_html = replacetext(quick_create_object_html, "null /* object types */", "\"[objectjs]\"") - - user << browse(replacetext(quick_create_object_html, "/* ref src */", "\ref[src]"), "window=quick_create_object;size=425x475") \ No newline at end of file + user << browse(replacetext(html_form, "/* ref src */", "\ref[src]"), "window=qco[path];size=425x475") \ No newline at end of file diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index 33fc2240830..17a2fc42239 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -28,11 +28,13 @@ var/list/admin_datums = list() owner = C owner.holder = src owner.add_admin_verbs() //TODO + owner.verbs -= /client/proc/readmin admins |= C /datum/admins/proc/disassociate() if(owner) admins -= owner + owner.remove_admin_verbs() owner.holder = null owner = null @@ -78,11 +80,17 @@ you will have to do something like if(client.holder.rights & R_ADMIN) yourself. usr << "Error: Cannot proceed. They have more or equal rights to us." return 0 - - /client/proc/deadmin() admin_datums -= ckey if(holder) holder.disassociate() del(holder) return 1 + +//This proc checks whether subject has at least ONE of the rights specified in rights_required. +/proc/check_rights_for(client/subject, rights_required) + if(subject && subject.holder) + if(rights_required && !(rights_required & subject.holder.rights)) + return 0 + return 1 + return 0 diff --git a/code/modules/admin/permissionverbs/permissionedit.dm b/code/modules/admin/permissionverbs/permissionedit.dm index fbd33cf0734..e53d4644c33 100644 --- a/code/modules/admin/permissionverbs/permissionedit.dm +++ b/code/modules/admin/permissionverbs/permissionedit.dm @@ -76,7 +76,7 @@ if(!istext(adm_ckey) || !istext(new_rank)) return - var/DBQuery/select_query = dbcon.NewQuery("SELECT id FROM erro_admin WHERE ckey = '[adm_ckey]'") + var/DBQuery/select_query = dbcon.NewQuery("SELECT id FROM [format_table_name("admin")] WHERE ckey = '[adm_ckey]'") select_query.Execute() var/new_admin = 1 @@ -86,16 +86,16 @@ admin_id = text2num(select_query.item[1]) if(new_admin) - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO `erro_admin` (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)") + var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO [format_table_name("admin")] (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)") insert_query.Execute() - var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');") + var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.[format_table_name("admin_log")] (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');") log_query.Execute() usr << "\blue New admin added." else if(!isnull(admin_id) && isnum(admin_id)) - var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET rank = '[new_rank]' WHERE id = [admin_id]") + var/DBQuery/insert_query = dbcon.NewQuery("UPDATE [format_table_name("admin")] SET rank = '[new_rank]' WHERE id = [admin_id]") insert_query.Execute() - var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');") + var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.[format_table_name("admin_log")] (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');") log_query.Execute() usr << "\blue Admin rank changed." @@ -128,7 +128,7 @@ if(!istext(adm_ckey) || !isnum(new_permission)) return - var/DBQuery/select_query = dbcon.NewQuery("SELECT id, flags FROM erro_admin WHERE ckey = '[adm_ckey]'") + var/DBQuery/select_query = dbcon.NewQuery("SELECT id, flags FROM [format_table_name("admin")] WHERE ckey = '[adm_ckey]'") select_query.Execute() var/admin_id @@ -141,14 +141,24 @@ return if(admin_rights & new_permission) //This admin already has this permission, so we are removing it. - var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]") + var/DBQuery/insert_query = dbcon.NewQuery("UPDATE [format_table_name("admin")] SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]") insert_query.Execute() - var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');") + var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.[format_table_name("admin_log")] (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');") log_query.Execute() usr << "\blue Permission removed." else //This admin doesn't have this permission, so we are adding it. - var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]") + var/DBQuery/insert_query = dbcon.NewQuery("UPDATE [format_table_name("admin")] SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]") insert_query.Execute() - var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')") + var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.[format_table_name("admin_log")] (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')") log_query.Execute() - usr << "\blue Permission added." \ No newline at end of file + usr << "\blue Permission added." + +/datum/admins/proc/updateranktodb(ckey,newrank) + establish_db_connection() + if (!dbcon.IsConnected()) + return + var/sql_ckey = sanitizeSQL(ckey) + var/sql_admin_rank = sanitizeSQL(newrank) + + var/DBQuery/query_update = dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastadminrank = '[sql_admin_rank]' WHERE ckey = '[sql_ckey]'") + query_update.Execute() \ No newline at end of file diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 8d9a61b10e9..8873f385d90 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -81,9 +81,9 @@ body += "TP - " body += "PM - " body += "SM - " - body += "JMP" + body += "FLW" if(eyeref) - body += "|EYE" + body += "|EYE" body += "
" if(antagonist > 0) body += "Antagonist"; diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index a0ce958a5f4..d7c928c8c21 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -3,7 +3,7 @@ if(usr.client != src.owner || !check_rights(0)) log_admin("[key_name(usr)] tried to use the admin panel without authorization.") - message_admins("[usr.key] has attempted to override the admin panel!") + message_admins("[key_name_admin(usr)] has attempted to override the admin panel!") return if(ticker.mode && ticker.mode.check_antagonists_topic(href, href_list)) @@ -124,7 +124,7 @@ if(bancid) banreason = "[banreason] (CUSTOM CID)" else - message_admins("Ban process: A mob matching [playermob.ckey] was found at location [playermob.x], [playermob.y], [playermob.z]. Custom ip and computer id fields replaced with the ip and computer id from the located mob") + message_admins("Ban process: A mob matching [playermob.ckey] was found at location [playermob.x], [playermob.y], [playermob.z]. Custom IP and computer id fields replaced with the IP and computer id from the located mob") DB_ban_record(bantype, playermob, banduration, banreason, banjob, null, banckey, banip, bancid ) @@ -160,6 +160,7 @@ admin_datums -= adm_ckey D.disassociate() + updateranktodb(adm_ckey, "player") message_admins("[key_name_admin(usr)] removed [adm_ckey] from the admins list") log_admin("[key_name(usr)] removed [adm_ckey] from the admins list") log_admin_rank_modification(adm_ckey, "Removed") @@ -204,6 +205,7 @@ var/client/C = directory[adm_ckey] //find the client with the specified ckey (if they are logged in) D.associate(C) //link up with the client and add verbs + updateranktodb(adm_ckey, new_rank) message_admins("[key_name_admin(usr)] edited the admin rank of [adm_ckey] to [new_rank]") log_admin("[key_name(usr)] edited the admin rank of [adm_ckey] to [new_rank]") log_admin_rank_modification(adm_ckey, new_rank) @@ -278,7 +280,7 @@ ticker.delay_end = !ticker.delay_end log_admin("[key_name(usr)] [ticker.delay_end ? "delayed the round end" : "has made the round end normally"].") - message_admins("\blue [key_name(usr)] [ticker.delay_end ? "delayed the round end" : "has made the round end normally"].", 1) + message_admins("\blue [key_name_admin(usr)] [ticker.delay_end ? "delayed the round end" : "has made the round end normally"].", 1) href_list["secretsadmin"] = "check_antagonist" else if(href_list["simplemake"]) @@ -1000,8 +1002,8 @@ M << "\red To try to resolve this matter head to [config.banappeals]" else M << "\red No ban appeals URL has been set." - log_admin("[usr.client.ckey] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.") - message_admins("\blue[usr.client.ckey] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.") + log_admin("[key_name(usr)] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.") + message_admins("\blue [key_name_admin(usr)] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.") del(M.client) //del(M) // See no reason why to delete mob. Important stuff can be lost. And ban can be lifted before round ends. @@ -1022,8 +1024,8 @@ else M << "\red No ban appeals URL has been set." ban_unban_log_save("[usr.client.ckey] has permabanned [M.ckey]. - Reason: [reason] - This is a permanent ban.") - log_admin("[usr.client.ckey] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.") - message_admins("\blue[usr.client.ckey] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.") + log_admin("[key_name(usr)] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.") + message_admins("\blue[key_name_admin(usr)] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.") feedback_inc("ban_perma",1) DB_ban_record(BANTYPE_PERMA, M, -1, reason) @@ -1032,6 +1034,63 @@ if("Cancel") return + //Watchlist + else if(href_list["watchlist"]) + if(!check_rights(R_ADMIN)) return + var/mob/M = locate(href_list["watchlist"]) + if(!dbcon.IsConnected()) + usr << "Failed to establish database connection." + return + if(!ismob(M)) + usr << "This can only be used on instances of type /mob" + return + if(!M.ckey) + usr << "This mob has no ckey" + return + var/sql_ckey = sanitizeSQL(M.ckey) + var/DBQuery/query = dbcon.NewQuery("SELECT ckey FROM [format_table_name("watch")] WHERE (ckey = '[sql_ckey]')") + query.Execute() + if(query.NextRow()) + switch(alert(usr, "Ckey already flagged", "[sql_ckey] is already on the watchlist, do you want to:", "Remove", "Edit reason", "Cancel")) + if("Cancel") + return + if("Remove") + var/DBQuery/query_watchdel = dbcon.NewQuery("DELETE FROM [format_table_name("watch")] WHERE ckey = '[sql_ckey]'") + if(!query_watchdel.Execute()) + var/err = query_watchdel.ErrorMsg() + log_game("SQL ERROR during removing watch entry. Error : \[[err]\]\n") + return + log_admin("[key_name_admin(usr)] has removed [key_name_admin(M)] from the watchlist") + message_admins("[key_name_admin(usr)] has removed [key_name_admin(M)] from the watchlist", 1) + if("Edit reason") + var/DBQuery/query_reason = dbcon.NewQuery("SELECT ckey, reason FROM [format_table_name("watch")] WHERE (ckey = '[sql_ckey]')") + query_reason.Execute() + if(query_reason.NextRow()) + var/watch_reason = query_reason.item[2] + var/new_reason = input("Insert new reason", "New Reason", "[watch_reason]", null) as null|text + new_reason = sanitizeSQL(new_reason) + if(!new_reason) + return + var/DBQuery/update_query = dbcon.NewQuery("UPDATE [format_table_name("watch")] SET reason = '[new_reason]' WHERE (ckey = '[sql_ckey]')") + if(!update_query.Execute()) + var/err = update_query.ErrorMsg() + log_game("SQL ERROR during edit watch entry reason. Error : \[[err]\]\n") + return + log_admin("[key_name_admin(usr)] has edited [sql_ckey]'s reason from [watch_reason] to [new_reason]",1) + message_admins("[key_name_admin(usr)] has edited [sql_ckey]'s reason from [watch_reason] to [new_reason]",1) + else + var/reason = input(usr,"Reason?","reason","Metagaming") as text|null + if(!reason) + return + reason = sanitizeSQL(reason) + var/DBQuery/query_watchadd = dbcon.NewQuery("INSERT INTO [format_table_name("watch")] (ckey, reason) VALUES ('[sql_ckey]', '[reason]')") + if(!query_watchadd.Execute()) + var/err = query_watchadd.ErrorMsg() + log_game("SQL ERROR during adding new watch entry. Error : \[[err]\]\n") + return + log_admin("[key_name_admin(usr)] has added [key_name_admin(M)] to the watchlist - Reason: [reason]") + message_admins("[key_name_admin(usr)] has added [key_name_admin(M)] to the watchlist - Reason: [reason]", 1) + else if(href_list["mute"]) if(!check_rights(R_MOD)) return @@ -1201,7 +1260,7 @@ return log_admin("[key_name(usr)] has sent [key_name(M)] back to the Lobby.") - message_admins("[key_name(usr)] has sent [key_name(M)] back to the Lobby.") + message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] back to the Lobby.") var/mob/new_player/NP = new() NP.ckey = M.ckey @@ -1353,7 +1412,7 @@ L.revive() message_admins("\red Admin [key_name_admin(usr)] healed / revived [key_name_admin(L)]!", 1) - log_admin("[key_name(usr)] healed / Revived [key_name(L)]") + log_admin("[key_name(usr)] healed / revived [key_name(L)]") else if(href_list["makeai"]) if(!check_rights(R_SPAWN)) return @@ -1452,6 +1511,17 @@ if(!isobserver(usr)) C.admin_ghost() sleep(2) C.jumptomob(M) + + else if(href_list["adminplayerobservefollow"]) + if(!check_rights(R_MOD,0) && !check_rights(R_ADMIN)) return + + var/mob/M = locate(href_list["adminplayerobservefollow"]) + + var/client/C = usr.client + if(!isobserver(usr)) C.admin_ghost() + var/mob/dead/observer/A = C.mob + sleep(2) + A.ManualFollow(M) else if(href_list["check_antagonist"]) check_antagonists() @@ -1519,7 +1589,7 @@ src.owner << "Name = [M.name]; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = [M.key];" src.owner << "Location = [location_description];" src.owner << "[special_role_description]" - src.owner << "(PM) (PP) (VV) (SM) ([admin_jump_link(M, src)]) (CA)" + src.owner << "(PM) (PP) (VV) (SM) (FLW) (CA)" else if(href_list["adminspawncookie"]) if(!check_rights(R_ADMIN|R_EVENT)) return @@ -1534,14 +1604,14 @@ H.equip_to_slot_or_del( new /obj/item/weapon/reagent_containers/food/snacks/cookie(H), slot_r_hand ) if(!(istype(H.r_hand,/obj/item/weapon/reagent_containers/food/snacks/cookie))) log_admin("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") - message_admins("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") + message_admins("[key_name_admin(H)] has their hands full, so they did not receive their cookie, spawned by [key_name_admin(src.owner)].") return else H.update_inv_r_hand()//To ensure the icon appears in the HUD else H.update_inv_l_hand() log_admin("[key_name(H)] got their cookie, spawned by [key_name(src.owner)]") - message_admins("[key_name(H)] got their cookie, spawned by [key_name(src.owner)]") + message_admins("[key_name_admin(H)] got their cookie, spawned by [key_name_admin(src.owner)]") feedback_inc("admin_cookies_spawned",1) H << "\blue Your prayers have been answered!! You received the best cookie!" @@ -1565,8 +1635,8 @@ BSACooldown = 0 M << "You've been hit by bluespace artillery!" - log_admin("[key_name(M)] has been hit by Bluespace Artillery fired by [src.owner]") - message_admins("[key_name(M)] has been hit by Bluespace Artillery fired by [src.owner]") + log_admin("[key_name(M)] has been hit by Bluespace Artillery fired by [key_name(src.owner)]") + message_admins("[key_name_admin(M)] has been hit by Bluespace Artillery fired by [key_name_admin(src.owner)]") var/obj/effect/stop/S S = new /obj/effect/stop @@ -1604,8 +1674,8 @@ if(!input) return src.owner << "You sent [input] to [H] via a secure channel." - log_admin("[src.owner] replied to [key_name(H)]'s Centcomm message with the message [input].") - message_admins("[src.owner] replied to [key_name(H)]'s Centcom message with: \"[input]\"") + log_admin("[key_name(src.owner)] replied to [key_name(H)]'s Centcomm message with the message [input].") + message_admins("[key_name_admin(src.owner)] replied to [key_name_admin(H)]'s Centcom message with: \"[input]\"") H << "You hear something crackle in your headset for a moment before a voice speaks. \"Please stand by for a message from Central Command. Message as follows. [input]. Message ends.\"" else if(href_list["SyndicateReply"]) @@ -1935,28 +2005,13 @@ dirty_paths = href_list["object_list"] var/paths = list() - var/removed_paths = list() for(var/dirty_path in dirty_paths) var/path = text2path(dirty_path) if(!path) - removed_paths += dirty_path continue else if(!ispath(path, /obj) && !ispath(path, /turf) && !ispath(path, /mob)) - removed_paths += dirty_path continue - else if(ispath(path, /obj/item/weapon/gun/energy/pulse_rifle)) - if(!check_rights((R_SERVER|R_EVENT),0)) - removed_paths += dirty_path - continue - else if(ispath(path, /obj/item/weapon/melee/energy/blade))//Not an item one should be able to spawn./N - if(!check_rights((R_SERVER|R_EVENT),0)) - removed_paths += dirty_path - continue - else if(ispath(path, /obj/effect/anomaly/bhole)) - if(!check_rights((R_SERVER|R_EVENT),0)) - removed_paths += dirty_path - continue paths += path if(!paths) @@ -1965,8 +2020,6 @@ if(length(paths) > 5) alert("Select fewer object types, (max 5)") return - else if(length(removed_paths)) - alert("Removed:\n" + list2text(removed_paths, "\n")) var/list/offset = text2list(href_list["offset"],",") var/number = dd_range(1, 100, text2num(href_list["object_count"])) @@ -1978,41 +2031,36 @@ if(!obj_dir || !(obj_dir in list(1,2,4,8,5,6,9,10))) obj_dir = 2 var/obj_name = sanitize(href_list["object_name"]) + + + var/atom/target //Where the object will be spawned var/where = href_list["object_where"] if (!( where in list("onfloor","inhand","inmarked") )) where = "onfloor" - if( where == "inhand" ) - usr << "Support for inhand not available yet. Will spawn on floor." - where = "onfloor" - if ( where == "inhand" ) //Can only give when human or monkey - if ( !( ishuman(usr) ) ) - usr << "Can only spawn in hand when you're a human or a monkey." - where = "onfloor" - else if ( usr.get_active_hand() ) - usr << "Your active hand is full. Spawning on floor." - where = "onfloor" + switch(where) + if("inhand") + if (!iscarbon(usr) && !isrobot(usr)) + usr << "Can only spawn in hand when you're a carbon mob or cyborg." + where = "onfloor" + target = usr - if ( where == "inmarked" ) - if ( !marked_datum ) - usr << "You don't have any object marked. Abandoning spawn." - return - else - if ( !istype(marked_datum,/atom) ) - usr << "The object you have marked cannot be used as a target. Target must be of type /atom. Abandoning spawn." - return - - var/atom/target //Where the object will be spawned - switch ( where ) - if ( "onfloor" ) - switch (href_list["offset_type"]) + if("onfloor") + switch(href_list["offset_type"]) if ("absolute") target = locate(0 + X,0 + Y,0 + Z) if ("relative") target = locate(loc.x + X,loc.y + Y,loc.z + Z) - if ( "inmarked" ) - target = marked_datum + if("inmarked") + if(!marked_datum) + usr << "You don't have any object marked. Abandoning spawn." + return + else if(!istype(marked_datum,/atom)) + usr << "The object you have marked cannot be used as a target. Target must be of type /atom. Abandoning spawn." + return + else + target = marked_datum if(target) for (var/path in paths) @@ -2020,9 +2068,8 @@ if(path in typesof(/turf)) var/turf/O = target var/turf/N = O.ChangeTurf(path) - if(N) - if(obj_name) - N.name = obj_name + if(N && obj_name) + N.name = obj_name else var/atom/O = new path(target) if(O) @@ -2032,18 +2079,30 @@ if(istype(O,/mob)) var/mob/M = O M.real_name = obj_name + if(where == "inhand" && isliving(usr) && istype(O, /obj/item)) + var/mob/living/L = usr + var/obj/item/I = O + L.put_in_hands(I) + if(isrobot(L)) + var/mob/living/silicon/robot/R = L + if(R.module) + R.module.modules += I + I.loc = R.module + R.module.rebuild() + R.activate_module(I) + R.module.fix_modules() if (number == 1) log_admin("[key_name(usr)] created a [english_list(paths)]") for(var/path in paths) if(ispath(path, /mob)) - message_admins("[key_name_admin(usr)] created a [english_list(paths)]", 1) + message_admins("[key_name_admin(usr)] created a [english_list(paths)]") break else log_admin("[key_name(usr)] created [number]ea [english_list(paths)]") for(var/path in paths) if(ispath(path, /mob)) - message_admins("[key_name_admin(usr)] created [number]ea [english_list(paths)]", 1) + message_admins("[key_name_admin(usr)] created [number]ea [english_list(paths)]") break return @@ -2322,11 +2381,11 @@ S.long_jump(origin_area, destination_area, transition_area, move_duration) message_admins("\blue [key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle", 1) - log_admin("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle") + log_admin("[key_name(usr)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle") else S.short_jump(origin_area, destination_area) message_admins("\blue [key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle", 1) - log_admin("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle") + log_admin("[key_name(usr)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle") if("moveshuttle") @@ -2992,15 +3051,15 @@ if(isAI(target)) // AI core/eye follow links var/mob/living/silicon/ai/A = target - . = "JMP" + . = "FLW" if(A.client && A.eyeobj) // No point following clientless AI eyes - . += "|EYE" + . += "|EYE" return else if(istype(target, /mob/dead/observer)) var/mob/dead/observer/O = target - . = "JMP" + . = "FLW" if(O.mind && O.mind.current) - . += "|BDY" + . += "|BDY" return else - return "JMP" + return "FLW" diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 0a4b63a6892..1d7196c0d97 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -87,7 +87,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," mobs_found += found if(!ai_found && isAI(found)) ai_found = 1 - msg += "[original_word] (?) " + msg += "[original_word] " continue msg += "[original_word] " @@ -147,3 +147,31 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," send2adminirc("[selected_type] from [key_name(src)]: [original_msg]") feedback_add_details("admin_verb","AH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return + +/proc/send2irc_adminless_only(source, msg, requiredflags = R_BAN) + var/admin_number_total = 0 //Total number of admins + var/admin_number_afk = 0 //Holds the number of admins who are afk + var/admin_number_ignored = 0 //Holds the number of admins without +BAN (so admins who are not really admins) + var/admin_number_decrease = 0 //Holds the number of admins with are afk, ignored or both + for(var/client/X in admins) + admin_number_total++; + var/invalid = 0 + if(requiredflags != 0 && !check_rights_for(X, requiredflags)) + admin_number_ignored++ + invalid = 1 + if(X.is_afk()) + admin_number_afk++ + invalid = 1 + if(X.holder.fakekey) + admin_number_ignored++ + invalid = 1 + if(invalid) + admin_number_decrease++ + var/admin_number_present = admin_number_total - admin_number_decrease //Number of admins who are neither afk nor invalid + if(admin_number_present <= 0) + if(!admin_number_afk && !admin_number_ignored) + send2irc(source, "[msg] - No admins online") + else + send2irc(source, "[msg] - All admins AFK ([admin_number_afk]/[admin_number_total]) or skipped ([admin_number_ignored]/[admin_number_total])") + return admin_number_present + \ No newline at end of file diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index 932f54f0689..99385ee5ff6 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -1,30 +1,39 @@ -/client/proc/Jump(var/area/A in return_sorted_areas()) +/client/proc/Jump(area/A in return_sorted_areas()) set name = "Jump to Area" set desc = "Area to jump to" set category = "Admin" - if(!src.holder) - src << "Only administrators may use this command." + + if(!check_rights(R_ADMIN)) return - var/list/area_turfs = get_area_turfs(A) - if(area_turfs && area_turfs.len) - usr.loc = pick(area_turfs) - else - src << "That area has no turfs to jump to!" + if(!A) return + + var/list/turfs = list() + for(var/turf/T in A) + if(T.density) + continue + turfs.Add(T) + + var/turf/T = pick_n_take(turfs) + if(!T) + src << "Nowhere to jump to!" + return + + admin_forcemove(usr, T) log_admin("[key_name(usr)] jumped to [A]") - message_admins("[key_name_admin(usr)] jumped to [A]", 1) + message_admins("[key_name_admin(usr)] jumped to [A]") feedback_add_details("admin_verb","JA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/jumptoturf(var/turf/T in world) set name = "Jump to Turf" set category = "Admin" - if(!src.holder) - src << "Only administrators may use this command." + + if(!check_rights(R_ADMIN)) return - log_admin("[key_name(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]") - message_admins("[key_name_admin(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]", 1) + log_admin("[key_name(usr)] jumped to [T.x], [T.y], [T.z] in [T.loc]") + message_admins("[key_name_admin(usr)] jumped to [T.x], [T.y], [T.z] in [T.loc]", 1) usr.loc = T feedback_add_details("admin_verb","JT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return @@ -33,8 +42,7 @@ set category = "Admin" set name = "Jump to Mob" - if(!src.holder) - src << "Only administrators may use this command." + if(!check_rights(R_ADMIN)) return log_admin("[key_name(usr)] jumped to [key_name(M)]") @@ -44,7 +52,7 @@ var/turf/T = get_turf(M) if(T && isturf(T)) feedback_add_details("admin_verb","JM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - A.loc = T + admin_forcemove(A, M.loc) else A << "This mob is not located in the game world." @@ -52,8 +60,7 @@ set category = "Admin" set name = "Jump to Coordinate" - if (!holder) - src << "Only administrators may use this command." + if(!check_rights(R_ADMIN)) return if(src.mob) @@ -68,8 +75,7 @@ set category = "Admin" set name = "Jump to Key" - if(!src.holder) - src << "Only administrators may use this command." + if(!check_rights(R_ADMIN)) return var/list/keys = list() @@ -82,20 +88,22 @@ var/mob/M = selection:mob log_admin("[key_name(usr)] jumped to [key_name(M)]") message_admins("[key_name_admin(usr)] jumped to [key_name_admin(M)]", 1) - usr.loc = M.loc + + admin_forcemove(usr, M.loc) + feedback_add_details("admin_verb","JK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/Getmob(var/mob/M in mob_list) set category = "Admin" set name = "Get Mob" set desc = "Mob to teleport" - if(!src.holder) - src << "Only administrators may use this command." + + if(!check_rights(R_ADMIN)) return log_admin("[key_name(usr)] teleported [key_name(M)]") message_admins("[key_name_admin(usr)] teleported [key_name_admin(M)]", 1) - M.loc = get_turf(usr) + admin_forcemove(M, get_turf(usr)) feedback_add_details("admin_verb","GM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/Getkey() @@ -103,8 +111,7 @@ set name = "Get Key" set desc = "Key to teleport" - if(!src.holder) - src << "Only administrators may use this command." + if(!check_rights(R_ADMIN)) return var/list/keys = list() @@ -120,19 +127,27 @@ log_admin("[key_name(usr)] teleported [key_name(M)]") message_admins("[key_name_admin(usr)] teleported [key_name(M)]", 1) if(M) - M.loc = get_turf(usr) + admin_forcemove(M, get_turf(usr)) + usr.loc = M.loc feedback_add_details("admin_verb","GK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/sendmob(var/mob/M in sortmobs()) set category = "Admin" set name = "Send Mob" - if(!src.holder) - src << "Only administrators may use this command." + + if(!check_rights(R_ADMIN)) return + var/area/A = input(usr, "Pick an area.", "Pick an area") in return_sorted_areas() if(A) - M.loc = pick(get_area_turfs(A)) + admin_forcemove(M, pick(get_area_turfs(A))) feedback_add_details("admin_verb","SMOB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - log_admin("[key_name(usr)] teleported [key_name(M)] to [A]") - message_admins("[key_name_admin(usr)] teleported [key_name_admin(M)] to [A]", 1) \ No newline at end of file + message_admins("[key_name_admin(usr)] teleported [key_name_admin(M)] to [A]", 1) + +/proc/admin_forcemove(mob/mover, atom/newloc) + mover.loc = newloc + mover.on_forcemove(newloc) + +/mob/proc/on_forcemove(atom/newloc) + return diff --git a/code/modules/admin/verbs/check_customitem_activity.dm b/code/modules/admin/verbs/check_customitem_activity.dm index 19dfd6bbdce..18a796a0b08 100644 --- a/code/modules/admin/verbs/check_customitem_activity.dm +++ b/code/modules/admin/verbs/check_customitem_activity.dm @@ -55,7 +55,7 @@ var/inactive_keys = "None
" //run a query to get all ckeys inactive for over 2 months var/list/inactive_ckeys = list() if(ckeys_with_customitems.len) - var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey, lastseen FROM erro_player WHERE datediff(Now(), lastseen) > 60") + var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey, lastseen FROM [format_table_name("player")] WHERE datediff(Now(), lastseen) > 60") query_inactive.Execute() while(query_inactive.NextRow()) var/cur_ckey = query_inactive.item[1] @@ -67,7 +67,7 @@ var/inactive_keys = "None
" //if there are ckeys left over, check whether they have a database entry at all if(ckeys_with_customitems.len) for(var/cur_ckey in ckeys_with_customitems) - var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE ckey = '[cur_ckey]'") + var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ckey = '[cur_ckey]'") query_inactive.Execute() if(!query_inactive.RowCount()) inactive_ckeys += cur_ckey diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index eb6b02cc626..1673171ceec 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -922,7 +922,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that M.equip_to_slot_or_del(new /obj/item/device/radio/headset/ert/alt(M), slot_l_ear) M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/gun(M), slot_belt) M.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses(M), slot_glasses) - M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(M), slot_back) + M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/ert(M), slot_back) var/obj/item/weapon/card/id/W = new(M) W.name = "[M.real_name]'s ID Card (Emergency Response Team - Member)" @@ -944,7 +944,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that M.equip_to_slot_or_del(new /obj/item/device/radio/headset/ert/alt(M), slot_l_ear) M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/gun(M), slot_belt) M.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses(M), slot_glasses) - M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(M), slot_back) + M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/ert/commander(M), slot_back) var/obj/item/weapon/card/id/W = new(M) W.name = "[M.real_name]'s ID Card (Emergency Response Team - Leader)" diff --git a/code/modules/admin/verbs/freeze.dm b/code/modules/admin/verbs/freeze.dm index 128ef87060b..2d3314bd045 100644 --- a/code/modules/admin/verbs/freeze.dm +++ b/code/modules/admin/verbs/freeze.dm @@ -26,8 +26,8 @@ var/global/list/frozen_mob_list = list() /mob/living/proc/admin_Freeze(var/client/admin) if(istype(admin)) - src << "You have been frozen by [admin.key]" - message_admins("\blue [key_name_admin(admin)] froze [key_name(src)]") + src << "You have been frozen by [key_name(admin)]" + message_admins("[key_name_admin(admin)] froze [key_name_admin(src)]") log_admin("[key_name(admin)] froze [key_name(src)]") var/obj/effect/overlay/adminoverlay/AO = new @@ -42,8 +42,8 @@ var/global/list/frozen_mob_list = list() /mob/living/proc/admin_unFreeze(var/client/admin) if(istype(admin)) - src << "You have been unfrozen by [key]" - message_admins("\blue [key_name_admin(admin)] unfroze [key_name(src)]") + src << "You have been unfrozen by [key_name(admin)]" + message_admins("\blue [key_name_admin(admin)] unfroze [key_name_admin(src)]") log_admin("[key_name(admin)] unfroze [key_name(src)]") update_icons() diff --git a/code/modules/admin/verbs/honksquad.dm b/code/modules/admin/verbs/honksquad.dm index 9b383a93d17..e64cbf66574 100644 --- a/code/modules/admin/verbs/honksquad.dm +++ b/code/modules/admin/verbs/honksquad.dm @@ -79,13 +79,13 @@ var/global/sent_honksquad = 0 var/honksquad_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major") var/honksquad_name = pick(clown_names) - new_honksquad.gender = pick(MALE, FEMALE) - var/datum/preferences/A = new()//Randomize appearance for the commando. - A.randomize_appearance_for(new_honksquad) - - new_honksquad.real_name = "[!honk_leader_selected ? honksquad_rank : honksquad_leader_rank] [honksquad_name]" - new_honksquad.age = !honk_leader_selected ? rand(23,35) : rand(35,45) + if(honk_leader_selected) + A.age = rand(35,45) + A.real_name = "[honksquad_leader_rank] [honksquad_name]" + else + A.real_name = "[honksquad_rank] [honksquad_name]" + A.copy_to(new_honksquad) new_honksquad.dna.ready_dna(new_honksquad)//Creates DNA. diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 319c76a6974..5acf6c21b44 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -118,33 +118,37 @@ var/intercom_range_display_status = 0 del(F) feedback_add_details("admin_verb","mIRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +var/list/admin_verbs_show_debug_verbs = list( + /client/proc/camera_view, //-errorage + /client/proc/sec_camera_report, //-errorage + /client/proc/intercom_view, //-errorage + /client/proc/Cell, //More air things + /client/proc/atmosscan, //check plumbing + /client/proc/powerdebug, //check power + /client/proc/count_objects_on_z_level, + /client/proc/count_objects_all, + /client/proc/cmd_assume_direct_control, //-errorage + /client/proc/startSinglo, + /client/proc/ticklag, + /client/proc/cmd_admin_grantfullaccess, +// /client/proc/splash, + /client/proc/cmd_admin_areatest, + /client/proc/cmd_admin_rejuvenate, + /datum/admins/proc/show_traitor_panel, + /client/proc/print_jobban_old, + /client/proc/print_jobban_old_filter, + /client/proc/forceEvent, + ///client/proc/cmd_admin_rejuvenate, + /client/proc/nanomapgen_DumpImage +) + /client/proc/enable_debug_verbs() set category = "Debug" set name = "Debug verbs" if(!check_rights(R_DEBUG)) return - src.verbs += /client/proc/camera_view //-errorage - src.verbs += /client/proc/sec_camera_report //-errorage - src.verbs += /client/proc/intercom_view //-errorage - src.verbs += /client/proc/Cell //More air things - src.verbs += /client/proc/atmosscan //check plumbing - src.verbs += /client/proc/powerdebug //check power - src.verbs += /client/proc/count_objects_on_z_level - src.verbs += /client/proc/count_objects_all - src.verbs += /client/proc/cmd_assume_direct_control //-errorage - src.verbs += /client/proc/startSinglo - src.verbs += /client/proc/ticklag - src.verbs += /client/proc/cmd_admin_grantfullaccess -// src.verbs += /client/proc/splash - src.verbs += /client/proc/cmd_admin_areatest - src.verbs += /client/proc/cmd_admin_rejuvenate - src.verbs += /datum/admins/proc/show_traitor_panel - src.verbs += /client/proc/print_jobban_old - src.verbs += /client/proc/print_jobban_old_filter - src.verbs += /client/proc/forceEvent - //src.verbs += /client/proc/cmd_admin_rejuvenate - src.verbs += /client/proc/nanomapgen_DumpImage + verbs += admin_verbs_show_debug_verbs feedback_add_details("admin_verb","mDV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 6bb2f96ba06..93e5bb5c078 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -396,16 +396,8 @@ client/proc/one_click_antag() //First we spawn a dude. var/mob/living/carbon/human/new_character = new(pick(latejoin))//The mob being spawned. - new_character.gender = pick(MALE,FEMALE) - var/datum/preferences/A = new() - A.randomize_appearance_for(new_character) - if(new_character.gender == MALE) - new_character.real_name = "[pick(first_names_male)] [pick(last_names)]" - else - new_character.real_name = "[pick(first_names_female)] [pick(last_names)]" - new_character.name = new_character.real_name - new_character.age = rand(17,45) + A.copy_to(new_character) new_character.dna.ready_dna(new_character) new_character.key = G_found.key @@ -418,14 +410,13 @@ client/proc/one_click_antag() var/syndicate_commando_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major") var/syndicate_commando_name = pick(last_names) - new_syndicate_commando.gender = pick(MALE, FEMALE) - var/datum/preferences/A = new()//Randomize appearance for the commando. - A.randomize_appearance_for(new_syndicate_commando) - - new_syndicate_commando.real_name = "[!syndicate_leader_selected ? syndicate_commando_rank : syndicate_commando_leader_rank] [syndicate_commando_name]" - new_syndicate_commando.name = new_syndicate_commando.real_name - new_syndicate_commando.age = !syndicate_leader_selected ? rand(23,35) : rand(35,45) + if(syndicate_leader_selected) + A.real_name = "[syndicate_commando_leader_rank] [syndicate_commando_name]" + A.age = rand(35,45) + else + A.real_name = "[syndicate_commando_rank] [syndicate_commando_name]" + A.copy_to(new_syndicate_commando) new_syndicate_commando.dna.ready_dna(new_syndicate_commando)//Creates DNA. @@ -610,14 +601,7 @@ client/proc/one_click_antag() var/mob/living/carbon/human/newMember = new(L.loc) - newMember.gender = pick(MALE,FEMALE) - A.randomize_appearance_for(newMember) - if(newMember.gender == MALE) - newMember.real_name = "[pick(first_names_male)] [pick(last_names)]" - else - newMember.real_name = "[pick(first_names_female)] [pick(last_names)]" - newMember.name = newMember.real_name - newMember.age = rand(17,45) + A.copy_to(newMember) newMember.dna.ready_dna(newMember) @@ -639,14 +623,7 @@ client/proc/one_click_antag() var/mob/living/carbon/human/newMember = new(L.loc) - newMember.gender = pick(MALE,FEMALE) - A.randomize_appearance_for(newMember) - if(newMember.gender == MALE) - newMember.real_name = "[pick(first_names_male)] [pick(last_names)]" - else - newMember.real_name = "[pick(first_names_female)] [pick(last_names)]" - newMember.name = newMember.real_name - newMember.age = rand(17,45) + A.copy_to(newMember) newMember.dna.ready_dna(newMember) diff --git a/code/modules/admin/verbs/possess.dm b/code/modules/admin/verbs/possess.dm index bb1a6b56480..e6c5659f63b 100644 --- a/code/modules/admin/verbs/possess.dm +++ b/code/modules/admin/verbs/possess.dm @@ -11,10 +11,10 @@ if(T) log_admin("[key_name(usr)] has possessed [O] ([O.type]) at ([T.x], [T.y], [T.z])") - message_admins("[key_name(usr)] has possessed [O] ([O.type]) at ([T.x], [T.y], [T.z])", 1) + message_admins("[key_name_admin(usr)] has possessed [O] ([O.type]) at ([T.x], [T.y], [T.z])", 1) else log_admin("[key_name(usr)] has possessed [O] ([O.type]) at an unknown location") - message_admins("[key_name(usr)] has possessed [O] ([O.type]) at an unknown location", 1) + message_admins("[key_name_admin(usr)] has possessed [O] ([O.type]) at an unknown location", 1) if(!usr.control_object) //If you're not already possessing something... usr.name_archive = usr.real_name diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 75eda3ea588..6c281461e89 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -107,7 +107,7 @@ return world << "[msg]" log_admin("GlobalNarrate: [key_name(usr)] : [msg]") - message_admins("\blue \bold GlobalNarrate: [key_name_admin(usr)] : [msg]
", 1) + message_admins("\blue \bold GlobalNarrate: [key_name_admin(usr)]: [msg]
", 1) feedback_add_details("admin_verb","GLN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_admin_direct_narrate(var/mob/M) // Targetted narrate -- TLE @@ -128,8 +128,8 @@ return M << msg - log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]") - message_admins("\blue \bold DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]
", 1) + log_admin("DirectNarrate: [key_name(usr)] to ([key_name(M)]): [msg]") + message_admins("\blue \bold DirectNarrate: [key_name_admin(usr)] to ([key_name_admin(M)]): [msg]
", 1) feedback_add_details("admin_verb","DIRN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_admin_godmode(mob/M as mob in mob_list) @@ -433,14 +433,11 @@ Traitors and the like can also be revived with the previous role mostly intact. else new_character.gender = pick(MALE,FEMALE) var/datum/preferences/A = new() - A.randomize_appearance_for(new_character) - new_character.real_name = G_found.real_name + A.real_name = G_found.real_name + A.copy_to(new_character) if(!new_character.real_name) - if(new_character.gender == MALE) - new_character.real_name = capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names)) - else - new_character.real_name = capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names)) + new_character.real_name = random_name(new_character.gender) new_character.name = new_character.real_name if(G_found.mind && !G_found.mind.active) @@ -472,10 +469,6 @@ Traitors and the like can also be revived with the previous role mostly intact. If they don't have a mind, they obviously don't have a special role. */ - //Two variables to properly announce later on. - var/admin = key_name_admin(src) - var/player_key = G_found.key - //Now for special roles and equipment. switch(new_character.mind.special_role) if("traitor") @@ -519,7 +512,7 @@ Traitors and the like can also be revived with the previous role mostly intact. if(alert(new_character,"Would you like an active AI to announce this character?",,"No","Yes")=="Yes") call(/mob/new_player/proc/AnnounceArrival)(new_character, new_character.mind.assigned_role) - message_admins("\blue [admin] has respawned [player_key] as [new_character.real_name].", 1) + message_admins("\blue [key_name_admin(usr)] has respawned [key_name_admin(G_found)] as [new_character.real_name].", 1) new_character << "You have been fully respawned. Enjoy the game." @@ -728,8 +721,8 @@ Traitors and the like can also be revived with the previous role mostly intact. if (heavy || light) empulse(O, heavy, light) - log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at ([O.x],[O.y],[O.z])") - message_admins("[key_name_admin(usr)] created an EM PUlse ([heavy],[light]) at ([O.x],[O.y],[O.z])", 1) + log_admin("[key_name(usr)] created an EM pulse ([heavy], [light]) at ([O.x],[O.y],[O.z])") + message_admins("[key_name_admin(usr)] created an EM pulse ([heavy], [light]) at ([O.x],[O.y],[O.z])", 1) feedback_add_details("admin_verb","EMP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return @@ -916,7 +909,7 @@ Traitors and the like can also be revived with the previous role mostly intact. choice = input("Is this an emergency evacuation or a crew transfer?") in list("Emergency", "Crew Transfer") if (choice == "Emergency") - var/reason = stripped_input(usr, "Optional: Please enter the reason for calling the shuttle.", "Shuttle Call Reason.","") as text|null + var/reason = input(usr, "Optional: Please enter the reason for calling the shuttle.", "Shuttle Call Reason.","") as text|null emergency_shuttle.call_evac(reason) else emergency_shuttle.call_transfer() diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm index 347f461dca8..c4fda49439a 100644 --- a/code/modules/admin/verbs/striketeam.dm +++ b/code/modules/admin/verbs/striketeam.dm @@ -104,13 +104,13 @@ var/global/sent_strike_team = 0 var/commando_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major") var/commando_name = pick(last_names) - new_commando.gender = pick(MALE, FEMALE) - var/datum/preferences/A = new()//Randomize appearance for the commando. - A.randomize_appearance_for(new_commando) - - new_commando.real_name = "[!leader_selected ? commando_rank : commando_leader_rank] [commando_name]" - new_commando.age = !leader_selected ? rand(23,35) : rand(35,45) + if(leader_selected) + A.age = rand(35,45) + A.real_name = "[commando_leader_rank] [commando_name]" + else + A.real_name = "[commando_rank] [commando_name]" + A.copy_to(new_commando) new_commando.dna.ready_dna(new_commando)//Creates DNA. diff --git a/code/modules/admin/verbs/striketeam_syndicate.dm b/code/modules/admin/verbs/striketeam_syndicate.dm index 3113e58c2be..42a635feafb 100644 --- a/code/modules/admin/verbs/striketeam_syndicate.dm +++ b/code/modules/admin/verbs/striketeam_syndicate.dm @@ -108,13 +108,13 @@ var/global/sent_syndicate_strike_team = 0 var/syndicate_commando_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major") var/syndicate_commando_name = pick(last_names) - new_syndicate_commando.gender = pick(MALE, FEMALE) - var/datum/preferences/A = new()//Randomize appearance for the commando. - A.randomize_appearance_for(new_syndicate_commando) - - new_syndicate_commando.real_name = "[!syndicate_leader_selected ? syndicate_commando_rank : syndicate_commando_leader_rank] [syndicate_commando_name]" - new_syndicate_commando.age = !syndicate_leader_selected ? rand(23,35) : rand(35,45) + if(syndicate_leader_selected) + A.age = rand(35,45) + A.real_name = "[syndicate_commando_leader_rank] [syndicate_commando_name]" + else + A.real_name = "[syndicate_commando_rank] [syndicate_commando_name]" + A.copy_to(new_syndicate_commando) new_syndicate_commando.dna.ready_dna(new_syndicate_commando)//Creates DNA. diff --git a/code/modules/admin/verbs/ticklag.dm b/code/modules/admin/verbs/ticklag.dm index 928ba733caa..defe8f7d846 100644 --- a/code/modules/admin/verbs/ticklag.dm +++ b/code/modules/admin/verbs/ticklag.dm @@ -11,7 +11,7 @@ //I've used ticks of 2 before to help with serious singulo lags if(newtick && newtick <= 2 && newtick > 0) log_admin("[key_name(src)] has modified world.tick_lag to [newtick]", 0) - message_admins("[key_name(src)] has modified world.tick_lag to [newtick]", 0) + message_admins("[key_name_admin(src)] has modified world.tick_lag to [newtick]", 0) world.tick_lag = newtick feedback_add_details("admin_verb","TICKLAG") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm index 8085fefd999..ec2277c22dd 100644 --- a/code/modules/assembly/bomb.dm +++ b/code/modules/assembly/bomb.dm @@ -44,12 +44,12 @@ if((istype(W, /obj/item/weapon/weldingtool) && W:welding)) if(!status) status = 1 - bombers += "[key_name(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]" - msg_admin_attack("[key_name_admin(user)][isAntag(user) ? "(ANTAG)" : ""] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]") + bombers += "[key_name(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]" + msg_admin_attack("[key_name_admin(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]") user << "A pressure hole has been bored to [bombtank] valve. \The [bombtank] can now be ignited." else status = 0 - bombers += "[key_name(user)] unwelded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]" + bombers += "[key_name(user)] unwelded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]" user << "The hole has been closed." add_fingerprint(user) ..() diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index f773d23229f..2b0e72aaade 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -53,7 +53,7 @@ process() if(timing && (time > 0)) - time-- + time -= 2 // 2 seconds per process() if(timing && time <= 0) timing = repeat timer_end() @@ -110,6 +110,10 @@ if(href_list["time"]) timing = !timing + if(timing && istype(holder, /obj/item/device/transfer_valve)) + message_admins("[key_name_admin(usr)] activated [src] attachment on [holder].") + bombers += "[key_name(usr)] activated [src] attachment for [loc]" + log_game("[key_name(usr)] activated [src] attachment for [loc]") update_icon() if(href_list["reset"]) time = set_time @@ -120,7 +124,7 @@ if(href_list["tp"]) var/tp = text2num(href_list["tp"]) set_time += tp - set_time = min(max(round(set_time), 5), 600) + set_time = min(max(round(set_time), 6), 600) if(!timing) time = set_time diff --git a/code/modules/awaymissions/bluespaceartillery.dm b/code/modules/awaymissions/bluespaceartillery.dm index 41c2d08c22b..76a0e4d490b 100644 --- a/code/modules/awaymissions/bluespaceartillery.dm +++ b/code/modules/awaymissions/bluespaceartillery.dm @@ -2,7 +2,7 @@ name = "bluespace artillery control" icon_screen = "accelerator" icon_keyboard = "accelerator_key" - icon_state = "computer_wires" + icon_state = "computer-wires" req_access = list(access_cent_commander) var/last_fire = 0 var/reload_cooldown = 180 // 3 minute cooldown diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 88da993387e..80c4114059a 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -303,7 +303,7 @@ var/sql_ckey = sql_sanitize_text(src.ckey) - var/DBQuery/query = dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM erro_player WHERE ckey = '[sql_ckey]'") + var/DBQuery/query = dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'") query.Execute() var/sql_id = 0 player_age = 0 // New players won't have an entry so knowing we have a connection we set this to zero to be updated if their is a record. @@ -312,24 +312,30 @@ player_age = text2num(query.item[2]) break - var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE ip = '[address]'") + var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip = '[address]'") query_ip.Execute() related_accounts_ip = list() while(query_ip.NextRow()) if(ckey != query_ip.item[1]) related_accounts_ip.Add("[query_ip.item[1]]") - var/DBQuery/query_cid = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE computerid = '[computer_id]'") + var/DBQuery/query_cid = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE computerid = '[computer_id]'") query_cid.Execute() related_accounts_cid = list() while(query_cid.NextRow()) if(ckey != query_cid.item[1]) - related_accounts_cid.Add("[query_cid.item[1]]") - + related_accounts_cid.Add("[query_cid.item[1]]") + //Log all the alts if(related_accounts_cid.len) log_access("Alts: [key_name(src)]:[list2text(related_accounts_cid, " - ")]") + var/DBQuery/query_watch = dbcon.NewQuery("SELECT ckey, reason FROM [format_table_name("watch")] WHERE (ckey = '[sql_ckey]')") + query_watch.Execute() + if(query_watch.NextRow()) + message_admins("Notice: [key_name_admin(src)] is flagged for watching and has just connected - Reason: [query_watch.item[2]]") + send2irc_adminless_only("Watchlist", "[key_name_admin(src)] is flagged for watching and has just connected - Reason: [query_watch.item[2]]") + //Just the standard check to see if it's actually a number if(sql_id) if(istext(sql_id)) @@ -348,16 +354,16 @@ if(sql_id) //Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables - var/DBQuery/query_update = dbcon.NewQuery("UPDATE erro_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]") + var/DBQuery/query_update = dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]") query_update.Execute() else //New player!! Need to insert all the stuff - var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO erro_player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[sql_ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')") + var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO [format_table_name("player")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[sql_ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')") query_insert.Execute() //Logging player access var/serverip = "[world.internet_address]:[world.port]" - var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `erro_connection_log`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[sql_ckey]','[sql_ip]','[sql_computerid]');") + var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[sql_ckey]','[sql_ip]','[sql_computerid]');") query_accesslog.Execute() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 46327c2cd04..e2d4a48e58d 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -30,7 +30,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts num2text(BE_REV) = 14, num2text(BE_VAMPIRE) = 14, num2text(BE_BLOB) = 14, - num2text(BE_REVENANT) = 14, + num2text(BE_REVENANT) = 14, num2text(BE_OPERATIVE) = 21, num2text(BE_CULTIST) = 21, num2text(BE_RAIDER) = 21, @@ -104,8 +104,8 @@ datum/preferences var/age = 30 //age of character var/spawnpoint = "Arrivals Shuttle" //where this character will spawn (0-2). var/b_type = "A+" //blood type (not-chooseable) - var/underwear = 1 //underwear type - var/undershirt = 1 //undershirt type + var/underwear = "Nude" //underwear type + var/undershirt = "Nude" //undershirt type var/backbag = 2 //backpack type var/h_style = "Bald" //Hair type var/r_hair = 0 //Hair color @@ -185,14 +185,17 @@ datum/preferences var/volume = 100 /datum/preferences/New(client/C) b_type = pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") - if(istype(C)) - if(!IsGuestKey(C.key)) -// load_path(C.ckey) - if(load_preferences(C)) - if(load_character(C)) - return - gender = pick(MALE, FEMALE) + + var/loaded_preferences_successfully = load_preferences(C) + if(loaded_preferences_successfully) + if(load_character(C)) + return + //we couldn't load character data so just randomize the character appearance + name + random_character() //let's create a random character then - rather than a fat, bald and naked man. real_name = random_name(gender) + if(!loaded_preferences_successfully) + save_preferences(C) + save_character(C) //let's save this new random character so it doesn't keep generating new ones. /datum/preferences proc/ShowChoices(mob/user) @@ -316,11 +319,8 @@ datum/preferences dat += "\[...\]

" else dat += "

" - if(gender == MALE) - dat += "Underwear: [underwear_m[underwear]]
" - else - dat += "Underwear: [underwear_f[underwear]]
" - dat += "Undershirt: [undershirt_t[undershirt]]
" + dat += "Underwear:
[underwear]
" + dat += "Undershirt:
[undershirt]
" dat += "Backpack Type:
[backbaglist[backbag]]
" dat += "Nanotrasen Relation:
[nanotrasen_relation]
" dat += "Preview
" @@ -984,10 +984,10 @@ datum/preferences if("f_style") f_style = random_facial_hair_style(gender, species) if("underwear") - underwear = rand(1,underwear_m.len) + underwear = random_underwear(gender) ShowChoices(user) if("undershirt") - undershirt = rand(1,undershirt_t.len) + undershirt = random_undershirt(gender) ShowChoices(user) if("eyes") r_eyes = rand(0,255) @@ -1006,7 +1006,7 @@ datum/preferences /*if("skin_style") h_style = random_skin_style(gender)*/ if("all") - randomize_appearance_for() //no params needed + random_character() if("input") switch(href_list["preference"]) if("name") @@ -1176,16 +1176,17 @@ datum/preferences var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_options if(new_underwear) - underwear = underwear_options.Find(new_underwear) + underwear = new_underwear ShowChoices(user) if("undershirt") - var/list/undershirt_options - undershirt_options = undershirt_t - - var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_options - if (new_undershirt) - undershirt = undershirt_options.Find(new_undershirt) + var/new_undershirt + if(gender == MALE) + new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_m + else + new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_f + if(new_undershirt) + undershirt = new_undershirt ShowChoices(user) if("eyes") @@ -1340,7 +1341,7 @@ datum/preferences gender = FEMALE else gender = MALE - + underwear = random_underwear(gender) if("hear_adminhelps") sound ^= SOUND_ADMINHELP @@ -1410,7 +1411,10 @@ datum/preferences close_load_dialog(user) if("changeslot") - load_character(user,text2num(href_list["num"])) + if(!load_character(user,text2num(href_list["num"]))) + random_character() + real_name = random_name(gender) + save_character(user) close_load_dialog(user) if("tab") @@ -1420,7 +1424,7 @@ datum/preferences ShowChoices(user) return 1 - proc/copy_to(mob/living/carbon/human/character, safety = 0) + proc/copy_to(mob/living/carbon/human/character) if(be_random_name) real_name = random_name(gender,species) @@ -1517,12 +1521,7 @@ datum/preferences W.buckled_mob = character W.add_fingerprint(character) - if(underwear > underwear_m.len || underwear < 1) - underwear = 0 //I'm sure this is 100% unnecessary, but I'm paranoid... sue me. //HAH NOW NO MORE MAGIC CLONING UNDIES character.underwear = underwear - - if(undershirt > undershirt_t.len || undershirt < 1) - undershirt = 0 character.undershirt = undershirt if(backbag > 4 || backbag < 1) @@ -1532,7 +1531,7 @@ datum/preferences //Debugging report to track down a bug, which randomly assigned the plural gender to people. if(character.gender in list(PLURAL, NEUTER)) if(isliving(src)) //Ghosts get neuter by default - message_admins("[character] ([character.ckey]) has spawned with their gender as plural or neuter. Please notify coders.") + message_admins("[key_name_admin(character)] has spawned with their gender as plural or neuter. Please notify coders.") character.gender = MALE proc/open_load_dialog(mob/user) diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index f098ff77989..a9ce9b35621 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -1,6 +1,6 @@ /datum/preferences/proc/load_preferences(client/C) - var/DBQuery/query = dbcon.NewQuery("SELECT ooccolor,UI_style,UI_style_color,UI_style_alpha,be_special,default_slot,toggles,sound,randomslot,volume FROM erro_player WHERE ckey='[C.ckey]'") + var/DBQuery/query = dbcon.NewQuery("SELECT ooccolor,UI_style,UI_style_color,UI_style_alpha,be_special,default_slot,toggles,sound,randomslot,volume FROM [format_table_name("player")] WHERE ckey='[C.ckey]'") if(!query.Execute()) var/err = query.ErrorMsg() log_game("SQL ERROR during loading player preferences. Error : \[[err]\]\n") @@ -37,7 +37,7 @@ /datum/preferences/proc/save_preferences(client/C) - var/DBQuery/query = dbcon.NewQuery("UPDATE erro_player SET ooccolor='[ooccolor]',UI_style='[UI_style]',UI_style_color='[UI_style_color]',UI_style_alpha='[UI_style_alpha]',be_special='[be_special]',default_slot='[default_slot]',toggles='[toggles]',sound='[sound]',randomslot='[randomslot]',volume='[volume]' WHERE ckey='[C.ckey]'") + var/DBQuery/query = dbcon.NewQuery("UPDATE [format_table_name("player")] SET ooccolor='[ooccolor]',UI_style='[UI_style]',UI_style_color='[UI_style_color]',UI_style_alpha='[UI_style_alpha]',be_special='[be_special]',default_slot='[default_slot]',toggles='[toggles]',sound='[sound]',randomslot='[randomslot]',volume='[volume]' WHERE ckey='[C.ckey]'") if(!query.Execute()) var/err = query.ErrorMsg() log_game("SQL ERROR during saving player preferences. Error : \[[err]\]\n") @@ -51,7 +51,7 @@ slot = sanitize_integer(slot, 1, MAX_SAVE_SLOTS, initial(default_slot)) if(slot != default_slot) default_slot = slot - var/DBQuery/firstquery = dbcon.NewQuery("UPDATE erro_player SET default_slot=[slot] WHERE ckey='[C.ckey]'") + var/DBQuery/firstquery = dbcon.NewQuery("UPDATE [format_table_name("player")] SET default_slot=[slot] WHERE ckey='[C.ckey]'") firstquery.Execute() var/DBQuery/query = dbcon.NewQuery("SELECT * FROM characters WHERE ckey='[C.ckey]' AND slot='[slot]'") @@ -87,8 +87,8 @@ r_eyes = text2num(query.item[23]) g_eyes = text2num(query.item[24]) b_eyes = text2num(query.item[25]) - underwear = text2num(query.item[26]) - undershirt = text2num(query.item[27]) + underwear = query.item[26] + undershirt = query.item[27] backbag = text2num(query.item[28]) b_type = query.item[29] @@ -147,8 +147,8 @@ r_eyes = sanitize_integer(r_eyes, 0, 255, initial(r_eyes)) g_eyes = sanitize_integer(g_eyes, 0, 255, initial(g_eyes)) b_eyes = sanitize_integer(b_eyes, 0, 255, initial(b_eyes)) - underwear = sanitize_integer(underwear, 1, underwear_m.len, initial(underwear)) - undershirt = sanitize_integer(undershirt, 1, undershirt_t.len, initial(undershirt)) + underwear = sanitize_text(underwear, initial(underwear)) + undershirt = sanitize_text(undershirt, initial(undershirt)) backbag = sanitize_integer(backbag, 1, backbaglist.len, initial(backbag)) b_type = sanitize_text(b_type, initial(b_type)) @@ -204,7 +204,7 @@ message_admins("SQL ERROR during character slot saving. Error : \[[err]\]\n") return return 1 - +/* /datum/preferences/proc/random_character(client/C) var/DBQuery/query = dbcon.NewQuery("SELECT slot FROM characters WHERE ckey='[C.ckey]' ORDER BY slot") @@ -218,4 +218,4 @@ load_character(C) return 0 load_character(C,pick(saves)) - return 1 \ No newline at end of file + return 1*/ \ No newline at end of file diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index f7924a83ed7..be2b3a0c075 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -9,6 +9,7 @@ #define ASSIGNMENT_SECURITY "Security" var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT_LEVEL_MODERATE = "Moderate", EVENT_LEVEL_MAJOR = "Major") +var/list/event_last_fired = list() /datum/event_container var/severity = -1 @@ -134,8 +135,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Vermin Infestation",/datum/event/infestation, 100, list(ASSIGNMENT_JANITOR = 100)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Wallrot", /datum/event/wallrot, 0, list(ASSIGNMENT_ENGINEER = 30, ASSIGNMENT_GARDENER = 50)), // NON-BAY EVENTS - new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Cargo Bonus", /datum/event/cargo_bonus, 100), - new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Revenant", /datum/event/revenant, 50) + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Cargo Bonus", /datum/event/cargo_bonus, 100) ) /datum/event_container/moderate @@ -158,7 +158,6 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta(EVENT_LEVEL_MODERATE, "Spider Infestation", /datum/event/spider_infestation, 100, list(ASSIGNMENT_SECURITY = 30), 1), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Ion Storm", /datum/event/ion_storm, 0, list(ASSIGNMENT_AI = 50, ASSIGNMENT_CYBORG = 50, ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_SCIENTIST = 5)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Borer Infestation", /datum/event/borer_infestation, 20, list(ASSIGNMENT_SECURITY = 20), 1), - new /datum/event_meta/alien(EVENT_LEVEL_MODERATE, "Alien Infestation", /datum/event/alien_infestation, 0, list(ASSIGNMENT_SECURITY = 15), 1), //new /datum/event_meta/ninja(EVENT_LEVEL_MODERATE, "Space Ninja", /datum/event/space_ninja, 0, list(ASSIGNMENT_SECURITY = 15), 1), // NON-BAY EVENTS new /datum/event_meta(EVENT_LEVEL_MODERATE, "Mass Hallucination", /datum/event/mass_hallucination, 300), @@ -172,6 +171,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta(EVENT_LEVEL_MODERATE, "Bluespace Anomaly", /datum/event/anomaly/anomaly_bluespace, 50, list(ASSIGNMENT_ENGINEER = 25)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Flux Anomaly", /datum/event/anomaly/anomaly_flux, 50, list(ASSIGNMENT_ENGINEER = 50)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Gravitational Anomaly", /datum/event/anomaly/anomaly_grav, 200), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Revenant", /datum/event/revenant, 150) ) /datum/event_container/major @@ -183,6 +183,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta(EVENT_LEVEL_MAJOR, "Viral Infection", /datum/event/viral_infection, 0, list(ASSIGNMENT_MEDICAL = 30), 1), new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, 0, list(ASSIGNMENT_ENGINEER = 30), 1), new /datum/event_meta(EVENT_LEVEL_MAJOR, "Meteor Wave", /datum/event/meteor_wave, 0, list(ASSIGNMENT_ENGINEER = 3), 1), + new /datum/event_meta/alien(EVENT_LEVEL_MAJOR, "Alien Infestation", /datum/event/alien_infestation, 0, list(ASSIGNMENT_SECURITY = 30), 1), ) diff --git a/code/modules/events/event_dynamic.dm b/code/modules/events/event_dynamic.dm deleted file mode 100644 index 2a491a62b9d..00000000000 --- a/code/modules/events/event_dynamic.dm +++ /dev/null @@ -1,242 +0,0 @@ - -/* -/proc/start_events() - //changed to a while(1) loop since they are more efficient. - //Moved the spawn in here to allow it to be called with advance proc call if it crashes. - //and also to stop spawn copying variables from the game ticker - spawn(3000) - while(1) - /*if(prob(50))//Every 120 seconds and prob 50 2-4 weak spacedusts will hit the station - spawn(1) - dust_swarm("weak")*/ - if(!event) - //CARN: checks to see if random events are enabled. - if(config.allow_random_events) - hadevent = event() - else - Holiday_Random_Event() - else - event = 0 - sleep(2400) - */ - -var/list/event_last_fired = list() - -//Always triggers an event when called, dynamically chooses events based on job population -var/global/list/possibleEvents = list() -/proc/spawn_dynamic_event() - if(!config.allow_random_events) - return - - var/minutes_passed = world.time/600 - - var/list/active_with_role = number_active_with_role() - //var/engineer_count = number_active_with_role("Engineer") - //var/security_count = number_active_with_role("Security") - //var/medical_count = number_active_with_role("Medical") - //var/AI_count = number_active_with_role("AI") - //var/janitor_count = number_active_with_role("Janitor") - - // Maps event names to event chances - // For each chance, 100 represents "normal likelihood", anything below 100 is "reduced likelihood", anything above 100 is "increased likelihood" - // Events have to be manually added to this proc to happen - - //see: - // Code/WorkInProgress/Cael_Aislinn/Economy/Economy_Events.dm - // Code/WorkInProgress/Cael_Aislinn/Economy/Economy_Events_Mundane.dm - - possibleEvents[/datum/event/economic_event] = 300 - possibleEvents[/datum/event/trivial_news] = 400 - possibleEvents[/datum/event/mundane_news] = 300 - - possibleEvents[/datum/event/cargo_bonus] = 100 - possibleEvents[/datum/event/revenant] = 75 - - possibleEvents[/datum/event/pda_spam] = max(min(25, player_list.len) * 4, 200) - possibleEvents[/datum/event/money_lotto] = max(min(5, player_list.len), 50) - if(account_hack_attempted) - possibleEvents[/datum/event/money_hacker] = max(min(25, player_list.len) * 4, 200) - - possibleEvents[/datum/event/mass_hallucination] = 200 - possibleEvents[/datum/event/vent_clog] = 300 - possibleEvents[/datum/event/anomaly/anomaly_grav] = 200 - - possibleEvents[/datum/event/wormholes] = 150 - - possibleEvents[/datum/event/carp_migration] = 20 + 10 * active_with_role["Engineer"] - possibleEvents[/datum/event/dust] = 50 + 50 * active_with_role["Engineer"] - possibleEvents[/datum/event/dust/meaty] = 50 + 50 * active_with_role["Engineer"] - - possibleEvents[/datum/event/rogue_drone] = 5 + 25 * active_with_role["Engineer"] + 25 * active_with_role["Security"] - possibleEvents[/datum/event/infestation] = 100 + 100 * active_with_role["Janitor"] - - possibleEvents[/datum/event/communications_blackout] = 50 + 25 * active_with_role["AI"] + active_with_role["Scientist"] * 25 - possibleEvents[/datum/event/ion_storm] = active_with_role["AI"] * 25 + active_with_role["Cyborg"] * 25 + active_with_role["Engineer"] * 10 + active_with_role["Scientist"] * 5 -// possibleEvents[/datum/event/grid_check] = 25 + 10 * active_with_role["Engineer"] - possibleEvents[/datum/event/electrical_storm] = 15 * active_with_role["Janitor"] + 5 * active_with_role["Engineer"] - possibleEvents[/datum/event/wallrot] = 30 * active_with_role["Engineer"] + 50 * active_with_role["Botanist"] - possibleEvents[/datum/event/borer_infestation] = 50 + 15 * active_with_role["Security"] - - if(!spacevines_spawned) - possibleEvents[/datum/event/spacevine] = 10 + 5 * active_with_role["Engineer"] - if(minutes_passed >= 30) // Give engineers time to set up engine - possibleEvents[/datum/event/brand_intelligence] = 50 + 25 * active_with_role["Engineer"] - possibleEvents[/datum/event/anomaly/anomaly_pyro] = 100 + 60 * active_with_role["Engineer"] - possibleEvents[/datum/event/anomaly/anomaly_vortex] = 50 + 25 * active_with_role["Engineer"] - possibleEvents[/datum/event/anomaly/anomaly_bluespace] = 50 + 25 * active_with_role["Engineer"] - possibleEvents[/datum/event/anomaly/anomaly_flux] = 50 + 50 * active_with_role["Engineer"] - - possibleEvents[/datum/event/meteor_wave] = 10 * active_with_role["Engineer"] - possibleEvents[/datum/event/blob] = 10 * active_with_role["Engineer"] - - if(active_with_role["Medical"] > 0) - possibleEvents[/datum/event/radiation_storm] = active_with_role["Medical"] * 10 - possibleEvents[/datum/event/viral_infection] = active_with_role["Medical"] * 10 - - possibleEvents[/datum/event/prison_break] = active_with_role["Security"] * 50 - if(active_with_role["Security"] > 0) - if(!sent_spiders_to_station) - possibleEvents[/datum/event/spider_infestation] = max(active_with_role["Security"], 5) + 5 - if(aliens_allowed && !sent_aliens_to_station) - possibleEvents[/datum/event/alien_infestation] = max(active_with_role["Security"], 5) + 2.5 - /*if(!sent_ninja_to_station && toggle_space_ninja) - possibleEvents[/datum/event/space_ninja] = max(active_with_role["Security"], 5)*/ - possibleEvents[/datum/event/tear] = active_with_role["Security"] * 25 - - for(var/event_type in event_last_fired) if(possibleEvents[event_type]) - var/time_passed = world.time - event_last_fired[event_type] - var/full_recharge_after = 60 * 60 * 10 * 3 // 3 hours - var/weight_modifier = max(0, (full_recharge_after - time_passed) / 300) - - possibleEvents[event_type] = max(possibleEvents[event_type] - weight_modifier, 0) - - var/picked_event = pickweight(possibleEvents) - event_last_fired[picked_event] = world.time - - // Debug code below here, very useful for testing so don't delete please. - var/debug_message = "Firing random event. " - for(var/V in active_with_role) - debug_message += "#[V]:[active_with_role[V]] " - debug_message += "||| " - for(var/V in possibleEvents) - debug_message += "[V]:[possibleEvents[V]]" - debug_message += "|||Picked:[picked_event]" - log_debug(debug_message) - - if(!picked_event) - return - - //The event will add itself to the MC's event list - //and start working via the constructor. - new picked_event - - //moved this to proc/check_event() - /*var/chance = possibleEvents[picked_event] - var/base_chance = 0.4 - switch(player_list.len) - if(5 to 10) - base_chance = 0.6 - if(11 to 15) - base_chance = 0.7 - if(16 to 20) - base_chance = 0.8 - if(21 to 25) - base_chance = 0.9 - if(26 to 30) - base_chance = 1.0 - if(30 to 100000) - base_chance = 1.1 - - // Trigger the event based on how likely it currently is. - if(!prob(chance * eventchance * base_chance / 100)) - return 0*/ - - /*switch(picked_event) - if("Meteor") - command_announcement.Announce("Meteors have been detected on collision course with the station.", "Meteor Alert", new_sound = 'sound/AI/meteors.ogg') - spawn(100) - meteor_wave(10) - spawn_meteors() - spawn(700) - meteor_wave(10) - spawn_meteors() - if("Space Ninja") - //Handled in space_ninja.dm. Doesn't announce arrival, all sneaky-like. - space_ninja_arrival() - if("Radiation") - high_radiation_event() - if("Virus") - viral_outbreak() - if("Alien") - alien_infestation() - if("Prison Break") - prison_break() - if("Carp") - carp_migration() - if("Lights") - lightsout(1,2) - if("Appendicitis") - appendicitis() - if("Ion Storm") - IonStorm() - if("Spacevine") - spacevine_infestation() - if("Communications") - communications_blackout() - if("Grid Check") - grid_check() - if("Meteor") - meteor_shower()*/ - - return 1 - -// Returns how many characters are currently active(not logged out, not AFK for more than 10 minutes) -// with a specific role. -// Note that this isn't sorted by department, because e.g. having a roboticist shouldn't make meteors spawn. -/proc/number_active_with_role() - var/list/active_with_role = list() - active_with_role["Engineer"] = 0 - active_with_role["Medical"] = 0 - active_with_role["Security"] = 0 - active_with_role["Scientist"] = 0 - active_with_role["AI"] = 0 - active_with_role["Cyborg"] = 0 - active_with_role["Janitor"] = 0 - active_with_role["Botanist"] = 0 - active_with_role["Any"] = player_list.len - - for(var/mob/M in player_list) - if(!M.mind || !M.client || M.client.inactivity > 10 * 10 * 60) // longer than 10 minutes AFK counts them as inactive - continue - - if(istype(M, /mob/living/silicon/robot) && M:module && M:module.name == "engineering robot module") - active_with_role["Engineer"]++ - if(M.mind.assigned_role in list("Chief Engineer", "Station Engineer")) - active_with_role["Engineer"]++ - - if(istype(M, /mob/living/silicon/robot) && M:module && M:module.name == "medical robot module") - active_with_role["Medical"]++ - if(M.mind.assigned_role in list("Chief Medical Officer", "Medical Doctor")) - active_with_role["Medical"]++ - - if(istype(M, /mob/living/silicon/robot) && M:module && M:module.name == "security robot module") - active_with_role["Security"]++ - if(M.mind.assigned_role in security_positions) - active_with_role["Security"]++ - - if(M.mind.assigned_role in list("Research Director", "Scientist")) - active_with_role["Scientist"]++ - - if(M.mind.assigned_role == "AI") - active_with_role["AI"]++ - - if(M.mind.assigned_role == "Cyborg") - active_with_role["Cyborg"]++ - - if(M.mind.assigned_role == "Janitor") - active_with_role["Janitor"]++ - - if(M.mind.assigned_role == "Botanist") - active_with_role["Botanist"]++ - - return active_with_role diff --git a/code/modules/events/event_manager.dm b/code/modules/events/event_manager.dm index 7982fc1debf..b5fec993420 100644 --- a/code/modules/events/event_manager.dm +++ b/code/modules/events/event_manager.dm @@ -361,3 +361,54 @@ if(P.client) players++ return players + +// Returns how many characters are currently active(not logged out, not AFK for more than 10 minutes) +// with a specific role. +// Note that this isn't sorted by department, because e.g. having a roboticist shouldn't make meteors spawn. +/proc/number_active_with_role() + var/list/active_with_role = list() + active_with_role["Engineer"] = 0 + active_with_role["Medical"] = 0 + active_with_role["Security"] = 0 + active_with_role["Scientist"] = 0 + active_with_role["AI"] = 0 + active_with_role["Cyborg"] = 0 + active_with_role["Janitor"] = 0 + active_with_role["Botanist"] = 0 + active_with_role["Any"] = player_list.len + + for(var/mob/M in player_list) + if(!M.mind || !M.client || M.client.inactivity > 10 * 10 * 60) // longer than 10 minutes AFK counts them as inactive + continue + + if(istype(M, /mob/living/silicon/robot) && M:module && M:module.name == "engineering robot module") + active_with_role["Engineer"]++ + if(M.mind.assigned_role in list("Chief Engineer", "Station Engineer")) + active_with_role["Engineer"]++ + + if(istype(M, /mob/living/silicon/robot) && M:module && M:module.name == "medical robot module") + active_with_role["Medical"]++ + if(M.mind.assigned_role in list("Chief Medical Officer", "Medical Doctor")) + active_with_role["Medical"]++ + + if(istype(M, /mob/living/silicon/robot) && M:module && M:module.name == "security robot module") + active_with_role["Security"]++ + if(M.mind.assigned_role in security_positions) + active_with_role["Security"]++ + + if(M.mind.assigned_role in list("Research Director", "Scientist")) + active_with_role["Scientist"]++ + + if(M.mind.assigned_role == "AI") + active_with_role["AI"]++ + + if(M.mind.assigned_role == "Cyborg") + active_with_role["Cyborg"]++ + + if(M.mind.assigned_role == "Janitor") + active_with_role["Janitor"]++ + + if(M.mind.assigned_role == "Botanist") + active_with_role["Botanist"]++ + + return active_with_role diff --git a/code/modules/events/mass_hallucination.dm b/code/modules/events/mass_hallucination.dm index b3fbea5343c..c1778e060bc 100644 --- a/code/modules/events/mass_hallucination.dm +++ b/code/modules/events/mass_hallucination.dm @@ -3,4 +3,4 @@ if(!(C.species.flags & IS_SYNTHETIC)) C.hallucination += rand(50, 100) /datum/event/mass_hallucination/announce() - command_announcement.Announce("It seems that station [station_name()] is passing through a minor radiation field, this may cause some hallucination, but no further damage") \ No newline at end of file + command_announcement.Announce("It seems that station [station_name()] is passing through a minor radiation field, this may cause some hallucinations, but no further damage") diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm index d22c1338c38..2018558a055 100644 --- a/code/modules/events/radiation_storm.dm +++ b/code/modules/events/radiation_storm.dm @@ -39,7 +39,7 @@ for(var/i = 0, i < 10, i++) for(var/mob/living/carbon/human/H in living_mob_list) - if(H.species.flags & IS_SYNTHETIC) // Leave synthetics completely unaffected + if(H.species.flags & NO_DNA_RAD) // Leave synthetics completely unaffected continue var/turf/T = get_turf(H) if(!T) diff --git a/code/modules/events/tgevents/false_alarm.dm b/code/modules/events/tgevents/false_alarm.dm index 5d29829eaa8..b91ceeebfbf 100644 --- a/code/modules/events/tgevents/false_alarm.dm +++ b/code/modules/events/tgevents/false_alarm.dm @@ -3,8 +3,10 @@ endWhen = 1 /datum/event/falsealarm/announce() - var/datum/event/E = pick(possibleEvents) - var/datum/event/Event = new E - message_admins("False Alarm: [Event]") - Event.announce() //just announce it like it's happening - Event.kill() //do not process this event - no starts, no ticks, no ends + var/weight = pick(EVENT_LEVEL_MUNDANE,EVENT_LEVEL_MUNDANE,EVENT_LEVEL_MUNDANE,EVENT_LEVEL_MODERATE,EVENT_LEVEL_MODERATE,EVENT_LEVEL_MAJOR) + var/datum/event_container/container = event_manager.event_containers[weight] + var/datum/event/E = container.acquire_event() + var/datum/event/Event = new E + message_admins("False Alarm: [Event]") + Event.announce() //just announce it like it's happening + Event.kill() //do not process this event - no starts, no ticks, no ends diff --git a/code/modules/events/tgevents/mass_hallucination.dm b/code/modules/events/tgevents/mass_hallucination.dm index f23a2c15510..ffb6909aec2 100644 --- a/code/modules/events/tgevents/mass_hallucination.dm +++ b/code/modules/events/tgevents/mass_hallucination.dm @@ -3,7 +3,7 @@ /datum/event/mass_hallucination/start() for(var/mob/living/carbon/human/C in living_mob_list) - if(!(C.species.flags & IS_SYNTHETIC)) + if(!(C.species.flags & NO_DNA_RAD)) C.hallucination += rand(50, 100) /datum/event/mass_hallucination/announce() command_announcement.Announce("It seems that station [station_name()] is passing through a minor radiation field, this may cause some hallucination, but no further damage") \ No newline at end of file diff --git a/code/modules/garbage collection/gc_testing.dm b/code/modules/garbage collection/gc_testing.dm index 34467b15b5a..1682f5c5634 100644 --- a/code/modules/garbage collection/gc_testing.dm +++ b/code/modules/garbage collection/gc_testing.dm @@ -11,7 +11,7 @@ garbageCollector.del_everything = !garbageCollector.del_everything // world << "GC: qdel turned [garbageCollector.del_everything ? "off" : "on"]." log_admin("[key_name(usr)] turned qdel [garbageCollector.del_everything ? "off" : "on"].") - message_admins("\blue [key_name(usr)] turned qdel [garbageCollector.del_everything ? "off" : "on"].", 1) + message_admins("\blue [key_name_admin(usr)] turned qdel [garbageCollector.del_everything ? "off" : "on"].", 1) /client/proc/gc_toggle_profiling() set name = "(GC) Toggle Profiling" @@ -23,7 +23,7 @@ del_profiling = !del_profiling log_admin("[key_name(usr)] turned deletion profiling [del_profiling ? "on" : "off"].") - message_admins("\blue [key_name(usr)] turned deletion profiling [del_profiling ? "on" : "off"].", 1) + message_admins("\blue [key_name_admin(usr)] turned deletion profiling [del_profiling ? "on" : "off"].", 1) /client/proc/gc_show_del_report() set name = "(GC) Show Del Report" diff --git a/code/modules/genetics/side_effects.dm b/code/modules/genetics/side_effects.dm deleted file mode 100644 index a3153beaa59..00000000000 --- a/code/modules/genetics/side_effects.dm +++ /dev/null @@ -1,91 +0,0 @@ -/datum/genetics/side_effect - var/name // name of the side effect, to use as a header in the manual - var/symptom // description of the symptom of the side effect - var/treatment // description of the treatment of the side effect - var/effect // description of what happens when not treated - var/duration = 0 // delay between start() and finish() - - proc/start(mob/living/carbon/human/H) - // start the side effect, this should give some cue as to what's happening, - // such as gasping. These cues need to be unique among side-effects. - - proc/finish(mob/living/carbon/human/H) - // Finish the side-effect. This should first check whether the cure has been - // applied, and if not, cause bad things to happen. - -/datum/genetics/side_effect/genetic_burn - name = "Genetic Burn" - symptom = "Subject's skin turns unusualy red." - treatment = "Inject small dose of salbutamol." - effect = "Subject's skin burns." - duration = 10*30 - - start(mob/living/carbon/human/H) - H.emote("me", 1, "starts turning very red..") - - finish(mob/living/carbon/human/H) - if(!H.reagents.has_reagent("salbutamol")) - for(var/organ_name in list("chest","l_arm","r_arm","r_leg","l_leg","head","groin")) - var/obj/item/organ/external/E = H.get_organ(organ_name) - E.take_damage(0, 5, 0) - -/datum/genetics/side_effect/bone_snap - name = "Bone Snap" - symptom = "Subject's limbs tremble notably." - treatment = "Inject small dose of Styptic Powder." - effect = "Subject's bone breaks." - duration = 10*60 - - start(mob/living/carbon/human/H) - H.emote("me", 1, "'s limbs start shivering uncontrollably.") - - finish(mob/living/carbon/human/H) - if(!H.reagents.has_reagent("styptic_powder")) - var/organ_name = pick("chest","l_arm","r_arm","r_leg","l_leg","head","groin") - var/obj/item/organ/external/E = H.get_organ(organ_name) - E.take_damage(20, 0, 0) - E.fracture() - -/datum/genetics/side_effect/monkey - name = "Monkey" - symptom = "Subject starts drooling uncontrollably." - treatment = "Inject small dose of charcoal." - effect = "Subject turns into monkey." - duration = 10*90 - - start(mob/living/carbon/human/H) - H.emote("me", 1, "has drool running down from his mouth.") - - finish(mob/living/carbon/human/H) - if(!H.reagents.has_reagent("charcoal")) - H.monkeyize() - -/datum/genetics/side_effect/confuse - name = "Confuse" - symptom = "Subject starts drooling uncontrollably." - treatment = "Inject small dose of charcoal." - effect = "Subject becomes confused." - duration = 10*30 - - start(mob/living/carbon/human/H) - H.emote("me", 1, "has drool running down from his mouth.") - - finish(mob/living/carbon/human/H) - if(!H.reagents.has_reagent("charcoal")) - H.confused += 100 - -proc/trigger_side_effect(mob/living/carbon/human/H) - spawn - if(!istype(H)) return - var/tp = pick(subtypesof(/datum/genetics/side_effect)) - var/datum/genetics/side_effect/S = new tp - - S.start(H) - spawn(20) - if(!istype(H)) return - H.Weaken(rand(0, S.duration / 50)) - sleep(S.duration) - - if(!istype(H)) return - H.SetWeakened(0) - S.finish(H) \ No newline at end of file diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 17417104463..f494d7336db 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -302,9 +302,9 @@ user.lastattacked = M M.lastattacker = user - user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" - M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" ) + user.attack_log += "\[[time_stamp()]\] Attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" + M.attack_log += "\[[time_stamp()]\] Attacked by [key_name(user)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" + msg_admin_attack("[key_name_admin(user)] attacked [key_name_admin(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" ) if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index eb3a2a89fc1..9c19f780199 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -734,7 +734,7 @@ product = new /obj/item/weapon/reagent_containers/food/snacks/grown(get_turf(user),name) if(get_trait(TRAIT_PRODUCT_COLOUR)) if(modular_icon == 1) - if(!has_mob_product || (has_mob_product && has_mob_product != /mob/living/carbon/primitive/diona)) + if(!has_mob_product || (has_mob_product && has_mob_product != /mob/living/simple_animal/diona)) product.color = get_trait(TRAIT_PRODUCT_COLOUR) if(istype(product,/obj/item/weapon/reagent_containers/food)) var/obj/item/weapon/reagent_containers/food/food = product diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm index 919b2e5cbbc..ff24279989b 100644 --- a/code/modules/hydroponics/seed_datums.dm +++ b/code/modules/hydroponics/seed_datums.dm @@ -1184,7 +1184,7 @@ seed_noun = "nodes" display_name = "replicant pods" can_self_harvest = 1 - has_mob_product = /mob/living/carbon/primitive/diona + has_mob_product = /mob/living/simple_animal/diona /datum/seed/diona/New() ..() diff --git a/code/modules/hydroponics/seed_mobs.dm b/code/modules/hydroponics/seed_mobs.dm index d00baff79d7..b7fd3b4fdfd 100644 --- a/code/modules/hydroponics/seed_mobs.dm +++ b/code/modules/hydroponics/seed_mobs.dm @@ -69,7 +69,7 @@ host << "\green You awaken slowly, stirring into sluggish motion as the air caresses you." // This is a hack, replace with some kind of species blurb proc. - if(istype(host,/mob/living/carbon/primitive/diona)) + if(istype(host,/mob/living/simple_animal/diona)) host << "You are [host], one of a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders." host << "Too much darkness will send you into shock and starve you, but light will help you heal." diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index 077ad9ce444..76ede0d9d2d 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -140,8 +140,8 @@ return ..() /obj/machinery/portable_atmospherics/hydroponics/proc/attack_generic(var/mob/user) - if(istype(user,/mob/living/carbon/primitive/diona)) - var/mob/living/carbon/primitive/diona/nymph = user + if(istype(user,/mob/living/simple_animal/diona)) + var/mob/living/simple_animal/diona/nymph = user if(nymph.stat == DEAD || nymph.paralysis || nymph.weakened || nymph.stunned || nymph.restrained()) return diff --git a/code/modules/karma/karma.dm b/code/modules/karma/karma.dm index ed00a84e97c..4144c4ef5cc 100644 --- a/code/modules/karma/karma.dm +++ b/code/modules/karma/karma.dm @@ -63,8 +63,7 @@ var/list/karma_spenders = list() var/list/karma_list = list("Cancel") for(var/mob/M in player_list) if(M.client && M.mind) - var/special_role = M.mind.special_role - if (special_role == "Wizard" || special_role == "Ninja" || special_role == "Syndicate" || special_role == "Syndicate Commando" || special_role == "Vox Raider" || special_role == "Alien") // Don't include special roles, because players use it to meta + if(isNonCrewAntag(M)) // Don't include special roles, because players use it to meta continue karma_list += M diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index 22f90482727..b41f77a0b42 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -352,7 +352,7 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f usr << query.ErrorMsg() else log_game("[usr.name]/[usr.key] has uploaded the book titled [scanner.cache.name], [length(scanner.cache.dat)] signs") - message_admins("[usr.name]/[usr.key] has uploaded the book titled [scanner.cache.name], [length(scanner.cache.dat)] signs") + message_admins("[key_name_admin(usr)] has uploaded the book titled [scanner.cache.name], [length(scanner.cache.dat)] signs") alert("Upload Complete.") if(href_list["targetid"]) diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index f23bdb4d25a..96f23aaea0f 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -287,7 +287,7 @@ var/global/list/rockTurfEdgeCache if(z != 5) notify_admins = 1 if(!triggered_by_explosion) - message_admins("[key_name_admin(user)]? (FLW) has triggered a gibtonite deposit reaction at [A.name] (JMP).") + message_admins("[key_name_admin(user)] has triggered a gibtonite deposit reaction at [A.name] (JMP).") else message_admins("An explosion has triggered a gibtonite deposit reaction at [A.name] (JMP).") diff --git a/code/modules/mining/ore.dm b/code/modules/mining/ore.dm index cf66bdce72e..2815d1c5da7 100644 --- a/code/modules/mining/ore.dm +++ b/code/modules/mining/ore.dm @@ -174,9 +174,9 @@ if(triggered_by == 1) message_admins("An explosion has triggered a [name] to detonate at [A.name] (JMP).") else if(triggered_by == 2) - message_admins("A signal has triggered a [name] to detonate at [A.name] (JMP). Igniter attacher: [key_name_admin(attacher)]? (FLW)") + message_admins("A signal has triggered a [name] to detonate at [A.name] (JMP). Igniter attacher: [key_name_admin(attacher)]") else - message_admins("[key_name_admin(user)]? (FLW) has triggered a [name] to detonate at [A.name] (JMP).") + message_admins("[key_name_admin(user)] has triggered a [name] to detonate at [A.name] (JMP).") if(triggered_by == 1) log_game("An explosion has primed a [name] for detonation at [A.name]([bombturf.x],[bombturf.y],[bombturf.z])") else if(triggered_by == 2) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 84209d2ef37..6a2722470b2 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -311,13 +311,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(jobban_isbanned(M, "AntagHUD")) src << "\red You have been banned from using this feature" return - if(config.antag_hud_restricted && !M.has_enabled_antagHUD &&!client.holder) + if(config.antag_hud_restricted && !M.has_enabled_antagHUD && !check_rights(R_MOD,0)) var/response = alert(src, "If you turn this on, you will not be able to take any part in the round.","Are you sure you want to turn this feature on?","Yes","No") if(response == "No") return M.can_reenter_corpse = 0 if(M in respawnable_list) respawnable_list -= M - if(!M.has_enabled_antagHUD && !client.holder) + if(!M.has_enabled_antagHUD && !check_rights(R_MOD,0)) M.has_enabled_antagHUD = 1 if(M.antagHUD) M.antagHUD = 0 @@ -330,9 +330,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set category = "Ghost" set name = "Teleport" set desc= "Teleport to a location" - if(!istype(usr, /mob/dead/observer)) + + if(!isobserver(usr)) usr << "Not when you're not dead!" return + usr.verbs -= /mob/dead/observer/proc/dead_tele spawn(30) usr.verbs += /mob/dead/observer/proc/dead_tele @@ -348,7 +350,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(!L || !L.len) usr << "No area available." - usr.loc = pick(L) + usr.forceMove(pick(L)) /mob/dead/observer/verb/follow() set category = "Ghost" @@ -598,4 +600,5 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp //add images for the 60inv things ghosts can normally see when darkness is enabled so they can see them now client.images |= ghost_darkness_images if (ghostimage) - client.images -= ghostimage //remove ourself \ No newline at end of file + client.images -= ghostimage //remove ourself + \ No newline at end of file diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm index edee5035f2d..f99db44de5a 100644 --- a/code/modules/mob/hear_say.dm +++ b/code/modules/mob/hear_say.dm @@ -95,7 +95,7 @@ if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages if(!say_understands(speaker,language)) - if(istype(speaker,/mob/living/simple_animal)) + if(isanimal(speaker)) var/mob/living/simple_animal/S = speaker if(S.speak && S.speak.len) message = pick(S.speak) @@ -111,7 +111,8 @@ message = stars(message) var/speaker_name = "unknown" - if(speaker) speaker_name = speaker.name + if(speaker) + speaker_name = speaker.name if(vname) speaker_name = vname @@ -120,18 +121,17 @@ var/changed_voice - if(istype(src, /mob/living/silicon/ai) && !hard_to_hear) + if(isAI(src) && !hard_to_hear) var/jobname // the mob's "job" var/mob/living/carbon/human/impersonating //The crewmember being impersonated, if any. if (ishuman(speaker)) var/mob/living/carbon/human/H = speaker - if((H.wear_id && istype(H.wear_id,/obj/item/weapon/card/id/syndicate)) && (H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/gas/voice))) - + var/obj/item/weapon/card/id/id = H.wear_id + if((istype(id) && id.is_untrackable()) && H.HasVoiceChanger()) changed_voice = 1 var/mob/living/carbon/human/I = locate(speaker_name) - if(I) impersonating = I jobname = impersonating.get_assignment() @@ -141,28 +141,28 @@ jobname = H.get_assignment() else if (iscarbon(speaker)) // Nonhuman carbon mob - jobname = "No id" + jobname = "No ID" else if (isAI(speaker)) jobname = "AI" else if (isrobot(speaker)) jobname = "Cyborg" - else if (istype(speaker, /mob/living/silicon/pai)) + else if (ispAI(speaker)) jobname = "Personal AI" else jobname = "Unknown" if(changed_voice) if(impersonating) - track = "[speaker_name] ([jobname])" + track = "[speaker_name] ([jobname])" else track = "[speaker_name] ([jobname])" else - if(istype(follow_target, /obj/machinery/bot) && isAI(src)) - track = "[speaker_name] ([jobname])" + if(istype(follow_target, /obj/machinery/bot)) + track = "[speaker_name] ([jobname])" else - track = "[speaker_name] ([jobname])" + track = "[speaker_name] ([jobname])" - if(istype(src, /mob/dead/observer)) + if(isobserver(src)) if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs. speaker_name = "[speaker.real_name] ([speaker_name])" track = "[speaker_name] ([ghost_follow_link(follow_target, ghost=src)])" diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm index b11540db9f4..e1cae9e3c66 100644 --- a/code/modules/mob/language.dm +++ b/code/modules/mob/language.dm @@ -97,7 +97,7 @@ return (copytext(message, length(message)) == "!") ? 2 : 1 /datum/language/proc/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) - log_say("[key_name(speaker)] : ([name]) [message]") + log_say("[key_name(speaker)]: ([name]) [message]") if(!speaker_mask) speaker_mask = speaker.name var/msg = "[name], [speaker_mask] [format_message(message, get_spoken_verb(message))]" @@ -246,6 +246,13 @@ key = "5" flags = RESTRICTED | WHITELISTED syllables = list("02011","01222","10100","10210","21012","02011","21200","1002","2001","0002","0012","0012","000","120","121","201","220","10","11","0") + +/datum/language/machine/get_random_name() + if(prob(70)) + name = "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]" + else + name = pick(ai_names) + return name /datum/language/kidan name = "Chittin" @@ -468,7 +475,7 @@ if(drone_only && !istype(S,/mob/living/silicon/robot/drone)) continue else if(istype(S , /mob/living/silicon/ai)) - message_start = "[name], [speaker.name]" + message_start = "[name], [speaker.name]" else if (!S.binarycheck()) continue diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm index 4efc0c56dc6..3a60506ebe1 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm @@ -43,9 +43,11 @@ Doesn't work on other aliens/AI.*/ adjustToxLoss(-10) var/msg = sanitize(input("Message:", "Alien Whisper") as text|null) if(msg) - log_say("AlienWhisper: [key_name(src)]->[M.key] : [msg]") + log_say("Alien Whisper: [key_name(src)]->[key_name(M)]: [msg]") M << "You hear a strange, alien voice in your head...[msg]" - src << {"You said: "[msg]" to [M]"} + src << "You said: [msg] to [M]" + for(var/mob/dead/observer/G in player_list) + G.show_message("Alien message from [src] ([ghost_follow_link(src, ghost=G)]) to [M] ([ghost_follow_link(M, ghost=G)]): [msg]") return /mob/living/carbon/alien/humanoid/verb/transfer_plasma(mob/living/carbon/alien/M as mob in oview()) diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index d039311fe53..4c36d82202a 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -169,9 +169,9 @@ var/const/MAX_ACTIVE_TIME = 400 if(ishuman(target)) var/mob/living/carbon/human/H = target - if((H.species.flags & IS_SYNTHETIC)) + if(!H.check_has_mouth()) return - + if(!sterile) //target.contract_disease(new /datum/disease/alien_embryo(0)) //so infection chance is same as virus infection chance target.visible_message("[src] falls limp after violating [target]'s face!", \ diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm index 89e52b7e5ab..6265b1bdd9e 100644 --- a/code/modules/mob/living/carbon/brain/brain.dm +++ b/code/modules/mob/living/carbon/brain/brain.dm @@ -62,6 +62,14 @@ /mob/living/carbon/brain/blob_act() return + + +/mob/living/carbon/brain/on_forcemove(atom/newloc) + if(container) + container.loc = newloc + else //something went very wrong. + CRASH("Brainmob without container.") + loc = container /mob/living/carbon/brain/binarycheck() return istype(loc, /obj/item/device/mmi/posibrain) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index b67e2ad878e..b0b7d85e97e 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -452,9 +452,9 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, var/start_T_descriptor = "tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]" var/end_T_descriptor = "tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]" - M.attack_log += text("\[[time_stamp()]\] Has been thrown by [usr.name] ([usr.ckey]) from [start_T_descriptor] with the target [end_T_descriptor]") - usr.attack_log += text("\[[time_stamp()]\] Has thrown [M.name] ([M.ckey]) from [start_T_descriptor] with the target [end_T_descriptor]") - msg_admin_attack("[usr.name] ([usr.ckey])[isAntag(usr) ? "(ANTAG)" : ""] has thrown [M.name] ([M.ckey]) from [start_T_descriptor] with the target [end_T_descriptor] (JMP)") + M.attack_log += text("\[[time_stamp()]\] Has been thrown by [key_name(usr)] from [start_T_descriptor] with the target [end_T_descriptor]") + usr.attack_log += text("\[[time_stamp()]\] Has thrown [key_name(M)] from [start_T_descriptor] with the target [end_T_descriptor]") + msg_admin_attack("[key_name_admin(usr)] has thrown [key_name_admin(M)] from [start_T_descriptor] with the target [end_T_descriptor]") if(!iscarbon(usr)) M.LAssailant = null diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 721bf0fa6a8..a9cf1ea1094 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -5,7 +5,7 @@ canmove = 0 icon = null invisibility = 101 - if(!(species.flags & IS_SYNTHETIC)) + if(!isSynthetic()) animation = new(loc) animation.icon_state = "blank" animation.icon = 'icons/mob/mob.dmi' @@ -27,7 +27,7 @@ // Override the current limb status and don't cause an explosion E.droplimb(DROPLIMB_EDGE) - if(!(species.flags & IS_SYNTHETIC)) + if(!isSynthetic()) flick("gibbed-h", animation) hgibs(loc, viruses, dna) else diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index c0c11aa1aa7..c951a0a88ca 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -283,7 +283,7 @@ if(temp && !temp.is_stump()) if(temp.status & ORGAN_ROBOT) if(!(temp.brute_dam + temp.burn_dam)) - if(!(species.flags & IS_SYNTHETIC)) + if(!isSynthetic()) wound_flavor_text["[temp.limb_name]"] = "[t_He] has a robotic [temp.name]!\n" continue else diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index d2ad4b9dd71..5ae42000949 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -431,12 +431,10 @@ var/armor_block = run_armor_check(affecting, "melee") apply_damage(damage, BRUTE, affecting, armor_block) -/mob/living/carbon/human/proc/is_loyalty_implanted(mob/living/carbon/human/M) - if(!istype(M)) - return 0 - for(var/L in M.contents) +/mob/living/carbon/human/proc/is_loyalty_implanted() + for(var/L in contents) if(istype(L, /obj/item/weapon/implant/loyalty)) - for(var/obj/item/organ/external/O in M.organs) + for(var/obj/item/organ/external/O in organs) if(L in O.implants) return 1 return 0 @@ -696,6 +694,12 @@ // if looting pockets with gloves, do it quietly if(href_list["pockets"]) + if(isanimal(usr)) + return //animals cannot strip people + + if(frozen) + usr << "\red Do not attempt to strip frozen people." + return var/pocket_side = href_list["pockets"] var/pocket_id = (pocket_side == "right" ? slot_r_store : slot_l_store) var/obj/item/pocket_item = (pocket_id == slot_r_store ? src.r_store : src.l_store) @@ -722,16 +726,19 @@ // Update strip window if(usr.machine == src && in_range(src, usr)) show_inv(usr) - - - + else if(!pickpocket) // Display a warning if the user mocks up src << "You feel your [pocket_side] pocket being fumbled with!" - // if looting id with gloves, do it quietly - this allows pickpocket gloves to take/place id stealthily - Bone White if(href_list["item"]) + if(isanimal(usr)) + return //animals cannot strip people + + if(frozen) + usr << "\red Do not attempt to strip frozen people." + return var/itemTarget = href_list["item"] if(itemTarget == "id") if(pickpocket) @@ -764,9 +771,6 @@ // Display a warning if the user mocks up src << "You feel your ID slot being fumbled with!" - - - if (href_list["refresh"]) if((machine)&&(in_range(src, usr))) show_inv(machine) @@ -1126,26 +1130,47 @@ return /mob/living/carbon/human/can_inject(var/mob/user, var/error_msg, var/target_zone) - . = 1 // Default to returning true. - if(user && !target_zone) - target_zone = user.zone_sel.selecting - // If targeting the head, see if the head item is thin enough. - // If targeting anything else, see if the wear suit is thin enough. - if(above_neck(target_zone)) - if(head && head.flags & THICKMATERIAL) - . = 0 + . = 1 + + if(!target_zone) + if(!user) + target_zone = pick("chest","chest","chest","left leg","right leg","left arm", "right arm", "head") + else + target_zone = user.zone_sel.selecting + + var/obj/item/organ/external/affecting = get_organ(target_zone) + var/fail_msg + if(!affecting) + . = 0 + fail_msg = "They are missing that limb." + else if (affecting.status & ORGAN_ROBOT) + . = 0 + fail_msg = "That limb is robotic." else - if(wear_suit && wear_suit.flags & THICKMATERIAL) - . = 0 + switch(target_zone) + if("head") + if(head && head.flags & THICKMATERIAL) + . = 0 + else + if(wear_suit && wear_suit.flags & THICKMATERIAL) + . = 0 if(!. && error_msg && user) - // Might need re-wording. - user << "There is no exposed flesh or thin material [target_zone == "head" ? "on their head" : "on their body"]." + if(!fail_msg) + fail_msg = "There is no exposed flesh or thin material [target_zone == "head" ? "on their head" : "on their body"] to inject into." + user << "[fail_msg]" + +/mob/living/carbon/human/proc/check_has_mouth() + // Todo, check stomach organ when implemented. + var/obj/item/organ/external/head/H = get_organ("head") + if(!H || !H.can_intake_reagents) + return 0 + return 1 /mob/living/carbon/human/proc/vomit(hairball=0) - if(stat==2)return + if(stat==DEAD)return - if(species.flags & IS_SYNTHETIC) - return //Machines don't throw up. + if(!check_has_mouth()) + return if(!lastpuke) lastpuke = 1 diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 4a42d73357b..fe466cb1c74 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -63,13 +63,17 @@ help_shake_act(M) add_logs(src, M, "shaked") return 1 -// if(M.health < -75) return 0 - + if(!H.check_has_mouth()) + H << "You don't have a mouth, you cannot perform CPR!" + return + if(!check_has_mouth()) + H << "They don't have a mouth, you cannot perform CPR!" + return if((M.head && (M.head.flags & HEADCOVERSMOUTH)) || (M.wear_mask && (M.wear_mask.flags & MASKCOVERSMOUTH) && !M.wear_mask.mask_adjusted)) - M << "Remove your mask!" + M << "Remove your mask!" return 0 if((head && (head.flags & HEADCOVERSMOUTH)) || (wear_mask && (wear_mask.flags & MASKCOVERSMOUTH) && !wear_mask.mask_adjusted)) - M << "Remove his mask!" + M << "Remove his mask!" return 0 var/obj/effect/equip_e/human/O = new /obj/effect/equip_e/human() @@ -118,7 +122,7 @@ //we're good to suck the blood, blaah M.handle_bloodsucking(src) add_logs(src, M, "vampirebit") - message_admins("[M.name] ([M.ckey]) vampirebit [src.name] ([src.ckey])") + msg_admin_attack("[key_name_admin(M)] vampirebit [key_name_admin(src)]") return //end vampire codes diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index d72cef8de63..dcb1ee4e50c 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -11,13 +11,8 @@ total_burn += O.burn_dam health = 100 - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute //TODO: fix husking - if( (((100 - total_burn) < config.health_threshold_dead) && stat == DEAD) && (!(species.flags & IS_SYNTHETIC)))//100 only being used as the magic human max health number, feel free to change it if you add a var for it -- Urist + if( (((100 - total_burn) < config.health_threshold_dead) && stat == DEAD))//100 only being used as the magic human max health number, feel free to change it if you add a var for it -- Urist ChangeToHusk() - if (species.flags & IS_SYNTHETIC) - var/obj/item/organ/external/head/H = organs_by_name["head"] - if(H) - if((health >= (config.health_threshold_dead/100*75)) && stat == DEAD) //need to get them 25% away from death point before reviving synthetics - update_revive() if (stat == CONSCIOUS && (src in dead_mob_list)) //Defib fix update_revive() return @@ -31,17 +26,45 @@ tod = 0 timeofdeath = 0 +/mob/living/carbon/human/adjustBrainLoss(var/amount) + if(status_flags & GODMODE) return 0 //godmode + + if(species && species.has_organ["brain"]) + var/obj/item/organ/brain/sponge = internal_organs_by_name["brain"] + if(sponge) + sponge.take_damage(amount) + sponge.damage = min(max(sponge.damage, 0),(maxHealth*2)) + brainloss = sponge.damage + else + brainloss = 200 + else + brainloss = 0 + +/mob/living/carbon/human/setBrainLoss(var/amount) + if(status_flags & GODMODE) return 0 //godmode + + if(species && species.has_organ["brain"]) + var/obj/item/organ/brain/sponge = internal_organs_by_name["brain"] + if(sponge) + sponge.damage = min(max(amount, 0),(maxHealth*2)) + brainloss = sponge.damage + else + brainloss = 200 + else + brainloss = 0 + /mob/living/carbon/human/getBrainLoss() - var/res = brainloss - var/obj/item/organ/brain/sponge = internal_organs_by_name["brain"] - if(!sponge) - return - if (sponge.is_bruised()) - res += 20 - if (sponge.is_broken()) - res += 50 - res = min(res,maxHealth*2) - return res + if(status_flags & GODMODE) return 0 //godmode + + if(species && species.has_organ["brain"]) + var/obj/item/organ/brain/sponge = internal_organs_by_name["brain"] + if(sponge) + brainloss = min(sponge.damage,maxHealth*2) + else + brainloss = 200 + else + brainloss = 0 + return brainloss //These procs fetch a cumulative total damage from all organs /mob/living/carbon/human/getBruteLoss() @@ -114,13 +137,12 @@ /mob/living/carbon/human/Paralyse(amount) ..() - /mob/living/carbon/human/adjustCloneLoss(var/amount) - - if(species.flags & IS_SYNTHETIC) - return - ..() + + if(species.flags & (NO_SCAN)) + cloneloss = 0 + return var/heal_prob = max(0, 80 - getCloneLoss()) var/mut_prob = min(80, getCloneLoss()+10) @@ -151,6 +173,41 @@ O.unmutate() src << "Your [O.name] is shaped normally again." hud_updateflag |= 1 << HEALTH_HUD + +// Defined here solely to take species flags into account without having to recast at mob/living level. +/mob/living/carbon/human/getOxyLoss() + if(species.flags & NO_BREATHE) + oxyloss = 0 + return ..() + +/mob/living/carbon/human/adjustOxyLoss(var/amount) + if(species.flags & NO_BREATHE) + oxyloss = 0 + else + ..() + +/mob/living/carbon/human/setOxyLoss(var/amount) + if(species.flags & NO_BREATHE) + oxyloss = 0 + else + ..() + +/mob/living/carbon/human/getToxLoss() + if(species.flags & NO_POISON) + toxloss = 0 + return ..() + +/mob/living/carbon/human/adjustToxLoss(var/amount) + if(species.flags & NO_POISON) + toxloss = 0 + else + ..() + +/mob/living/carbon/human/setToxLoss(var/amount) + if(species.flags & NO_POISON) + toxloss = 0 + else + ..() //////////////////////////////////////////// diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index bccf63c73de..036dcc78803 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -35,13 +35,13 @@ emp_act if(check_shields(P.damage, "the [P.name]", P)) P.on_hit(src, 100, def_zone) return 2 - + + var/obj/item/organ/external/organ = get_organ(check_zone(def_zone)) + if(isnull(organ)) + return //Shrapnel if (P.damage_type == BRUTE) - var/obj/item/organ/external/organ = get_organ(check_zone(def_zone)) - if(!organ) - return var/armor = getarmor_organ(organ, "bullet") if((P.embed && prob(20 + max(P.damage - armor, -10)))) var/obj/item/weapon/shard/shrapnel/SP = new() @@ -50,9 +50,7 @@ emp_act (SP.loc) = organ organ.embed(SP) - var/mob/living/carbon/human/M = src - var/obj/item/organ/external/affected = M.get_organ(def_zone) - affected.add_autopsy_data(P.name, P.damage) // Add the bullet's name to the autopsy data + organ.add_autopsy_data(P.name, P.damage) // Add the bullet's name to the autopsy data return (..(P , def_zone)) @@ -204,11 +202,6 @@ emp_act for(var/obj/O in src) if(!O) continue O.emp_act(severity) - for(var/obj/item/organ/external/O in organs) - if(O.status & ORGAN_DESTROYED) continue - O.emp_act(severity) - for(var/obj/item/organ/I in O.internal_organs) - I.emp_act(severity) ..() /mob/living/carbon/human/emag_act(user as mob, var/obj/item/organ/external/affecting) @@ -239,9 +232,9 @@ emp_act --src.meatleft user << "\red You hack off a chunk of meat from [src.name]" if(!src.meatleft) - src.attack_log += "\[[time_stamp()]\] Was chopped up into meat by [user]/[user.ckey]" - user.attack_log += "\[[time_stamp()]\] Chopped up [src]/[src.ckey] into meat" - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] chopped up [src] ([src.ckey]) into meat (JMP)") + src.attack_log += "\[[time_stamp()]\] Was chopped up into meat by [key_name(user)]" + user.attack_log += "\[[time_stamp()]\] Chopped up [key_name(src)] into meat" + msg_admin_attack("[key_name_admin(user)] chopped up [key_name_admin(src)] into meat") if(!iscarbon(user)) LAssailant = null else @@ -394,12 +387,11 @@ emp_act if(ismob(O.thrower)) var/mob/M = O.thrower - var/client/assailant = M.client - if(assailant) - src.attack_log += text("\[[time_stamp()]\] Has been hit with a [O], thrown by [M.name] ([assailant.ckey])") - M.attack_log += text("\[[time_stamp()]\] Hit [src.name] ([src.ckey]) with a thrown [O]") + if(M) + src.attack_log += text("\[[time_stamp()]\] Has been hit with a [O], thrown by [key_name(M)]") + M.attack_log += text("\[[time_stamp()]\] Hit [key_name(src)] with a thrown [O]") if(!istype(src,/mob/living/simple_animal/mouse)) - msg_admin_attack("[src.name] ([src.ckey]) was hit by a [O], thrown by [M.name] ([assailant.ckey])[isAntag(M) ? "(ANTAG)" : ""] (JMP)") + msg_admin_attack("[key_name_admin(src)] was hit by a [O], thrown by [key_name_admin(M)]") //thrown weapon embedded object code. if(dtype == BRUTE && istype(O,/obj/item)) @@ -497,8 +489,11 @@ emp_act M.occupant_message("You hit [src].") visible_message("[src] has been hit by [M.name].", \ "[src] has been hit by [M.name].") - add_logs(M.occupant, src, "attacked", object=M, addition="(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") + attack_log += text("\[[time_stamp()]\] Has been attacked by \the [M] controlled by [key_name(M.occupant)] (INTENT: [uppertext(M.occupant.a_intent)])") + M.occupant.attack_log += text("\[[time_stamp()]\] Attacked [src] with \the [M] (INTENT: [uppertext(M.occupant.a_intent)])") + msg_admin_attack("[key_name_admin(M.occupant)] attacked [key_name_admin(src)] with \the [M] (INTENT: [uppertext(M.occupant.a_intent)])") + else ..() diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 39e0f052f2b..bc10d54b1c8 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -29,8 +29,8 @@ var/age = 30 //Player's age (pure fluff) var/b_type = "A+" //Player's bloodtype - var/underwear = 1 //Which underwear the player wants - var/undershirt = 0 //Which undershirt the player wants. + var/underwear = "Nude" //Which underwear the player wants + var/undershirt = "Nude" //Which undershirt the player wants. var/backbag = 2 //Which backpack type the player has chosen. Nothing, Satchel or Backpack. //Equipment slots diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm index 193f8373242..8889e5370da 100644 --- a/code/modules/mob/living/carbon/human/human_organs.dm +++ b/code/modules/mob/living/carbon/human/human_organs.dm @@ -72,11 +72,9 @@ for(var/limb_tag in list("l_leg","r_leg","l_foot","r_foot")) var/obj/item/organ/external/E = organs_by_name[limb_tag] - if(!E) - stance_damage += 2 - else if (E.status & ORGAN_DESTROYED) - stance_damage += 2 // let it fail even if just foot&leg - else if (E.is_malfunctioning() || (E.is_broken() && !(E.status & ORGAN_SPLINTED)) || !E.is_usable()) + if(!E || (E.status & (ORGAN_DESTROYED|ORGAN_DEAD)) || E.is_malfunctioning()) + stance_damage += 2 // let it fail even if just foot&leg. Also malfunctioning happens sporadically so it should impact more when it procs + else if (E.is_broken() || !E.is_usable()) stance_damage += 1 // Canes and crutches help you stand (if the latter is ever added) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index bc0504f29c9..507c8dab0ca 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -56,7 +56,7 @@ /mob/living/carbon/human/proc/has_organ(name) var/obj/item/organ/external/O = organs_by_name[name] - return (O && !(O.status & ORGAN_DESTROYED) ) + return (O && !(O.status & ORGAN_DESTROYED) && !O.is_stump()) /mob/living/carbon/human/proc/has_organ_for_slot(slot) switch(slot) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index d51d1f9de64..82f09f0f489 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -245,10 +245,6 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc adjustCloneLoss(0.1) /mob/living/carbon/human/proc/handle_mutations_and_radiation() - - if(species.flags & IS_SYNTHETIC) //Robots don't suffer from mutations or radloss. - return - if(getFireLoss()) if((RESIST_HEAT in mutations) || (prob(1))) heal_organ_damage(0,1) @@ -847,7 +843,7 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc if(species && species.flags & NO_INTORGANS) return - if(!(species.flags & IS_SYNTHETIC)) handle_trace_chems() + handle_trace_chems() updatehealth() @@ -904,7 +900,7 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc if(!reagents.has_reagent("epinephrine")) adjustOxyLoss(1)*/ - if(hallucination && !(species.flags & IS_SYNTHETIC)) + if(hallucination && !(species.flags & NO_DNA_RAD)) spawn handle_hallucinations() if(hallucination<=2) @@ -967,18 +963,35 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc if(!E.len) embedded_flag = 0 - - //Eyes - if(sdisabilities & BLIND) //disabled-blind, doesn't get better on its own - blinded = 1 - else if(eye_blind) //blindness, heals slowly over time - eye_blind = max(eye_blind-1,0) - blinded = 1 - else if(tinttotal >= TINT_BLIND) //covering your eyes heals blurry eyes faster - eye_blurry = max(eye_blurry-3, 0) - // blinded = 1 //now handled under /handle_regular_hud_updates() - else if(eye_blurry) //blurry eyes heal slowly - eye_blurry = max(eye_blurry-1, 0) + //Vision + var/obj/item/organ/vision + if(species.vision_organ) + vision = internal_organs_by_name[species.vision_organ] + + if(!species.vision_organ) // Presumably if a species has no vision organs, they see via some other means. + eye_blind = 0 + blinded = 0 + eye_blurry = 0 + else if(!vision || vision.is_broken()) // Vision organs cut out or broken? Permablind. + eye_blind = 1 + blinded = 1 + eye_blurry = 1 + else + //blindness + if(sdisabilities & BLIND) // Disabled-blind, doesn't get better on its own + blinded = 1 + else if(eye_blind) // Blindness, heals slowly over time + eye_blind = max(eye_blind-1,0) + blinded = 1 + else if(istype(glasses, /obj/item/clothing/glasses/sunglasses/blindfold)) //resting your eyes with a blindfold heals blurry eyes faster + eye_blurry = max(eye_blurry-3, 0) + blinded = 1 + + //blurry sight + if(vision.is_bruised()) // Vision organs impaired? Permablurry. + eye_blurry = 1 + if(eye_blurry) // Blurry eyes heal slowly + eye_blurry = max(eye_blurry-1, 0) //Ears if(sdisabilities & DEAF) //disabled-deaf, doesn't get better on its own @@ -1212,6 +1225,9 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc else if(!seer) see_in_dark = species.darksight see_invisible = SEE_INVISIBLE_LIVING + + if(see_override) //Override all + see_invisible = see_override if(ticker && ticker.mode.name == "nations") process_nations() @@ -1569,7 +1585,7 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc /mob/living/carbon/human/proc/handle_decay() var/decaytime = world.time - timeofdeath - if(species.flags & IS_SYNTHETIC) + if(isSynthetic()) return if(reagents.has_reagent("formaldehyde")) //embalming fluid stops decay diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 538a1dbbf50..0a38453c5fd 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -190,7 +190,7 @@ //These only pertain to common. Languages are handled by mob/say_understands() if (!speaking) - if (istype(other, /mob/living/carbon/primitive/diona)) + if (istype(other, /mob/living/simple_animal/diona)) if(other.languages.len >= 2) //They've sucked down some blood and can speak common now. return 1 if (istype(other, /mob/living/silicon)) @@ -207,16 +207,22 @@ // return 0 return ..() - -/mob/living/carbon/human/GetVoice() - - var/voice_sub + +/mob/living/carbon/human/proc/HasVoiceChanger() for(var/obj/item/gear in list(wear_mask,wear_suit,head)) if(!gear) continue var/obj/item/voice_changer/changer = locate() in gear if(changer && changer.active && changer.voice) - voice_sub = changer.voice + return changer + return 0 + +/mob/living/carbon/human/GetVoice() + + var/voice_sub + var/has_changer = HasVoiceChanger() + if(has_changer) + voice_sub = has_changer if(voice_sub) return voice_sub if(mind && mind.changeling && mind.changeling.mimicing) diff --git a/code/modules/mob/living/carbon/human/species/apollo.dm b/code/modules/mob/living/carbon/human/species/apollo.dm index fa428ac43a2..ccfc7d429ef 100644 --- a/code/modules/mob/living/carbon/human/species/apollo.dm +++ b/code/modules/mob/living/carbon/human/species/apollo.dm @@ -1,5 +1,6 @@ /datum/species/wryn name = "Wryn" + name_plural = "Wryn" icobase = 'icons/mob/human_races/r_wryn.dmi' deform = 'icons/mob/human_races/r_wryn.dmi' language = "Wryn Hivemind" @@ -76,6 +77,7 @@ /datum/species/nucleation name = "Nucleation" + name_plural = "Nucleations" icobase = 'icons/mob/human_races/r_nucleation.dmi' unarmed_type = /datum/unarmed_attack/punch blurb = "A sub-race of unforunates who have been exposed to too much supermatter radiation. As a result, \ diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm index cfc0eb08207..9c5a9ef851e 100644 --- a/code/modules/mob/living/carbon/human/species/golem.dm +++ b/code/modules/mob/living/carbon/human/species/golem.dm @@ -1,5 +1,6 @@ /datum/species/golem name = "Golem" + name_plural = "Golems" icobase = 'icons/mob/human_races/r_golem.dmi' deform = 'icons/mob/human_races/r_golem.dmi' diff --git a/code/modules/mob/living/carbon/human/species/monkey.dm b/code/modules/mob/living/carbon/human/species/monkey.dm index 7c3dbd46108..d8487e8d795 100644 --- a/code/modules/mob/living/carbon/human/species/monkey.dm +++ b/code/modules/mob/living/carbon/human/species/monkey.dm @@ -1,5 +1,6 @@ /datum/species/monkey name = "Monkey" + name_plural = "Monkeys" blurb = "Ook." icobase = 'icons/mob/human_races/monkeys/r_monkey.dmi' @@ -52,7 +53,8 @@ datum/species/monkey/get_random_name(var/gender) /datum/species/monkey/tajaran name = "Farwa" - + name_plural = "Farwa" + icobase = 'icons/mob/human_races/monkeys/r_farwa.dmi' deform = 'icons/mob/human_races/monkeys/r_farwa.dmi' @@ -66,6 +68,7 @@ datum/species/monkey/get_random_name(var/gender) /datum/species/monkey/vulpkanin name = "Wolpin" + name_plural = "Wolpin" icobase = 'icons/mob/human_races/monkeys/r_wolpin.dmi' deform = 'icons/mob/human_races/monkeys/r_wolpin.dmi' @@ -80,6 +83,7 @@ datum/species/monkey/get_random_name(var/gender) /datum/species/monkey/skrell name = "Neara" + name_plural = "Neara" icobase = 'icons/mob/human_races/monkeys/r_neara.dmi' deform = 'icons/mob/human_races/monkeys/r_neara.dmi' @@ -96,6 +100,7 @@ datum/species/monkey/get_random_name(var/gender) /datum/species/monkey/unathi name = "Stok" + name_plural = "Stok" icobase = 'icons/mob/human_races/monkeys/r_stok.dmi' deform = 'icons/mob/human_races/monkeys/r_stok.dmi' diff --git a/code/modules/mob/living/carbon/human/species/plasmaman.dm b/code/modules/mob/living/carbon/human/species/plasmaman.dm index 890a5c3102b..5c36ba41bbd 100644 --- a/code/modules/mob/living/carbon/human/species/plasmaman.dm +++ b/code/modules/mob/living/carbon/human/species/plasmaman.dm @@ -1,5 +1,6 @@ /datum/species/plasmaman // /vg/ name = "Plasmaman" + name_plural = "Plasmamen" icobase = 'icons/mob/human_races/r_plasmaman_sb.dmi' deform = 'icons/mob/human_races/r_plasmaman_pb.dmi' // TODO: Need deform. //language = "Clatter" diff --git a/code/modules/mob/living/carbon/human/species/shadow.dm b/code/modules/mob/living/carbon/human/species/shadow.dm index cd0b03fc745..3e888c026f8 100644 --- a/code/modules/mob/living/carbon/human/species/shadow.dm +++ b/code/modules/mob/living/carbon/human/species/shadow.dm @@ -1,6 +1,7 @@ /datum/species/shadow name = "Shadow" - + name_plural = "Shadows" + icobase = 'icons/mob/human_races/r_shadow.dmi' deform = 'icons/mob/human_races/r_shadow.dmi' diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 5113ea3144e..96d0d89030f 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -4,6 +4,7 @@ /datum/species var/name // Species name. + var/name_plural // Pluralized name (since "[name]s" is not always valid) var/path // Species path var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set. var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set. @@ -37,7 +38,7 @@ var/heat_level_3_breathe = 1000 // Heat damage level 3 above this point; used for breathed air temperature var/body_temperature = 310.15 //non-IS_SYNTHETIC species will try to stabilize at this temperature. (also affects temperature processing) - var/synth_temp_gain = 0 //IS_SYNTHETIC species will gain this much temperature every second + var/passive_temp_gain = 0 //IS_SYNTHETIC species will gain this much temperature every second var/reagent_tag //Used for metabolizing reagents. var/darksight = 2 @@ -78,6 +79,7 @@ var/icon/icon_template var/is_small var/show_ssd = 1 + var/virus_immune // Language/culture vars. var/default_language = "Galactic Common" // Default language is used when 'say' is used without modifiers. @@ -95,8 +97,8 @@ "brain" = /obj/item/organ/brain, "appendix" = /obj/item/organ/appendix, "eyes" = /obj/item/organ/eyes - ) - + ) + var/vision_organ // If set, this organ is required for vision. Defaults to "eyes" if the species has them. var/list/has_limbs = list( "chest" = list("path" = /obj/item/organ/external/chest), "groin" = list("path" = /obj/item/organ/external/groin), @@ -112,6 +114,10 @@ ) /datum/species/New() + //If the species has eyes, they are the default vision organ + if(!vision_organ && has_organ["eyes"]) + vision_organ = "eyes" + unarmed = new unarmed_type() /datum/species/proc/get_random_name(var/gender) @@ -150,14 +156,6 @@ for(var/obj/item/organ/external/O in H.organs) O.owner = H - if(flags & IS_SYNTHETIC) - for(var/obj/item/organ/external/E in H.organs) - if(E.status & ORGAN_CUT_AWAY || E.status & ORGAN_DESTROYED) continue - E.robotize() - for(var/obj/item/organ/I in H.internal_organs) - I.robotize() - - /datum/species/proc/handle_breath(var/datum/gas_mixture/breath, var/mob/living/carbon/human/H) var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa //var/safe_oxygen_max = 140 // Maximum safe partial pressure of O2, in kPa (Not used for now) diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index a5729c0f8ac..5cb414f1bd4 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -1,5 +1,6 @@ /datum/species/human name = "Human" + name_plural = "Humans" icobase = 'icons/mob/human_races/r_human.dmi' deform = 'icons/mob/human_races/r_def_human.dmi' primitive_form = "Monkey" @@ -19,6 +20,7 @@ /datum/species/unathi name = "Unathi" + name_plural = "Unathi" icobase = 'icons/mob/human_races/r_lizard.dmi' deform = 'icons/mob/human_races/r_def_lizard.dmi' path = /mob/living/carbon/human/unathi @@ -59,6 +61,7 @@ /datum/species/tajaran name = "Tajaran" + name_plural = "Tajaran" icobase = 'icons/mob/human_races/r_tajaran.dmi' deform = 'icons/mob/human_races/r_def_tajaran.dmi' path = /mob/living/carbon/human/tajaran @@ -99,6 +102,7 @@ /datum/species/vulpkanin name = "Vulpkanin" + name_plural = "Vulpakanin" icobase = 'icons/mob/human_races/r_vulpkanin.dmi' deform = 'icons/mob/human_races/r_vulpkanin.dmi' path = /mob/living/carbon/human/vulpkanin @@ -129,6 +133,7 @@ /datum/species/skrell name = "Skrell" + name_plural = "Skrell" icobase = 'icons/mob/human_races/r_skrell.dmi' deform = 'icons/mob/human_races/r_def_skrell.dmi' path = /mob/living/carbon/human/skrell @@ -153,6 +158,7 @@ /datum/species/vox name = "Vox" + name_plural = "Vox" icobase = 'icons/mob/human_races/r_vox.dmi' deform = 'icons/mob/human_races/r_def_vox.dmi' path = /mob/living/carbon/human/vox @@ -213,6 +219,7 @@ /datum/species/vox/armalis name = "Vox Armalis" + name_plural = "Vox Armalis" icobase = 'icons/mob/human_races/r_armalis.dmi' deform = 'icons/mob/human_races/r_armalis.dmi' path = /mob/living/carbon/human/voxarmalis @@ -260,6 +267,7 @@ /datum/species/kidan name = "Kidan" + name_plural = "Kidan" icobase = 'icons/mob/human_races/r_kidan.dmi' deform = 'icons/mob/human_races/r_def_kidan.dmi' path = /mob/living/carbon/human/kidan @@ -278,6 +286,7 @@ /datum/species/slime name = "Slime People" + name_plural = "Slime People" default_language = "Galactic Common" language = "Bubblish" icobase = 'icons/mob/human_races/r_slime.dmi' @@ -299,6 +308,7 @@ /datum/species/grey name = "Grey" + name_plural = "Greys" icobase = 'icons/mob/human_races/r_grey.dmi' deform = 'icons/mob/human_races/r_def_grey.dmi' default_language = "Galactic Common" @@ -332,6 +342,7 @@ /datum/species/diona name = "Diona" + name_plural = "Dionaea" icobase = 'icons/mob/human_races/r_diona.dmi' deform = 'icons/mob/human_races/r_def_plant.dmi' path = /mob/living/carbon/human/diona @@ -395,7 +406,7 @@ ) /datum/species/diona/can_understand(var/mob/other) - var/mob/living/carbon/primitive/diona/D = other + var/mob/living/simple_animal/diona/D = other if(istype(D)) return 1 return 0 @@ -408,30 +419,38 @@ /* //overpowered and dumb as hell; they get cloning back, though. /datum/species/diona/handle_death(var/mob/living/carbon/human/H) - var/mob/living/carbon/primitive/diona/S = new(get_turf(H)) + var/mob/living/simple_animal/diona/S = new(get_turf(H)) if(H.mind) H.mind.transfer_to(S) else S.key = H.key - for(var/mob/living/carbon/primitive/diona/D in H.contents) + for(var/mob/living/simple_animal/diona/D in H.contents) if(D.client) D.loc = H.loc else del(D) - H.visible_message("\red[H] splits apart with a wet slithering noise!") */ + H.visible_message("The [src.name] signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null)) - m_type = 1 - if("scratch") - if (!src.restrained()) - message = "The [src.name] scratches." - m_type = 1 - if("whimper") - if (!muzzled) - message = "The [src.name] whimpers." - m_type = 2 - if("roar") - if (!muzzled) - message = "The [src.name] roars." - m_type = 2 - if("tail") - message = "The [src.name] waves his tail." - m_type = 1 - if("gasp") - message = "The [src.name] gasps." - m_type = 2 - if("shiver") - message = "The [src.name] shivers." - m_type = 2 - if("drool") - message = "The [src.name] drools." - m_type = 1 - if("paw") - if (!src.restrained()) - message = "The [src.name] flails his paw." - m_type = 1 - if("scretch") - if (!muzzled) - message = "The [src.name] scretches." - m_type = 2 - if("choke") - message = "The [src.name] chokes." - m_type = 2 - if("moan") - message = "The [src.name] moans!" - m_type = 2 - if("nod") - message = "The [src.name] nods his head." - m_type = 1 - if("sit") - message = "The [src.name] sits down." - m_type = 1 - if("sway") - message = "The [src.name] sways around dizzily." - m_type = 1 - if("sulk") - message = "The [src.name] sulks down sadly." - m_type = 1 - if("twitch") - message = "The [src.name] twitches violently." - m_type = 1 - if("dance") - if (!src.restrained()) - message = "The [src.name] dances around happily." - m_type = 1 - if("roll") - if (!src.restrained()) - message = "The [src.name] rolls." - m_type = 1 - if("shake") - message = "The [src.name] shakes his head." - m_type = 1 - if("gnarl") - if (!muzzled) - message = "The [src.name] gnarls and shows his teeth.." - m_type = 2 - if("jump") - message = "The [src.name] jumps!" - m_type = 1 - if("collapse") - Paralyse(2) - message = "[src.name] collapses!" - m_type = 2 - if("deathgasp") - message = "The [src.name] lets out a faint chimper as it collapses and stops moving..." - m_type = 1 - if ("flip") - m_type = 1 - if (!src.restrained()) - var/M = null - if (param) - for (var/mob/A in view(1, null)) - if (param == A.name) - M = A - break - if (M == src) - M = null - if (M) - if(src.lying || src.weakened) - message = "[src] flops and flails around on the floor." - else - message = "[src] flips in [M]'s general direction." - src.SpinAnimation(5,1) - else - if(src.lying || src.weakened) - message = "[src] flops and flails around on the floor." - else - message = "[src] does a flip!" - src.SpinAnimation(5,1) - if("help") - var/text = "choke, " - if(istype(src,/mob/living/carbon/primitive/diona)) - text += "chirp, " - text += "flip, collapse, dance, deathgasp, drool, gasp, shiver, gnarl, jump, paw, moan, nod, roar, roll, scratch,\nscretch, shake, sign-#, sit, sulk, sway, tail, twitch, whimper" - src << text - else - src << text("Invalid Emote: []", act) - if ((message && src.stat == 0)) - if(src.client) - log_emote("[name]/[key] : [message]") - if (m_type & 1) - for(var/mob/O in viewers(src, null)) - O.show_message(message, m_type) - //Foreach goto(703) - else - for(var/mob/O in hearers(src, null)) - O.show_message(message, m_type) - //Foreach goto(746) - return \ No newline at end of file diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 13676d438a9..e219c342187 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -75,7 +75,7 @@ /mob/living/carbon/human/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0) - if((species.flags & IS_SYNTHETIC) && (effecttype == IRRADIATE)) + if((species.flags & NO_DNA_RAD) && (effecttype == IRRADIATE)) return return ..() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 5c94d8d5dbd..d1017431eb8 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -115,12 +115,11 @@ if(ismob(O.thrower)) var/mob/M = O.thrower - var/client/assailant = M.client - if(assailant) - src.attack_log += text("\[[time_stamp()]\] Has been hit with a [O], thrown by [M.name] ([assailant.ckey])") - M.attack_log += text("\[[time_stamp()]\] Hit [src.name] ([src.ckey]) with a thrown [O]") + if(M) + src.attack_log += text("\[[time_stamp()]\] Has been hit with a [O], thrown by [key_name(M)]") + M.attack_log += text("\[[time_stamp()]\] Hit [key_name(src)] with a thrown [O]") if(!istype(src,/mob/living/simple_animal/mouse)) - msg_admin_attack("[src.name] ([src.ckey]) was hit by a [O], thrown by [M.name] ([assailant.ckey])[isAntag(M) ? "(ANTAG)" : ""] (JMP)") + msg_admin_attack("[key_name_admin(src)] was hit by a [O], thrown by [key_name_admin(M)]") // Begin BS12 momentum-transfer code. if(O.throw_source && speed >= 15) @@ -166,13 +165,16 @@ M.occupant_message("You hit [src].") visible_message("[src] has been hit by [M.name].", \ "[src] has been hit by [M.name].") - add_logs(M.occupant, src, "attacked", object=M, addition="(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") + attack_log += text("\[[time_stamp()]\] Has been attacked by \the [M] controlled by [key_name(M.occupant)] (INTENT: [uppertext(M.occupant.a_intent)])") + M.occupant.attack_log += text("\[[time_stamp()]\] Attacked [src] with \the [M] (INTENT: [uppertext(M.occupant.a_intent)])") + msg_admin_attack("[key_name_admin(M.occupant)] attacked [key_name_admin(src)] with \the [M] (INTENT: [uppertext(M.occupant.a_intent)])") + else + step_away(src,M) add_logs(M.occupant, src, "pushed", object=M, admin=0) M.occupant_message("You push [src] out of the way.") visible_message("[M] pushes [src] out of the way.") - return //Mobs on Fire diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index c89552719bb..d64dc143ec2 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -55,6 +55,7 @@ var/list/ai_verbs_default = list( var/ioncheck[1] var/lawchannel = "Common" // Default channel on which to state laws var/icon/holo_icon//Default is assigned when AI is created. + var/obj/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye. var/obj/item/device/pda/ai/aiPDA = null var/obj/item/device/multitool/aiMulti = null var/custom_sprite = 0 //For our custom sprites @@ -66,7 +67,7 @@ var/list/ai_verbs_default = list( var/processing_time = 100 var/list/datum/AI_Module/current_modules = list() var/fire_res_on_core = 0 - + var/can_dominate_mechs = 0 var/control_disabled = 0 // Set to 1 to stop AI from interacting via Click() -- TLE var/malfhacking = 0 // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite var/malf_cooldown = 0 //Cooldown var for malf modules @@ -242,6 +243,7 @@ var/list/ai_verbs_default = list( powered_ai = ai if(isnull(powered_ai)) qdel(src) + return loc = powered_ai.loc use_power(1) // Just incase we need to wake up the power system. @@ -251,6 +253,7 @@ var/list/ai_verbs_default = list( /obj/machinery/ai_powersupply/process() if(!powered_ai || powered_ai.stat & DEAD) qdel(src) + return if(!powered_ai.anchored) loc = powered_ai.loc use_power = 0 @@ -336,7 +339,7 @@ var/list/ai_verbs_default = list( if(check_unable(AI_CHECK_WIRELESS)) return - var/input = stripped_input(usr, "Please enter the reason for calling the shuttle.", "Shuttle Call Reason.","") as text|null + var/input = input(usr, "Please enter the reason for calling the shuttle.", "Shuttle Call Reason.","") as text|null if(!input || stat) return @@ -502,18 +505,18 @@ var/list/ai_verbs_default = list( if (href_list["track"]) var/mob/target = locate(href_list["track"]) in mob_list - - if(target && (!istype(target, /mob/living/carbon/human) || html_decode(href_list["trackname"]) == target:get_face_name())) + if(target && trackable(target)) ai_actual_track(target) else - src << "\red System error. Cannot locate [html_decode(href_list["trackname"])]." + src << "Target is not on or near any active cameras on the station." return if (href_list["trackbot"]) var/obj/machinery/bot/target = locate(href_list["trackbot"]) in aibots - var/mob/living/silicon/ai/A = locate(href_list["track2"]) in mob_list - if(A && target) - A.ai_actual_track(target) + if(target && trackable(target)) + ai_actual_track(target) + else + src << "Target is not on or near any active cameras on the station." return if (href_list["callbot"]) //Command a bot to move to a selected location. @@ -534,6 +537,14 @@ var/list/ai_verbs_default = list( botcall() return + if (href_list["ai_take_control"]) //Mech domination + var/obj/mecha/M = locate(href_list["ai_take_control"]) + if(controlled_mech) + src << "You are already loaded into an onboard computer!" + return + if(M) + M.transfer_ai(AI_MECH_HACK,src, usr) //Called om the mech itself. + else if (href_list["faketrack"]) var/mob/target = locate(href_list["track"]) in mob_list var/mob/living/silicon/ai/A = locate(href_list["track2"]) in mob_list @@ -925,10 +936,8 @@ var/list/ai_verbs_default = list( spawn(0) if(istype(target, /mob/living/carbon/human)) var/mob/living/carbon/human/H = target - if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) - src << "Unable to locate an airlock" - return - if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) + var/obj/item/weapon/card/id/id = H.wear_id + if(istype(id) && id.is_untrackable()) src << "Unable to locate an airlock" return if(H.digitalcamo) @@ -981,6 +990,24 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai/proc/is_in_chassis() return istype(loc, /turf) + +/mob/living/silicon/ai/transfer_ai(var/interaction, var/mob/user, var/mob/living/silicon/ai/AI, var/obj/item/device/aicard/card) + if(!..()) + return + if(interaction == AI_TRANS_TO_CARD)//The only possible interaction. Upload AI mob to a card. + if(!mind) + user << "No intelligence patterns detected." //No more magical carding of empty cores, AI RETURN TO BODY!!!11 + return + if (mind.special_role == "malfunction") //AI MALF!! + user << "ERROR: Remote transfer interface disabled."//Do ho ho ho~ + return + new /obj/structure/AIcore/deactivated(loc)//Spawns a deactivated terminal at AI location. + aiRestorePowerRoutine = 0//So the AI initially has power. + control_disabled = 1//Can't control things remotely if you're stuck in a card! + aiRadio.disabledAi = 1 //No talking on the built-in radio for you either! + loc = card//Throw AI into the card. + src << "You have been downloaded to a mobile storage device. Remote device connection severed." + user << "Transfer successful: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory." #undef AI_CHECK_WIRELESS #undef AI_CHECK_RADIO diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 5be1da223a9..40facde6f9c 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -44,7 +44,7 @@ loc = T.loc if (istype(loc, /area)) //stage = 4 - if (!loc.power_equip && !istype(src.loc,/obj/item)) + if (!loc.power_equip && !is_type_in_list(src.loc,list(/obj/item, /obj/mecha))) //stage = 5 blind = 1 @@ -56,7 +56,8 @@ src.sight |= SEE_OBJS src.see_in_dark = 8 src.see_invisible = SEE_INVISIBLE_LEVEL_TWO - + if(see_override) + see_invisible = see_override //Congratulations! You've found a way for AI's to run without using power! //Todo: Without snowflaking up master_controller procs find a way to make AI use_power but only when APC's clear the area usage the tick prior @@ -97,7 +98,7 @@ src.see_in_dark = 0 src.see_invisible = SEE_INVISIBLE_LIVING - if (((!loc.power_equip) || istype(T, /turf/space)) && !istype(src.loc,/obj/item)) + if (((!loc.power_equip) || istype(T, /turf/space)) && !is_type_in_list(src.loc,list(/obj/item, /obj/mecha))) if (src:aiRestorePowerRoutine==0) src:aiRestorePowerRoutine = 1 diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 835a4f3e240..b9f85576e01 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -521,4 +521,11 @@ // No binary for pAIs. /mob/living/silicon/pai/binarycheck() - return 0 \ No newline at end of file + return 0 + +/mob/living/silicon/pai/on_forcemove(atom/newloc) + if(card) + card.loc = newloc + else //something went very wrong. + CRASH("pAI without card") + loc = card diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm index 14a3733154d..9cba0094d4d 100644 --- a/code/modules/mob/living/silicon/pai/software_modules.dm +++ b/code/modules/mob/living/silicon/pai/software_modules.dm @@ -369,6 +369,8 @@ /mob/living/silicon/pai/proc/hackloop() var/turf/T = get_turf_or_move(src.loc) for(var/mob/living/silicon/ai/AI in player_list) + if(!T || !(T.z in config.contact_levels)) + break if(T.loc) AI << "Network Alert: Brute-force encryption crack in progress in [T.loc]." else diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index 9673a766f72..ae09c2287a8 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -184,74 +184,74 @@ /obj/item/device/robotanalyzer/attack(mob/living/M as mob, mob/living/user as mob) if(( (CLUMSY in user.mutations) || user.getBrainLoss() >= 60) && prob(50)) - user << text("\red You try to analyze the floor's vitals!") - for(var/mob/O in viewers(M, null)) - O.show_message(text("\red [user] has analyzed the floor's vitals!"), 1) - user.show_message(text("\blue Analyzing Results for The floor:\n\t Overall Status: Healthy"), 1) - user.show_message(text("\blue \t Damage Specifics: [0]-[0]-[0]-[0]"), 1) - user.show_message("\blue Key: Suffocation/Toxin/Burns/Brute", 1) - user.show_message("\blue Body Temperature: ???", 1) + user.visible_message("[user] has analyzed the floor's vitals!", "You try to analyze the floor's vitals!") + user << "Analyzing Results for The floor:\n\t Overall Status: Healthy" + user << "\t Damage Specifics: [0]-[0]-[0]-[0]" + user << "Key: Suffocation/Toxin/Burns/Brute" + user << "Body Temperature: ???" return - if(!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - user << "\red You don't have the dexterity to do this!" - return - if(!istype(M, /mob/living/silicon/robot) && !(ishuman(M) && (M:species.flags & IS_SYNTHETIC))) - user << "\red You can't analyze non-robotic things!" - return - - user.visible_message(" [user] has analyzed [M]'s components."," You have analyzed [M]'s components.") - var/BU = M.getFireLoss() > 50 ? "[M.getFireLoss()]" : M.getFireLoss() - var/BR = M.getBruteLoss() > 50 ? "[M.getBruteLoss()]" : M.getBruteLoss() - var/TX = M.getToxLoss() > 50 ? "[M.getToxLoss()]" : M.getToxLoss() - - user.show_message("\blue Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "fully disabled" : "[M.health - M.halloss]% functional"]") - if (ishuman(M) && (M:species.flags & IS_SYNTHETIC)) - user.show_message("\t Key: Electronics/Brute/Residue", 1) - user.show_message("\t Damage Specifics: [BU] - [BR] - [TX]") + + var/scan_type + if(istype(M, /mob/living/silicon/robot)) + scan_type = "robot" + else if(istype(M, /mob/living/carbon/human)) + scan_type = "prosthetics" else - user.show_message("\t Key: Electronics/Brute", 1) - user.show_message("\t Damage Specifics: [BU] - [BR]") - if(M.tod && M.stat == DEAD) - user.show_message("\blue Time of Disable: [M.tod]") + user << "You can't analyze non-robotic things!" + return - if (istype(M, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/H = M - var/list/damaged = H.get_damaged_components(1,1,1) - user.show_message("\blue Localized Damage:",1) - if(length(damaged)>0) - for(var/datum/robot_component/org in damaged) - user.show_message(text("\blue \t []: [][] - [] - [] - []", \ - capitalize(org.name), \ - (org.installed == -1) ? "DESTROYED " :"",\ - (org.electronics_damage > 0) ? "[org.electronics_damage]" :0, \ - (org.brute_damage > 0) ? "[org.brute_damage]" :0, \ - (org.toggled) ? "Toggled ON" : "Toggled OFF",\ - (org.powered) ? "Power ON" : "Power OFF"),1) - else - user.show_message("\blue \t Components are OK.",1) - if(H.emagged && prob(5)) - user.show_message("\red \t ERROR: INTERNAL SYSTEMS COMPROMISED",1) + user.visible_message("[user] has analyzed [M]'s components.","You have analyzed [M]'s components.") + switch(scan_type) + if("robot") + var/BU = M.getFireLoss() > 50 ? "[M.getFireLoss()]" : M.getFireLoss() + var/BR = M.getBruteLoss() > 50 ? "[M.getBruteLoss()]" : M.getBruteLoss() + user << "Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "fully disabled" : "[M.health - M.halloss]% functional"]" + user << "\t Key: Electronics/Brute" + user << "\t Damage Specifics: [BU] - [BR]" + if(M.tod && M.stat == DEAD) + user << "Time of Disable: [M.tod]" + var/mob/living/silicon/robot/H = M + var/list/damaged = H.get_damaged_components(1,1,1) + user << "Localized Damage:" + if(length(damaged)>0) + for(var/datum/robot_component/org in damaged) + user.show_message(text("\t []: [][] - [] - [] - []", \ + capitalize(org.name), \ + (org.installed == -1) ? "DESTROYED " :"",\ + (org.electronics_damage > 0) ? "[org.electronics_damage]" :0, \ + (org.brute_damage > 0) ? "[org.brute_damage]" :0, \ + (org.toggled) ? "Toggled ON" : "Toggled OFF",\ + (org.powered) ? "Power ON" : "Power OFF"),1) + else + user << "\t Components are OK." + if(H.emagged && prob(5)) + user << "\t ERROR: INTERNAL SYSTEMS COMPROMISED" - if (ishuman(M) && (M:species.flags & IS_SYNTHETIC)) - var/mob/living/carbon/human/H = M - var/list/damaged = H.get_damaged_organs(1,1) - user.show_message("\blue Localized Damage, Brute/Electronics:",1) - if(length(damaged)>0) - for(var/obj/item/organ/external/org in damaged) - user.show_message(text("\blue \t []: [] - []", \ - capitalize(org.name), \ - (org.brute_dam > 0) ? "\red [org.brute_dam]" :0, \ - (org.burn_dam > 0) ? "[org.burn_dam]" :0),1) - else - user.show_message("\blue \t Components are OK.",1) - if (M.getBrainLoss() >= 100 || istype(M, /mob/living/carbon/human) && M:brain_op_stage == 4.0) - user.show_message("\red Subject posibrain is unresponsive. System shutdown imminent.") - else if (M.getBrainLoss() >= 60) - user.show_message("\red Severe posibrain damage detected. Heavy corrosion present.") - else if (M.getBrainLoss() >= 10) - user.show_message("\red Significant posibrain damage detected. Moderate corrosion present.") - - user.show_message("\blue Operating Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) + if("prosthetics") + var/mob/living/carbon/human/H = M + user << "Analyzing Results for \the [H]:" + user << "Key: Electronics/Brute" + user << "External prosthetics:" + var/organ_found + if(H.internal_organs.len) + for(var/obj/item/organ/external/E in H.organs) + if(!(E.status & ORGAN_ROBOT)) + continue + organ_found = 1 + user << "[E.name]: [round(E.brute_dam)] [round(E.burn_dam)]" + if(!organ_found) + user << "No prosthetics located." + user << "
" + user << "Internal prosthetics:" + organ_found = null + if(H.internal_organs.len) + for(var/obj/item/organ/O in H.internal_organs) + if(!(O.status & ORGAN_ROBOT)) + continue + organ_found = 1 + user << "[capitalize(O.name)]: [O.damage]" + if(!organ_found) + user << "No prosthetics located." + src.add_fingerprint(user) - return diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 0a18501ee01..c55cd5a7bbf 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -542,13 +542,6 @@ var/list/robot_verbs_default = list( return now_pushing = 0 ..() - if (istype(AM, /obj/machinery/recharge_station)) - var/obj/machinery/recharge_station/F = AM - if(F.panel_open) - usr << "\blue Close the maintenance panel first." - return - else - F.move_inside() if (!istype(AM, /atom/movable)) return if (!now_pushing) @@ -587,34 +580,35 @@ var/list/robot_verbs_default = list( return - if (istype(W, /obj/item/weapon/weldingtool)) - if(W == module_active) return + if (istype(W, /obj/item/weapon/weldingtool) && user.a_intent == "help") + if(W == module_active) + return if (!getBruteLoss()) - user << "Nothing to fix here!" + user << "Nothing to fix!" return var/obj/item/weapon/weldingtool/WT = W user.changeNext_move(CLICK_CD_MELEE) if (WT.remove_fuel(0)) + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) adjustBruteLoss(-30) updatehealth() add_fingerprint(user) - for(var/mob/O in viewers(user, null)) - O.show_message(text("\red [user] has fixed some of the dents on [src]!"), 1) + user.visible_message("\The [user] patches some dents on \the [src] with \the [WT].") else - user << "Need more welding fuel!" + user << "Need more welding fuel!" return - else if(istype(W, /obj/item/stack/cable_coil) && (wiresexposed || istype(src,/mob/living/silicon/robot/drone))) + else if(istype(W, /obj/item/stack/cable_coil) && user.a_intent == "help" && (wiresexposed || istype(src,/mob/living/silicon/robot/drone))) if (!getFireLoss()) - user << "Nothing to fix here!" + user << "Nothing to fix!" return var/obj/item/stack/cable_coil/coil = W adjustFireLoss(-30) updatehealth() + add_fingerprint(user) coil.use(1) - for(var/mob/O in viewers(user, null)) - O.show_message(text("\red [user] has fixed some of the burnt wires on [src]!"), 1) + user.visible_message("\The [user] fixes some of the burnt wires on \the [src] with \the [coil].") else if (istype(W, /obj/item/weapon/crowbar)) // crowbar means open or close the cover if(opened) diff --git a/code/modules/mob/living/simple_animal/borer.dm b/code/modules/mob/living/simple_animal/borer.dm index 5863daece9a..8ab01f44ab1 100644 --- a/code/modules/mob/living/simple_animal/borer.dm +++ b/code/modules/mob/living/simple_animal/borer.dm @@ -96,7 +96,7 @@ if(prob(5)) host.adjustBrainLoss(rand(1,2)) - if(prob(host.brainloss/20)) + if(prob(host.getBrainLoss()/20)) host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_s","gasp"))]") /mob/living/simple_animal/borer/New(var/by_gamemode=0) @@ -148,7 +148,7 @@ var/list/choices = list() for(var/mob/living/carbon/C in view(3,src)) - if(C.stat != 2) + if(C.stat != DEAD) choices += C if(world.time - used_dominate < 300) @@ -188,7 +188,7 @@ src << "You begin delicately adjusting your connection to the host brain..." - spawn(300+(host.brainloss*5)) + spawn(300+(host.getBrainLoss()*5)) if(!host || !src || controlling) return @@ -196,8 +196,8 @@ src << "\red You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system." host << "\red You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours." var/borer_key = src.key - host.attack_log += text("\[[time_stamp()]\] [src.name] ([src.ckey]) has assumed control of [host.name] ([host.ckey])") - msg_admin_attack("[src.name] ([src.ckey]) has assumed control of [host.name] ([host.ckey]) (JMP)") + host.attack_log += text("\[[time_stamp()]\] [key_name(src)] has assumed control of [key_name(host)]") + msg_admin_attack("[key_name_admin(src)] has assumed control of [key_name_admin(host)]") // host -> brain var/h2b_id = host.computer_id var/h2b_ip= host.lastKnownIP @@ -387,11 +387,14 @@ mob/living/simple_animal/borer/proc/detatch() return var/list/choices = list() - for(var/mob/living/carbon/C in view(1,src)) - if(C.stat != 2 && src.Adjacent(C)) - choices += C + for(var/mob/living/carbon/human/H in view(1,src)) + var/obj/item/organ/external/head/head = H.get_organ("head") + if(head.status & ORGAN_ROBOT) + continue + if(H.stat != DEAD && src.Adjacent(H) && !H.has_brain_worms()) + choices += H - var/mob/living/carbon/M = input(src,"Who do you wish to infest?") in null|choices + var/mob/living/carbon/human/M = input(src,"Who do you wish to infest?") in null|choices if(!M || !src) return @@ -400,13 +403,6 @@ mob/living/simple_animal/borer/proc/detatch() if(M.has_brain_worms()) src << "You cannot infest someone who is already infested!" return -/* - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.check_head_coverage()) - src << "You cannot get through that host's protective gear." - return -*/ src << "You slither up [M] and begin probing at their ear canal..." diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 9f28be0cd90..e099f8b3e4d 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -25,6 +25,7 @@ minbodytemp = 0 faction = list("cult") flying = 1 + universal_speak = 1 var/list/construct_spells = list() /mob/living/simple_animal/construct/New() diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index c0633fec3a3..b13714ae552 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -5,6 +5,7 @@ icon_state = "cat2" icon_living = "cat2" icon_dead = "cat2_dead" + icon_resting = "cat_rest" gender = MALE speak = list("Meow!", "Esp!", "Purr!", "HSSSSS") speak_emote = list("purrs", "meows") @@ -76,6 +77,7 @@ icon_state = "kitten" icon_living = "kitten" icon_dead = "kitten_dead" + icon_resting = null gender = NEUTER density = 0 pass_flags = PASSMOB @@ -86,8 +88,9 @@ icon_state = "Syndicat" icon_living = "Syndicat" icon_dead = "Syndicat_dead" + icon_resting = "Syndicat_rest" gender = FEMALE - flags = IS_SYNTHETIC|NO_BREATHE + flags = NO_BREATHE faction = list("syndicate") var/turns_since_scan = 0 var/mob/living/simple_animal/mouse/movement_target \ No newline at end of file diff --git a/code/modules/mob/living/carbon/primitive/dionaold.dm b/code/modules/mob/living/simple_animal/friendly/diona.dm similarity index 52% rename from code/modules/mob/living/carbon/primitive/dionaold.dm rename to code/modules/mob/living/simple_animal/friendly/diona.dm index c5a7b5a5b70..5a8b2618233 100644 --- a/code/modules/mob/living/carbon/primitive/dionaold.dm +++ b/code/modules/mob/living/simple_animal/friendly/diona.dm @@ -3,57 +3,73 @@ */ //Mob defines. -/mob/living/carbon/primitive/diona +/mob/living/simple_animal/diona name = "diona nymph" - voice_name = "diona nymph" - speak_emote = list("chirrups") icon = 'icons/mob/monkey.dmi' - icon_state = "nymph1" + icon_state = "nymph" + icon_living = "nymph" + icon_dead = "nymph_dead" + icon_resting = "nymph_sleep" + pass_flags = PASSTABLE + small = 1 + ventcrawler = 2 + + maxHealth = 50 + health = 50 + + voice_name = "diona nymph" + speak_emote = list("chirrups") + emote_hear = list("chirrups") + emote_see = list("chirrups") + + response_help = "pets" + response_disarm = "pushes" + response_harm = "kicks" + + melee_damage_lower = 5 + melee_damage_upper = 8 + attacktext = "bites" + attack_sound = 'sound/weapons/bite.ogg' + + speed = 0 + stop_automated_movement = 0 + turns_per_move = 4 + status_flags = 0 + var/list/donors = list() var/ready_evolve = 0 - ventcrawler = 1 - var/environment_smash = 0 // This is a sloppy way to solve attack_animal runtimes. Stupid nymphs... holder_type = /obj/item/weapon/holder/diona -/mob/living/carbon/primitive/diona/New() - +/mob/living/simple_animal/diona/New() ..() - gender = NEUTER - //greaterform = "Diona" + if(name == initial(name)) //To stop Pun-Pun becoming generic. + name = "[name] ([rand(1, 1000)])" + real_name = name + add_language("Rootspeak") + src.verbs += /mob/living/simple_animal/diona/proc/merge -/mob/living/carbon/primitive/diona/attack_hand(mob/living/carbon/human/M as mob) - +/mob/living/simple_animal/diona/attack_hand(mob/living/carbon/human/M as mob) //Let people pick the little buggers up. if(M.a_intent == "help") if(M.species && M.species.name == "Diona") M << "You feel your being twine with that of [src] as it merges with your biomass." src << "You feel your being twine with that of [M] as you merge with its biomass." - src.verbs += /mob/living/carbon/primitive/diona/proc/split - src.verbs -= /mob/living/carbon/primitive/diona/proc/merge + src.verbs += /mob/living/simple_animal/diona/proc/split + src.verbs -= /mob/living/simple_animal/diona/proc/merge src.forceMove(M) else get_scooped(M) ..() -/mob/living/carbon/primitive/diona/New() - - ..() - gender = NEUTER - //greaterform = "Diona" - add_language("Rootspeak") - src.verbs += /mob/living/carbon/primitive/diona/proc/merge - - -/mob/living/carbon/primitive/diona/proc/merge() - +/mob/living/simple_animal/diona/proc/merge() set category = "Diona" set name = "Merge with gestalt" set desc = "Merge with another diona." if(istype(src.loc,/mob/living/carbon)) - src.verbs -= /mob/living/carbon/primitive/diona/proc/merge + src.verbs -= /mob/living/simple_animal/diona/proc/merge return var/list/choices = list() @@ -76,19 +92,18 @@ src << "You feel your being twine with that of [M] as you merge with its biomass." src.loc = M - src.verbs += /mob/living/carbon/primitive/diona/proc/split - src.verbs -= /mob/living/carbon/primitive/diona/proc/merge + src.verbs += /mob/living/simple_animal/diona/proc/split + src.verbs -= /mob/living/simple_animal/diona/proc/merge else return -/mob/living/carbon/primitive/diona/proc/split() - +/mob/living/simple_animal/diona/proc/split() set category = "Diona" set name = "Split from gestalt" set desc = "Split away from your gestalt as a lone nymph." if(!(istype(src.loc,/mob/living/carbon))) - src.verbs -= /mob/living/carbon/primitive/diona/proc/split + src.verbs -= /mob/living/simple_animal/diona/proc/split return src.loc << "You feel a pang of loss as [src] splits away from your biomass." @@ -97,8 +112,8 @@ var/mob/living/M = src.loc src.loc = get_turf(src) - src.verbs -= /mob/living/carbon/primitive/diona/proc/split - src.verbs += /mob/living/carbon/primitive/diona/proc/merge + src.verbs -= /mob/living/simple_animal/diona/proc/split + src.verbs += /mob/living/simple_animal/diona/proc/merge if(istype(M)) for(var/atom/A in M.contents) @@ -106,8 +121,7 @@ return M.status_flags &= ~PASSEMOTES -/mob/living/carbon/primitive/diona/verb/fertilize_plant() - +/mob/living/simple_animal/diona/verb/fertilize_plant() set category = "Diona" set name = "Fertilize plant" set desc = "Turn your food into nutrients for plants." @@ -123,10 +137,9 @@ src.nutrition -= ((10-target.nutrilevel)*5) target.nutrilevel = 10 - src.visible_message("\red [src] secretes a trickle of green liquid from its tail, refilling [target]'s nutrient tray.","\red You secrete a trickle of green liquid from your tail, refilling [target]'s nutrient tray.") - -/mob/living/carbon/primitive/diona/verb/eat_weeds() + src.visible_message("[src] secretes a trickle of green liquid from its tail, refilling [target]'s nutrient tray.","\red You secrete a trickle of green liquid from your tail, refilling [target]'s nutrient tray.") +/mob/living/simple_animal/diona/verb/eat_weeds() set category = "Diona" set name = "Eat Weeds" set desc = "Clean the weeds out of soil or a hydroponics tray." @@ -142,24 +155,23 @@ src.nutrition += target.weedlevel * 15 target.weedlevel = 0 - src.visible_message("\red [src] begins rooting through [target], ripping out weeds and eating them noisily.","\red You begin rooting through [target], ripping out weeds and eating them noisily.") - -/mob/living/carbon/primitive/diona/verb/evolve() + src.visible_message("[src] begins rooting through [target], ripping out weeds and eating them noisily.","You begin rooting through [target], ripping out weeds and eating them noisily.") +/mob/living/simple_animal/diona/verb/evolve() set category = "Diona" set name = "Evolve" set desc = "Grow to a more complex form." if(donors.len < 5) - src << "You need more blood in order to ascend to a new state of consciousness..." + src << "You need more blood in order to ascend to a new state of consciousness..." return if(nutrition < 500) - src << "You need to binge on weeds in order to have the energy to grow..." + src << "You need to binge on weeds in order to have the energy to grow..." return src.split() - src.visible_message("\red [src] begins to shift and quiver, and erupts in a shower of shed bark as it splits into a tangle of nearly a dozen new dionaea.","\red You begin to shift and quiver, feeling your awareness splinter. All at once, we consume our stored nutrients to surge with growth, splitting into a tangle of at least a dozen new dionaea. We have attained our gestalt form.") + src.visible_message("[src] begins to shift and quiver, and erupts in a shower of shed bark as it splits into a tangle of nearly a dozen new dionaea.","You begin to shift and quiver, feeling your awareness splinter. All at once, we consume our stored nutrients to surge with growth, splitting into a tangle of at least a dozen new dionaea. We have attained our gestalt form.") var/mob/living/carbon/human/diona/adult = new(get_turf(src.loc)) adult.set_species("Diona") @@ -184,7 +196,7 @@ qdel(src) -/mob/living/carbon/primitive/diona/verb/steal_blood() +/mob/living/simple_animal/diona/verb/steal_blood() set category = "Diona" set name = "Steal Blood" set desc = "Take a blood sample from a suitable donor." @@ -198,14 +210,14 @@ if(!M || !src) return if(M.species.flags & NO_BLOOD) - src << "\red That donor has no blood to take." + src << "That donor has no blood to take." return if(donors.Find(M.real_name)) - src << "\red That donor offers you nothing new." + src << "That donor offers you nothing new." return - src.visible_message("\red [src] flicks out a feeler and neatly steals a sample of [M]'s blood.","\red You flick out a feeler and neatly steal a sample of [M]'s blood.") + src.visible_message("[src] flicks out a feeler and neatly steals a sample of [M]'s blood.","You flick out a feeler and neatly steal a sample of [M]'s blood.") donors += M.real_name for(var/datum/language/L in M.languages) if(!(L.flags & HIVEMIND)) @@ -214,36 +226,37 @@ spawn(25) update_progression() -/mob/living/carbon/primitive/diona/proc/update_progression() - +/mob/living/simple_animal/diona/proc/update_progression() if(!donors.len) return if(donors.len == 5) ready_evolve = 1 - src << "\green You feel ready to move on to your next stage of growth." + src << "You feel ready to move on to your next stage of growth." else if(donors.len == 3) universal_understand = 1 - src << "\green You feel your awareness expand, and realize you know how to understand the creatures around you." + src << "You feel your awareness expand, and realize you know how to understand the creatures around you." else - src << "\green The blood seeps into your small form, and you draw out the echoes of memories and personality from it, working them into your budding mind." + src << "The blood seeps into your small form, and you draw out the echoes of memories and personality from it, working them into your budding mind." -/mob/living/carbon/primitive/diona/put_in_hands(obj/item/W) +/mob/living/simple_animal/diona/put_in_hands(obj/item/W) W.loc = get_turf(src) W.layer = initial(W.layer) W.dropped() -/mob/living/carbon/primitive/diona/put_in_active_hand(obj/item/W) - src << "\red You don't have any hands!" +/mob/living/simple_animal/diona/put_in_active_hand(obj/item/W) + src << "You don't have any hands!" return + -/mob/living/carbon/primitive/diona/say(var/message) +/mob/living/simple_animal/diona/say(var/message) if(client) if(client.prefs.muted & MUTE_IC) src << "\red You cannot speak in IC (Muted)." return + var/verb message = trim_strip_html_properly(message) if(stat) @@ -257,5 +270,22 @@ if(copytext(message,1,2) == "*") return emote(copytext(message,2)) + + //parse the language code and consume it + var/datum/language/speaking = parse_language(message) + if(speaking) + message = copytext(message,2+length(speaking.key)) + else + speaking = get_default_language() - ..(message) + var/ending = copytext(message, length(message)) + if (speaking) + // This is broadcast to all mobs with the language, + // irrespective of distance or anything else. + if(speaking.flags & HIVEMIND) + speaking.broadcast(src,trim(message)) + return + //If we've gotten this far, keep going! + verb = speaking.get_spoken_verb(ending) + + ..(message,speaking,verb) diff --git a/code/modules/mob/living/simple_animal/friendly/fox.dm b/code/modules/mob/living/simple_animal/friendly/fox.dm index af2994feeef..38d79141803 100644 --- a/code/modules/mob/living/simple_animal/friendly/fox.dm +++ b/code/modules/mob/living/simple_animal/friendly/fox.dm @@ -30,5 +30,6 @@ icon_state = "Syndifox" icon_living = "Syndifox" icon_dead = "Syndifox_dead" - flags = IS_SYNTHETIC|NO_BREATHE + icon_resting = "Syndifox_rest" + flags = NO_BREATHE faction = list("syndicate") diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm index c2dc78c5377..3ec2633e2e9 100644 --- a/code/modules/mob/living/simple_animal/hostile/alien.dm +++ b/code/modules/mob/living/simple_animal/hostile/alien.dm @@ -30,7 +30,7 @@ min_n2 = 0 max_n2 = 0 var/dead = 0 - unsuitable_atoms_damage = 15 + unsuitable_atmos_damage = 15 faction = list("alien") status_flags = CANPUSH minbodytemp = 0 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 3a88146dfb0..285948e6073 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm @@ -8,7 +8,7 @@ max_co2 = 0 min_n2 = 0 max_n2 = 0 - unsuitable_atoms_damage = 15 + unsuitable_atmos_damage = 15 faction = list("mining") environment_smash = 2 minbodytemp = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm index b642c5c6dda..c519c2c62bc 100644 --- a/code/modules/mob/living/simple_animal/hostile/pirate.dm +++ b/code/modules/mob/living/simple_animal/hostile/pirate.dm @@ -27,7 +27,7 @@ max_co2 = 5 min_n2 = 0 max_n2 = 0 - unsuitable_atoms_damage = 15 + unsuitable_atmos_damage = 15 speak_emote = list("yarrs") var/corpse = /obj/effect/landmark/mobcorpse/pirate var/weapon1 = /obj/item/weapon/melee/energy/sword/pirate diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm index d62a4ba976d..2635c97f9a1 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm @@ -36,4 +36,4 @@ maxbodytemp = 370 heat_damage_per_tick = 15 //amount of damage applied if animal's body temperature is higher than maxbodytemp cold_damage_per_tick = 10 //same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp - unsuitable_atoms_damage = 10 + unsuitable_atmos_damage = 10 diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm index d1140f38c5b..729ef2ad658 100644 --- a/code/modules/mob/living/simple_animal/hostile/russian.dm +++ b/code/modules/mob/living/simple_animal/hostile/russian.dm @@ -29,7 +29,7 @@ max_co2 = 5 min_n2 = 0 max_n2 = 0 - unsuitable_atoms_damage = 15 + unsuitable_atmos_damage = 15 faction = list("russian") status_flags = CANPUSH diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm index a83eddf5e84..6eb56766229 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -30,7 +30,7 @@ max_co2 = 5 min_n2 = 0 max_n2 = 0 - unsuitable_atoms_damage = 15 + unsuitable_atmos_damage = 15 faction = list("syndicate") status_flags = CANPUSH diff --git a/code/modules/mob/living/simple_animal/revenant/revenant.dm b/code/modules/mob/living/simple_animal/revenant/revenant.dm index bad520aa326..1d83cbcc9d8 100644 --- a/code/modules/mob/living/simple_animal/revenant/revenant.dm +++ b/code/modules/mob/living/simple_animal/revenant/revenant.dm @@ -12,47 +12,52 @@ invisibility = INVISIBILITY_OBSERVER health = 25 maxHealth = 25 - see_in_dark = 255 see_invisible = SEE_INVISIBLE_OBSERVER universal_understand = 1 response_help = "passes through" response_disarm = "swings at" response_harm = "punches" + unsuitable_atmos_damage = 0 minbodytemp = 0 maxbodytemp = INFINITY - harm_intent_damage = 5 - speak_emote = list("hisses", "spits", "growls") + harm_intent_damage = 0 friendly = "touches" status_flags = 0 wander = 0 density = 0 + flying = 1 + anchored = 1 - var/essence = 25 //The resource of revenants. Max health is equal to twice this amount + var/essence = 25 //The resource of revenants. Max health is equal to three times this amount var/essence_regen_cap = 25 //The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount. - var/essence_regen = 1 //If the revenant regenerates essence or not; 1 for yes, 0 for no + var/essence_regenerating = 1 //If the revenant regenerates essence or not; 1 for yes, 0 for no + var/essence_regen_amount = 2 //How much essence regenerates var/essence_min = 1 //The minimum amount of essence a revenant can have; by default, it never drops below one - var/strikes = 0 //How many times a revenant can die before dying for good + var/essence_accumulated = 0 //How much essence the revenant has stolen var/revealed = 0 //If the revenant can take damage from normal sources. var/inhibited = 0 //If the revenant's abilities are blocked by a chaplain's power. + var/essence_drained = 0 //How much essence the revenant has drained. + var/draining = 0 //If the revenant is draining someone. + var/list/drained_mobs = list() //Cannot harvest the same mob twice /mob/living/simple_animal/revenant/Life() ..() if(essence < essence_min) essence = essence_min - if(strikes > 0) - strikes-- - src << "Your essence has dropped below critical levels. You barely manage to save yourself - [strikes ? "you can't keep this up!" : "next time, it's death."]" - else if(strikes <= 0) - Die() - maxHealth = essence * 2 + if(essence_regenerating && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate + essence += essence_regen_amount + if(essence > essence_regen_cap) + essence = essence_regen_cap + maxHealth = essence * 3 if(!revealed) health = maxHealth //Heals to full when not revealed - if(essence_regen && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate - essence++ /mob/living/simple_animal/revenant/ex_act(severity) return 1 //Immune to the effects of explosions. +/mob/living/simple_animal/revenant/blob_act() + return 1 //blah blah blobs aren't in tune with the spirit world, or something. + /mob/living/simple_animal/revenant/ClickOn(var/atom/A, var/params) //Copypaste from ghost code - revenants can't interact with the world directly. if(client.buildmode) build_click(src, client.buildmode, params, A) @@ -75,6 +80,70 @@ if(world.time <= next_move) return A.attack_ghost(src) + if(ishuman(A) && in_range(src, A)) + Harvest(A) + +/mob/living/simple_animal/revenant/proc/Harvest(mob/living/carbon/human/target) + if(!castcheck(0)) + return + if(draining) + src << "You are already siphoning the essence of a soul!" + return + if(target in drained_mobs) + src << "[target]'s soul is dead and empty." + return + if(!target.stat) + src << "This being's soul is too strong to harvest." + if(prob(10)) + target << "You feel as if you are being watched." + return + draining = 1 + essence_drained = 2 + src << "You search for the soul of [target]." + if(do_after(src, 10, 3, 0, target)) //did they get deleted in that second? + if(target.ckey) + src << "Their soul burns with intelligence." + essence_drained += 2 + if(target.stat != DEAD) + src << "Their soul blazes with life!" + essence_drained += 2 + else + src << "Their soul is weak and faltering." + if(do_after(src, 20, 6, 0, target)) //did they get deleted NOW? + switch(essence_drained) + if(1 to 2) + src << "[target] will not yield much essence. Still, every bit counts." + if(3 to 4) + src << "[target] will yield an average amount of essence." + if(5 to INFINITY) + src << "Such a feast! [target] will yield much essence to you." + if(do_after(src, 30, 9, 0, target)) //how about now + if(!target.stat) + src << "They are now powerful enough to fight off your draining." + target << "You feel something tugging across your body before subsiding." + draining = 0 + return //hey, wait a minute... + src << "You begin siphoning essence from [target]'s soul." + if(target.stat != DEAD) + target << "You feel a horribly unpleasant draining sensation as your grip on life weakens..." + icon_state = "revenant_draining" + reveal(65) + stun(65) + target.visible_message("[target] suddenly rises slightly into the air, their skin turning an ashy gray.") + target.Beam(src,icon_state="drain_life",icon='icons/effects/effects.dmi',time=60) + if(target) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining. + change_essence_amount(essence_drained * 5, 0, target) + src << "[target]'s soul has been considerably weakened and will yield no more essence for the time being." + target.visible_message("[target] gently slumps back onto the ground.") + drained_mobs.Add(target) + target.death(0) + icon_state = "revenant_idle" + else + src << "You are not close enough to siphon [target]'s soul. The link has been broken." + draining = 0 + return + draining = 0 + return /mob/living/simple_animal/revenant/say(message) return 0 //Revenants cannot speak out loud. @@ -83,6 +152,7 @@ ..() if(statpanel("Status")) stat(null, "Current essence: [essence]E") + stat(null, "Stolen essence: [essence_accumulated]E") /mob/living/simple_animal/revenant/New() ..() @@ -99,11 +169,11 @@ src << "You do not remember anything of your past lives, nor will you remember anything about this one after your death." src << "Be sure to read the wiki page at http://nanotrasen.se/wiki/index.php/Revenant to learn more." var/datum/objective/revenant/objective = new - objective.owner = src + objective.owner = src.mind src.mind.objectives += objective src << "Objective #1: [objective.explanation_text]" var/datum/objective/revenantFluff/objective2 = new - objective2.owner = src + objective2.owner = src.mind src.mind.objectives += objective2 src << "Objective #2: [objective2.explanation_text]" ticker.mode.traitors |= src.mind //Necessary for announcing @@ -119,13 +189,12 @@ src.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/revenant_harvest src.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/revenant_transmit src.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/revenant_light - src.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/revenantDefile + src.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/revenant_defile + src.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/revenant_malf return 1 return 0 /mob/living/simple_animal/revenant/Die() - if(strikes) - return 0 //Impossible to die with strikes still active ..() src << "NO! No... it's too late, you can feel yourself fading..." notransform = 1 @@ -145,74 +214,78 @@ /mob/living/simple_animal/revenant/attackby(obj/item/W, mob/living/user, params) - ..() if(istype(W, /obj/item/weapon/nullrod)) visible_message("[src] violently flinches!", \ - "The null rod invokes agony in you! You feel your essence draining away!") + "As the null rod passes through you, you feel your essence draining away!") essence -= 25 //hella effective inhibited = 1 spawn(30) inhibited = 0 + + ..() - - -/mob/living/simple_animal/revenant/proc/castcheck(var/essence_cost) - var/mob/living/simple_animal/revenant/user = usr - if(!istype(user) || !user) +/mob/living/simple_animal/revenant/proc/castcheck(essence_cost) + if(!src) return - var/turf/T = get_turf(usr) + var/turf/T = get_turf(src) if(istype(T, /turf/simulated/wall)) - user << "You cannot use abilities from inside of a wall." + src << "You cannot use abilities from inside of a wall." return 0 - if(!user.change_essence_amount(essence_cost, 1)) - user << "You lack the essence to use that ability." + if(src.inhibited) + src << "Your powers have been suppressed by nulling energy!" return 0 - if(user.inhibited) - user << "Your powers have been suppressed by holy energies!" + if(!src.change_essence_amount(essence_cost, 1)) + src << "You lack the essence to use that ability." return 0 return 1 - - -/mob/living/simple_animal/revenant/proc/change_essence_amount(var/essence_amt, var/silent = 0, var/source = null) - var/mob/living/simple_animal/revenant/user = usr - if(!istype(usr) || !usr) +/mob/living/simple_animal/revenant/proc/change_essence_amount(essence_amt, silent = 0, source = null) + if(!src) return - if(user.essence + essence_amt <= 0) + if(essence + essence_amt <= 0) return - user.essence += essence_amt - user.essence = Clamp(user.essence, 0, INFINITY) + essence += essence_amt + essence = max(0, essence) + if(essence_amt > 0) + essence_accumulated += essence_amt + essence_accumulated = max(0, essence_accumulated) if(!silent) if(essence_amt > 0) - user << "Gained [essence_amt]E from [source]." + src << "Gained [essence_amt]E from [source]." else - user << "Lost [essence_amt]E from [source]." + src << "Lost [essence_amt]E from [source]." return 1 - - -/mob/living/simple_animal/revenant/proc/reveal(var/time, var/stun) - var/mob/living/simple_animal/revenant/R = usr - if(!istype(usr) || !usr) +/mob/living/simple_animal/revenant/proc/reveal(time) + if(!src) return - R.revealed = 1 - R.invisibility = 0 - if(stun) - R.notransform = 1 - R << "You have been revealed [stun ? "and cannot move" : ""]." + if(time <= 0) + return + revealed = 1 + invisibility = 0 + src << "You have been revealed." spawn(time) - R.revealed = 0 - R.invisibility = INVISIBILITY_OBSERVER - if(stun) - R.notransform = 0 - R << "You are once more concealed [stun ? "and can move again" : ""]." + revealed = 0 + invisibility = INVISIBILITY_OBSERVER + src << "You are once more concealed." +/mob/living/simple_animal/revenant/proc/stun(time) + if(!src) + return + if(time <= 0) + return + notransform = 1 + src << "You cannot move!" + spawn(time) + notransform = 0 + src << "You can move again!" + /datum/objective/revenant var/targetAmount = 100 /datum/objective/revenant/New() targetAmount = rand(100,200) - explanation_text = "Absorb [targetAmount] points of essence." + explanation_text = "Absorb [targetAmount] points of essence from humans." ..() /datum/objective/revenant/check_completion() @@ -221,8 +294,8 @@ var/mob/living/simple_animal/revenant/R = owner.current if(!R || R.stat == DEAD) return 0 - var/essenceAccumulated = R.essence - if(essenceAccumulated < targetAmount) + var/essence_stolen = R.essence_accumulated + if(essence_stolen < targetAmount) return 0 return 1 @@ -254,7 +327,7 @@ /obj/item/weapon/ectoplasm/revenant/New() ..() reforming = 1 - spawn(1800) //3 minutes + spawn(600) //1 minutes if(src && reforming) return reform() if(src && !reforming) @@ -290,7 +363,7 @@ /obj/item/weapon/ectoplasm/revenant/proc/reform() if(!reforming || !src) return - message_admins("Revenant ectoplasm was left undestroyed for 3 minutes and has reformed into a new revenant.") + message_admins("Revenant ectoplasm was left undestroyed for 1 minute and has reformed into a new revenant.") loc = get_turf(src) //In case it's in a backpack or someone's hand visible_message("[src] suddenly rises into the air before fading away.") var/mob/living/simple_animal/revenant/R = new(get_turf(src)) diff --git a/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm b/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm index 01f527f2e07..016b8171113 100644 --- a/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm +++ b/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm @@ -1,128 +1,66 @@ //Harvest Essence: The bread and butter of the revenant. The basic way of harvesting additional essence. /obj/effect/proc_holder/spell/targeted/revenant_harvest - name = "Harvest (0E)" + name = "Harvest" desc = "Siphons the lingering spectral essence from a human, empowering yourself." panel = "Revenant Abilities" - charge_max = 100 //Short cooldown + charge_max = 0 //Short cooldown clothes_req = 0 - range = 5 - var/essence_drained = 0 - var/draining - var/list/drained_mobs = list() //Cannot harvest the same mob twice + range = 1 /obj/effect/proc_holder/spell/targeted/revenant_harvest/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr) - if(!user.castcheck(0)) - charge_counter = charge_max - return for(var/mob/living/carbon/human/target in targets) spawn(0) - if(draining) - user << "You are already siphoning the essence of a soul!" - return - if(target in drained_mobs) - user << "[target]'s soul is dead and empty." - return - if(target.stat != DEAD) - user << "This being's soul is too strong to harvest." - if(prob(10)) - target << "You feel as if you are being watched." - return - draining = 1 - essence_drained = 1 - user << "You search for the still-living soul of [target]." - sleep(10) - if(target.ckey) - user << "Their soul burns with intelligence." - essence_drained += 3 - sleep(20) - switch(essence_drained) - if(1 to 2) - user << "[target] will not yield much essence. Still, every bit counts." - if(3 to 4) - user << "[target] will yield an average amount of essence." - if(5 to INFINITY) - user << "Such a feast! [target] will yield much essence to you." - sleep(30) - if(!in_range(user, target)) - user << "You are not close enough to siphon [target]'s soul. The link has been broken." - draining = 0 - return - if(!target.stat) - user << "They are now powerful enough to fight off your draining." - target << "You feel something tugging across your body before subsiding." - user << "You begin siphoning essence from [target]'s soul. You can not move while this is happening." - if(target.stat != DEAD) - target << "You feel a horribly unpleasant draining sensation as your grip on life weakens..." - user.icon_state = "revenant_draining" - user.notransform = 1 - user.revealed = 1 - user.invisibility = 0 - target.visible_message("[target] suddenly rises slightly into the air, their skin turning an ashy gray.") - target.Beam(user,icon_state="drain_life",icon='icons/effects/effects.dmi',time=80) - target.death(0) - target.visible_message("[target] gently slumps back onto the ground.") - user.icon_state = "revenant_idle" - user.change_essence_amount(essence_drained * 5, 0, target) - user << "[target]'s soul has been considerably weakened and will yield no more essence for the time being." - user.revealed = 0 - user.notransform = 0 - user.invisibility = INVISIBILITY_OBSERVER - drained_mobs.Add(target) - draining = 0 - + user.Harvest(target) //Transmit: the revemant's only direct way to communicate. Sends a single message silently to a single mob for 5E. /obj/effect/proc_holder/spell/targeted/revenant_transmit - name = "Transmit (5E)" + name = "Transmit" desc = "Telepathically transmits a message to the target." - panel = "Revenant Abilities (Locked)" - charge_max = 50 + panel = "Revenant Abilities" + charge_max = 0 clothes_req = 0 - range = -1 - include_user = 1 - var/locked = 1 + range = 7 + include_user = 0 /obj/effect/proc_holder/spell/targeted/revenant_transmit/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr) - if(!user.castcheck(-5)) - charge_counter = charge_max - return - if(locked) - usr << "You have unlocked Transmit!" - locked = 0 - charge_counter = charge_max - panel = "Revenant Abilities" - range = 7 - include_user = 0 - return for(var/mob/living/M in targets) spawn(0) var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "") if(!msg) charge_counter = charge_max return - usr << "You transmit to [M]: [msg]" - M << "A strange voice resonates in your head... [msg]" + log_say("Revenant Transmit: [key_name(usr)]->[key_name(M)]: [msg]") + usr << "You transmit to [M]: [msg]" + M << "A strange voice resonates in your head... [msg]" + for(var/mob/dead/observer/G in player_list) + G.show_message("Revenant message from [usr] ([ghost_follow_link(usr, ghost=G)]) to [M] ([ghost_follow_link(M, ghost=G)]): [msg]") //Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people. /obj/effect/proc_holder/spell/aoe_turf/revenant_light - name = "Overload Light (25E)" - desc = "Directs a large amount of essence into an electrical light, causing an impressive light show." + name = "Overload Light (30E)" + desc = "Directs a large amount of essence into nearby electrical lights, causing lights to shock those nearby." panel = "Revenant Abilities (Locked)" - charge_max = 300 + charge_max = 200 clothes_req = 0 range = 1 + var/reveal = 80 + var/stun = 20 var/locked = 1 /obj/effect/proc_holder/spell/aoe_turf/revenant_light/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr) - if(!user.castcheck(-25)) - charge_counter = charge_max - return if(locked) - user << "You have unlocked Overload Light!" + if(!user.castcheck(-30)) + charge_counter = charge_max + return + user << "You have unlocked Overload Lights!" + name = "Overload Lights (20E)" panel = "Revenant Abilities" locked = 0 - range = 5 + range = 6 + charge_counter = charge_max + return + if(!user.castcheck(-20)) charge_counter = charge_max return for(var/turf/T in targets) @@ -132,57 +70,106 @@ if(!L.on) return L.visible_message("\The [L] suddenly flares brightly and begins to spark!") - sleep(20) + sleep(10) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(4, 1, L) + s.start() + sleep(10) for(var/mob/living/M in orange(4, L)) if(M == user) return M.Beam(L,icon_state="lightning",icon='icons/effects/effects.dmi',time=5) M.electrocute_act(25, "[L.name]") + var/datum/effect/effect/system/spark_spread/z = new /datum/effect/effect/system/spark_spread + z.set_up(4, 1, M) + z.start() playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1) - user.reveal(50, 1) - + user.reveal(reveal) + user.stun(stun) //Defile: Corrupts nearby stuff, unblesses floor tiles. -/obj/effect/proc_holder/spell/aoe_turf/revenantDefile - name = "Defile (30E)" - desc = "Twists and corrupts certain nearby objects. Also dispels holy auras on floors, but not salt lines." +/obj/effect/proc_holder/spell/aoe_turf/revenant_defile + name = "Defile (35E)" + desc = "Twists and corrupts the nearby area. Also dispels holy auras on floors, but not salt lines." panel = "Revenant Abilities (Locked)" - charge_max = 300 + charge_max = 200 clothes_req = 0 range = 1 + var/reveal = 100 + var/stun = 20 var/locked = 1 -/obj/effect/proc_holder/spell/aoe_turf/revenantDefile/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr) - if(!user.castcheck(-30)) - charge_counter = charge_max - return +/obj/effect/proc_holder/spell/aoe_turf/revenant_defile/cast(list/targets, var/mob/living/simple_animal/revenant/user = usr) if(locked) + if(!user.castcheck(-35)) + charge_counter = charge_max + return user << "You have unlocked Defile!" + name = "Defile (20E)" panel = "Revenant Abilities" locked = 0 - range = 4 + range = 3 + charge_counter = charge_max + return + if(!user.castcheck(-20)) charge_counter = charge_max return for(var/turf/T in targets) spawn(0) if(T.flags & NOJAUNT) T.flags -= NOJAUNT - for(var/obj/machinery/bot/secbot/secbot in T.contents) //Not including ED-209 - secbot.emagged = 2 - secbot.Emag(null) - for(var/obj/machinery/bot/cleanbot/cleanbot in T.contents) - cleanbot.emagged = 2 - cleanbot.Emag(null) + if(!istype(T, /turf/simulated/wall/cult) && istype(T, /turf/simulated/wall) && prob(40)) + T.ChangeTurf(/turf/simulated/wall/cult) + if(!istype(T, /turf/simulated/floor/engine/cult) && istype(T, /turf/simulated/floor) && prob(40)) + T.ChangeTurf(/turf/simulated/floor/engine/cult) for(var/mob/living/carbon/human/human in T.contents) human << "You suddenly feel tired." - human.adjustStaminaLoss(25) - for(var/mob/living/silicon/robot/robot in T.contents) - robot.visible_message("[robot] lets out an alarm!", \ - "01001111 01010110 01000101 01010010 01001100 01001111 01000001 01000100") //Translates to "OVERLOAD" - robot << 'sound/misc/interference.ogg' - playsound(robot, 'sound/machines/warning-buzzer.ogg', 50, 1) + human.adjustStaminaLoss(35) for(var/obj/structure/window/window in T.contents) - window.hit(rand(10,50)) + window.hit(rand(50,125)) for(var/obj/machinery/light/light in T.contents) light.flicker() //spooky - user.reveal(30, 1) + user.reveal(reveal) + user.stun(stun) + +//Malfunction: Makes bad stuff happen to robots and machines. +/obj/effect/proc_holder/spell/aoe_turf/revenant_malf + name = "Malfunction (50E)" + desc = "Corrupts and damages nearby machines and mechanical objects." + panel = "Revenant Abilities (Locked)" + charge_max = 150 + clothes_req = 0 + range = 1 + var/reveal = 60 + var/stun = 30 + var/locked = 1 + +/obj/effect/proc_holder/spell/aoe_turf/revenant_malf/cast(list/targets, mob/living/simple_animal/revenant/user = usr) + if(locked) + if(!user.castcheck(-50)) + charge_counter = charge_max + return + user << "You have unlocked Malfunction!" + name = "Malfunction (15E)" + panel = "Revenant Abilities" + locked = 0 + range = 4 + charge_counter = charge_max + return + if(!user.castcheck(-15)) + charge_counter = charge_max + return + for(var/turf/T in targets) + spawn(0) + for(var/obj/machinery/bot/bot in T.contents) + if(!bot.emagged) + bot.locked = 0 + bot.open = 1 + bot.Emag(null) + for(var/obj/machinery/mach in T.contents) + if(prob(10)) + mach.emag_act(null) + + empulse(user.loc, 3, 5) + user.reveal(reveal) + user.stun(stun) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index f6df572bbbe..dbd87107f1e 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -8,6 +8,7 @@ var/icon_living = "" var/icon_dead = "" + var/icon_resting = "" var/icon_gib = null //We only try to show a gibbing animation if this exists. var/oxygen_alert = 0 @@ -50,7 +51,7 @@ var/max_co2 = 5 var/min_n2 = 0 var/max_n2 = 0 - var/unsuitable_atoms_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above + var/unsuitable_atmos_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above //LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly @@ -86,6 +87,10 @@ return /mob/living/simple_animal/Life() + if(paralysis || stunned || weakened || buckled || resting) + canmove = 0 + else + canmove = 1 //Health if(stat == DEAD) @@ -97,12 +102,16 @@ density = 1 return 0 - if(health < 1) Die() if(health > maxHealth) health = maxHealth + + if(resting && icon_resting && stat != DEAD) + icon_state = icon_resting + else if(icon_resting && stat != DEAD) + icon_state = icon_living if(sleeping) sleeping = max(sleeping-1, 0) @@ -171,7 +180,7 @@ if(Environment) - if( abs(Environment.temperature - bodytemperature) > 40 && !(flags & IS_SYNTHETIC)) + if( abs(Environment.temperature - bodytemperature) > 40 && !(flags & NO_BREATHE)) bodytemperature += ((Environment.temperature - bodytemperature) / 5) if(min_oxy) @@ -204,7 +213,7 @@ if(max_co2) if(Environment.carbon_dioxide > max_co2) atmos_suitable = 0 - if(flags & NO_BREATHE || flags & IS_SYNTHETIC) + if(flags & NO_BREATHE) atmos_suitable = 1 //Atmos effect @@ -218,7 +227,7 @@ fire_alert = 0 if(!atmos_suitable) - adjustBruteLoss(unsuitable_atoms_damage) + adjustBruteLoss(unsuitable_atmos_damage) return 1 /mob/living/simple_animal/Bumped(AM as mob|obj) @@ -548,7 +557,7 @@ gib() return -/mob/living/simple_animal/say(var/message) +/mob/living/simple_animal/say(var/message,var/datum/language/speaking,var/verb) if(stat) return @@ -558,11 +567,11 @@ if(stat) return - var/verb = "says" + verb = "says" if(speak_emote.len) verb = pick(speak_emote) message = capitalize(trim_left(message)) - ..(message, null, verb) + ..(message, speaking, verb) diff --git a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm b/code/modules/mob/living/simple_animal/slaughter/slaughter.dm index a03b9b5173b..764947115d3 100644 --- a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm +++ b/code/modules/mob/living/simple_animal/slaughter/slaughter.dm @@ -120,8 +120,12 @@ var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "") if(!(msg)) return - usr << "You whisper to [M]: [msg]" - M << "Suddenly a strange,demonic,voice resonates in your head... [msg]" + log_say("Slaughter Demon Transmit: [key_name(usr)]->[key_name(M)]: [msg]") + usr << "You whisper to [M]: [msg]" + M << "Suddenly a strange, demonic voice resonates in your head... [msg]" + for(var/mob/dead/observer/G in player_list) + G.show_message("Demonic message from [usr] ([ghost_follow_link(usr, ghost=G)]) to [M] ([ghost_follow_link(M, ghost=G)]): [msg]") + //////////The Loot diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index 39a1fb53631..e72157aedfb 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -45,6 +45,9 @@ client.perspective = MOB_PERSPECTIVE + if(ckey in deadmins) + verbs += /client/proc/readmin + //Clear ability list and update from mob. client.verbs -= ability_verbs @@ -57,27 +60,3 @@ client.verbs |= H.species.abilities CallHook("Login", list("client" = src.client, "mob" = src)) - - //Update morgues on login/logout - if (stat == DEAD) - var/obj/structure/morgue/Morgue = null - var/mob/living/carbon/human/C = null - if (istype(src,/mob/dead/observer)) //We're a ghost, let's find our corpse - var/mob/dead/observer/G = src - if(!G.mind) //This'll probably break morgue sprites, but the line under the next If statement causes runtimes with Assume Direct Control. - return - if (G.can_reenter_corpse && G.mind.current) - C = G.mind.current - else if (istype(src,/mob/living/carbon/human)) - C = src - - if (C) //We found our corpse, is it inside a morgue? - if (istype(C.loc,/obj/structure/morgue)) - Morgue = C.loc - else if (istype(C.loc,/obj/structure/closet/body_bag)) - var/obj/structure/closet/body_bag/B = C.loc - if (istype(B.loc,/obj/structure/morgue)) - Morgue = B.loc - if (Morgue) - Morgue.update() - diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index 36df2619e38..fdc342876dc 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -6,32 +6,11 @@ if (ticker && ticker.current_state == GAME_STATE_PLAYING) //Only report this stuff if we are currently playing. var/admins_number = admins.len - message_admins("Admin logout: [key_name(src)]") + message_admins("Admin logout: [key_name_admin(src)]") if(admins_number == 0) //Apparently the admin logging out is no longer an admin at this point, so we have to check this towards 0 and not towards 1. Awell. send2adminirc("[key_name(src)] logged out - no more admins online.") ..() - - //Update morgues on login/logout - if (stat == DEAD) - var/obj/structure/morgue/Morgue = null - var/mob/living/carbon/human/C = null - if (istype(src,/mob/dead/observer)) //We're a ghost, let's find our corpse - var/mob/dead/observer/G = src - if(!G.mind) //This'll probably break morgue sprites, but the line under the next If statement causes runtimes with Assume Direct Control. - return 1 - if (G.can_reenter_corpse && G.mind.current) - C = G.mind.current - else if (istype(src,/mob/living/carbon/human)) - C = src - - if (C) //We found our corpse, is it inside a morgue? - if (istype(C.loc,/obj/structure/morgue)) - Morgue = C.loc - else if (istype(C.loc,/obj/structure/closet/body_bag)) - var/obj/structure/closet/body_bag/B = C.loc - if (istype(B.loc,/obj/structure/morgue)) - Morgue = B.loc - if (Morgue) - Morgue.update() - + + CallHook("Logout", list("client" = src.client, "mob" = src)) + return 1 \ No newline at end of file diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 4257d29b1fb..dc13bd8c00a 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -406,7 +406,7 @@ if(isalien(attacker) && iscarbon(prey)) //Xenomorphs eating carbon mobs return 1 - if(ishuman(attacker) && attacker.get_species() == "Kidan" && istype(prey,/mob/living/carbon/primitive/diona)) //Kidan eating nymphs + if(ishuman(attacker) && attacker.get_species() == "Kidan" && istype(prey,/mob/living/simple_animal/diona)) //Kidan eating nymphs return 1 if(ishuman(attacker) && attacker.get_species() == "Tajaran" && istype(prey,/mob/living/simple_animal/mouse)) //Tajaran eating mice. Meow! diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 953a898e25b..e64ec58e553 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -96,6 +96,16 @@ proc/isembryo(A) if(istype(A, /mob/living/silicon/ai)) return 1 return 0 + +/mob/proc/isSynthetic() + return 0 + +/mob/living/carbon/human/isSynthetic() + // If they are 100% robotic, they count as synthetic. + for(var/obj/item/organ/external/E in organs) + if(!(E.status & ORGAN_ROBOT)) + return 0 + return 1 /proc/isAIEye(A) if(istype(A, /mob/aiEye)) @@ -164,6 +174,18 @@ proc/isAntag(A) if(C.mind && C.mind.special_role) return 1 return 0 + +proc/isNonCrewAntag(A) + if(!isAntag(A)) + return 0 + + var/mob/living/carbon/C = A + var/special_role = C.mind.special_role + var/list/crew_roles = list("traitor", "Changeling", "Vampire", "Cultist", "Head Revolutionary", "Revolutionary", "malfunctioning AI", "Shadowling", "loyalist", "mutineer", "Response Team") + if((special_role in crew_roles)) + return 0 + + return 1 proc/isnewplayer(A) if(istype(A, /mob/new_player)) @@ -470,7 +492,7 @@ var/list/intents = list("help","disarm","grab","harm") name = realname for(var/mob/M in player_list) - if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || (M.client.holder && (M.client.holder.rights & R_MOD))) && (M.client.prefs.toggles & CHAT_DEAD)) + if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || check_rights(R_MOD,0,M)) && (M.client.prefs.toggles & CHAT_DEAD)) var/follow var/lname if(subject) @@ -481,7 +503,7 @@ var/list/intents = list("help","disarm","grab","harm") var/mob/dead/observer/DM if(istype(subject, /mob/dead/observer)) DM = subject - if(M.client.holder) // What admins see + if(check_rights(R_MOD,0,M)) // What admins see lname = "[keyname][(DM && DM.anonsay) ? "*" : (DM ? "" : "^")] ([name])" else if(DM && DM.anonsay) // If the person is actually observer they have the option to be anonymous diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index df5727e4315..1201c95b74c 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -191,8 +191,6 @@ if(world.time < move_delay) return - if(isAI(mob)) return AIMove(n,direct,mob) - if(!isliving(mob)) return mob.Move(n,direct) if(moving) return 0 @@ -211,10 +209,6 @@ var/mob/spirit/currentSpirit = mob return currentSpirit.Spirit_Move(direct) - // handle possible AI movement - if(isAI(mob)) - return AIMove(n,direct,mob) - if(mob.notransform) return//This is sota the goto stop mobs from moving var if(isliving(mob)) @@ -235,6 +229,9 @@ if(mob.remote_control) //we're controlling something, our movement is relayed to it return mob.remote_control.relaymove(mob, direct) + if(isAI(mob)) + return AIMove(n,direct,mob) + if(!mob.canmove) return diff --git a/code/modules/mob/new_player/login.dm b/code/modules/mob/new_player/login.dm index 53946a3eb1d..8c8e10493dc 100644 --- a/code/modules/mob/new_player/login.dm +++ b/code/modules/mob/new_player/login.dm @@ -30,6 +30,8 @@ CallHook("Login", list("client" = src.client, "mob" = src)) new_player_panel() + if(ckey in deadmins) + verbs += /client/proc/readmin spawn(40) if(client) handle_privacy_poll() diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 15456b3fa7c..cdbf376e97f 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -43,7 +43,7 @@ var/isadmin = 0 if(src.client && src.client.holder) isadmin = 1 - var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_poll_question WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM erro_poll_vote WHERE ckey = \"[ckey]\") AND id NOT IN (SELECT pollid FROM erro_poll_textreply WHERE ckey = \"[ckey]\")") + var/DBQuery/query = dbcon.NewQuery("SELECT id FROM [format_table_name("poll_question")] WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM [format_table_name("poll_vote")] WHERE ckey = \"[ckey]\") AND id NOT IN (SELECT pollid FROM [format_table_name("poll_textreply")] WHERE ckey = \"[ckey]\")") query.Execute() var/newpoll = 0 while(query.NextRow()) @@ -178,7 +178,7 @@ var/voted = 0 //First check if the person has not voted yet. - var/DBQuery/query = dbcon.NewQuery("SELECT * FROM erro_privacy WHERE ckey='[src.ckey]'") + var/DBQuery/query = dbcon.NewQuery("SELECT * FROM [format_table_name("privacy")] WHERE ckey='[src.ckey]'") query.Execute() while(query.NextRow()) voted = 1 @@ -203,7 +203,7 @@ return if(!voted) - var/sql = "INSERT INTO erro_privacy VALUES (null, Now(), '[src.ckey]', '[option]')" + var/sql = "INSERT INTO [format_table_name("privacy")] VALUES (null, Now(), '[src.ckey]', '[option]')" var/DBQuery/query_insert = dbcon.NewQuery(sql) query_insert.Execute() usr << "Thank you for your vote!" @@ -468,11 +468,9 @@ if(is_alien_whitelisted(src, client.prefs.language) || !config.usealienwhitelist || !(chosen_language.flags & WHITELISTED)) new_character.add_language(client.prefs.language) if(ticker.random_players || appearance_isbanned(new_character)) - new_character.gender = pick(MALE, FEMALE) + client.prefs.random_character() client.prefs.real_name = random_name(new_character.gender) - client.prefs.randomize_appearance_for(new_character) - else - client.prefs.copy_to(new_character) + client.prefs.copy_to(new_character) src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // MAD JAMS cant last forever yo diff --git a/code/modules/mob/new_player/poll.dm b/code/modules/mob/new_player/poll.dm index 884b7ffc4ee..4786537d36b 100644 --- a/code/modules/mob/new_player/poll.dm +++ b/code/modules/mob/new_player/poll.dm @@ -5,7 +5,7 @@ return var/voted = 0 - var/DBQuery/query = dbcon.NewQuery("SELECT * FROM erro_privacy WHERE ckey='[src.ckey]'") + var/DBQuery/query = dbcon.NewQuery("SELECT * FROM [format_table_name("privacy")] WHERE ckey='[src.ckey]'") query.Execute() while(query.NextRow()) voted = 1 @@ -53,7 +53,7 @@ if(src.client && src.client.holder) isadmin = 1 - var/DBQuery/select_query = dbcon.NewQuery("SELECT id, question FROM erro_poll_question WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime") + var/DBQuery/select_query = dbcon.NewQuery("SELECT id, question FROM [format_table_name("poll_question")] WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime") select_query.Execute() var/output = "
Player polls" @@ -84,7 +84,7 @@ establish_db_connection() if(dbcon.IsConnected()) - var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM erro_poll_question WHERE id = [pollid]") + var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM [format_table_name("poll_question")] WHERE id = [pollid]") select_query.Execute() var/pollstarttime = "" @@ -109,7 +109,7 @@ switch(polltype) //Polls that have enumerated options if("OPTION") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT optionid FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT optionid FROM [format_table_name("poll_vote")] WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") voted_query.Execute() var/voted = 0 @@ -121,7 +121,7 @@ var/list/datum/polloption/options = list() - var/DBQuery/options_query = dbcon.NewQuery("SELECT id, text FROM erro_poll_option WHERE pollid = [pollid]") + var/DBQuery/options_query = dbcon.NewQuery("SELECT id, text FROM [format_table_name("poll_option")] WHERE pollid = [pollid]") options_query.Execute() while(options_query.NextRow()) var/datum/polloption/PO = new() @@ -162,7 +162,7 @@ //Polls with a text input if("TEXT") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT replytext FROM erro_poll_textreply WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT replytext FROM [format_table_name("poll_textreply")] WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") voted_query.Execute() var/voted = 0 @@ -204,7 +204,7 @@ //Polls with a text input if("NUMVAL") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT o.text, v.rating FROM erro_poll_option o, erro_poll_vote v WHERE o.pollid = [pollid] AND v.ckey = '[usr.ckey]' AND o.id = v.optionid") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT o.text, v.rating FROM [format_table_name("poll_option")] o, erro_poll_vote v WHERE o.pollid = [pollid] AND v.ckey = '[usr.ckey]' AND o.id = v.optionid") voted_query.Execute() var/output = "
Player poll" @@ -230,7 +230,7 @@ var/minid = 999999 var/maxid = 0 - var/DBQuery/option_query = dbcon.NewQuery("SELECT id, text, minval, maxval, descmin, descmid, descmax FROM erro_poll_option WHERE pollid = [pollid]") + var/DBQuery/option_query = dbcon.NewQuery("SELECT id, text, minval, maxval, descmin, descmid, descmax FROM [format_table_name("poll_option")] WHERE pollid = [pollid]") option_query.Execute() while(option_query.NextRow()) var/optionid = text2num(option_query.item[1]) @@ -273,7 +273,7 @@ src << browse(output,"window=playerpoll;size=500x500") if("MULTICHOICE") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT optionid FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT optionid FROM [format_table_name("poll_vote")] WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") voted_query.Execute() var/list/votedfor = list() @@ -286,7 +286,7 @@ var/maxoptionid = 0 var/minoptionid = 0 - var/DBQuery/options_query = dbcon.NewQuery("SELECT id, text FROM erro_poll_option WHERE pollid = [pollid]") + var/DBQuery/options_query = dbcon.NewQuery("SELECT id, text FROM [format_table_name("poll_option")] WHERE pollid = [pollid]") options_query.Execute() while(options_query.NextRow()) var/datum/polloption/PO = new() @@ -345,7 +345,7 @@ establish_db_connection() if(dbcon.IsConnected()) - var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") + var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM [format_table_name("poll_question")] WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") select_query.Execute() var/validpoll = 0 @@ -363,7 +363,7 @@ usr << "\red Poll is not valid." return - var/DBQuery/select_query2 = dbcon.NewQuery("SELECT id FROM erro_poll_option WHERE id = [optionid] AND pollid = [pollid]") + var/DBQuery/select_query2 = dbcon.NewQuery("SELECT id FROM [format_table_name("poll_option")] WHERE id = [optionid] AND pollid = [pollid]") select_query2.Execute() var/validoption = 0 @@ -378,7 +378,7 @@ var/alreadyvoted = 0 - var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM [format_table_name("poll_vote")] WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") voted_query.Execute() while(voted_query.NextRow()) @@ -399,7 +399,7 @@ adminrank = usr.client.holder.rank - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO erro_poll_vote (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]')") + var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO [format_table_name("poll_vote")] (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]')") insert_query.Execute() usr << "\blue Vote successful." @@ -415,7 +415,7 @@ establish_db_connection() if(dbcon.IsConnected()) - var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") + var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype FROM [format_table_name("poll_question")] WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") select_query.Execute() var/validpoll = 0 @@ -432,7 +432,7 @@ var/alreadyvoted = 0 - var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM erro_poll_textreply WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM [format_table_name("poll_textreply")] WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") voted_query.Execute() while(voted_query.NextRow()) @@ -457,7 +457,7 @@ usr << "The text you entered was blank, contained illegal characters or was too long. Please correct the text and submit again." return - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO erro_poll_textreply (id ,datetime ,pollid ,ckey ,ip ,replytext ,adminrank) VALUES (null, Now(), [pollid], '[usr.ckey]', '[usr.client.address]', '[replytext]', '[adminrank]')") + var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO [format_table_name("poll_textreply")] (id ,datetime ,pollid ,ckey ,ip ,replytext ,adminrank) VALUES (null, Now(), [pollid], '[usr.ckey]', '[usr.client.address]', '[replytext]', '[adminrank]')") insert_query.Execute() usr << "\blue Feedback logging successful." @@ -473,7 +473,7 @@ establish_db_connection() if(dbcon.IsConnected()) - var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") + var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype FROM [format_table_name("poll_question")] WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") select_query.Execute() var/validpoll = 0 @@ -488,7 +488,7 @@ usr << "\red Poll is not valid." return - var/DBQuery/select_query2 = dbcon.NewQuery("SELECT id FROM erro_poll_option WHERE id = [optionid] AND pollid = [pollid]") + var/DBQuery/select_query2 = dbcon.NewQuery("SELECT id FROM [format_table_name("poll_option")] WHERE id = [optionid] AND pollid = [pollid]") select_query2.Execute() var/validoption = 0 @@ -503,7 +503,7 @@ var/alreadyvoted = 0 - var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM erro_poll_vote WHERE optionid = [optionid] AND ckey = '[usr.ckey]'") + var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM [format_table_name("poll_vote")] WHERE optionid = [optionid] AND ckey = '[usr.ckey]'") voted_query.Execute() while(voted_query.NextRow()) @@ -519,7 +519,7 @@ adminrank = usr.client.holder.rank - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO erro_poll_vote (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank, rating) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]', [(isnull(rating)) ? "null" : rating])") + var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO [format_table_name("poll_vote")] (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank, rating) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]', [(isnull(rating)) ? "null" : rating])") insert_query.Execute() usr << "\blue Vote successful." diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index 363675b723c..b60ebe12c5d 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -1,11 +1,12 @@ datum/preferences //The mob should have a gender you want before running this proc. Will run fine without H - proc/randomize_appearance_for(var/mob/living/carbon/human/H) - if(H) - if(H.gender == MALE) - gender = MALE - else - gender = FEMALE + proc/random_character(gender_override) + if(gender_override) + gender = gender_override + else + gender = pick(MALE, FEMALE) + underwear = random_underwear(gender) + undershirt = random_undershirt(gender) if(species == "Human") s_tone = random_skin_tone() h_style = random_hair_style(gender, species) @@ -16,12 +17,8 @@ datum/preferences randomize_eyes_color() if(species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Vulpkanin") randomize_skin_color() - underwear = rand(1,underwear_m.len) - undershirt = rand(1,undershirt_t.len) backbag = 2 age = rand(AGE_MIN,AGE_MAX) - if(H) - copy_to(H,1) proc/randomize_hair_color(var/target = "hair") @@ -256,12 +253,16 @@ datum/preferences var/icon/underwear_s = null - if(underwear > 0 && underwear < 7 && current_species.flags & HAS_UNDERWEAR) - underwear_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = "underwear[underwear]_[g]_s") + if(underwear && current_species.flags & HAS_UNDERWEAR) + var/datum/sprite_accessory/underwear/U = underwear_list[underwear] + if(U) + underwear_s = new/icon(U.icon, "[U.icon_state]_s", ICON_OVERLAY) var/icon/undershirt_s = null - if(undershirt > 0 && undershirt < 45 && current_species.flags & HAS_UNDERWEAR) - undershirt_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = "undershirt[undershirt]_s") + if(undershirt && current_species.flags & HAS_UNDERWEAR) + var/datum/sprite_accessory/undershirt/U2 = undershirt_list[undershirt] + if(U2) + undershirt_s = new/icon(U2.icon, "[U2.icon_state]_s", ICON_OVERLAY) var/icon/clothes_s = null var/uniform_dmi='icons/mob/uniform.dmi' diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index 24959d7e151..45fe53c3d82 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -17,16 +17,29 @@ conversion in savefile.dm */ +/proc/init_sprite_accessory_subtypes(var/prototype, var/list/L, var/list/male, var/list/female) + if(!istype(L)) L = list() + if(!istype(male)) male = list() + if(!istype(female)) female = list() + + for(var/path in subtypesof(prototype)) + var/datum/sprite_accessory/D = new path() + + L[D.name] = D + + switch(D.gender) + if(MALE) male += D.name + if(FEMALE) female += D.name + else + male += D.name + female += D.name + return L + /datum/sprite_accessory - - var/icon // the icon file the accessory is located in - var/icon_state // the icon_state of the accessory - var/preview_state // a custom preview state for whatever reason - - var/name // the preview name of the accessory - - // Determines if the accessory will be skipped or included in random hair generations - var/gender = NEUTER + var/icon //the icon file the accessory is located in + var/icon_state //the icon_state of the accessory + var/name //the preview name of the accessory + var/gender = NEUTER //Determines if the accessory will be skipped or included in random hair generations // Restrict some styles to specific species var/list/species_allowed = list("Human") @@ -935,3 +948,316 @@ icon_state = "default" icon = 'icons/mob/human_races/r_skrell.dmi' species_allowed = list("Skrell") + +/////////////////////////// +// Underwear Definitions // +/////////////////////////// +/datum/sprite_accessory/underwear + icon = 'icons/mob/underwear.dmi' + + species_allowed = list("Human","Unathi","Vox","Diona","Kidan","Grey","Plasmaman","Skellington") + + nude + name = "Nude" + icon_state = null + gender = NEUTER + + male_white + name = "Mens White" + icon_state = "male_white" + gender = MALE + + male_grey + name = "Mens Grey" + icon_state = "male_grey" + gender = MALE + + male_green + name = "Mens Green" + icon_state = "male_green" + gender = MALE + + male_blue + name = "Mens Blue" + icon_state = "male_blue" + gender = MALE + + male_black + name = "Mens Black" + icon_state = "male_black" + gender = MALE + + male_mankini + name = "Mankini" + icon_state = "male_mankini" + gender = MALE + + female_red + name = "Ladies Red" + icon_state = "female_red" + gender = FEMALE + + female_white + name = "Ladies White" + icon_state = "female_white" + gender = FEMALE + + female_yellow + name = "Ladies Yellow" + icon_state = "female_yellow" + gender = FEMALE + + female_blue + name = "Ladies Blue" + icon_state = "female_blue" + gender = FEMALE + + female_black + name = "Ladies Black" + icon_state = "female_black" + gender = FEMALE + + female_kinky + name = "Ladies Kinky" + icon_state = "female_kinky" + gender = FEMALE + +//////////////////////////// +// Undershirt Definitions // +//////////////////////////// +/datum/sprite_accessory/undershirt + icon = 'icons/mob/underwear.dmi' + + species_allowed = list("Human","Unathi","Vox","Diona","Kidan","Grey","Plasmaman","Skellington") + +/datum/sprite_accessory/undershirt/nude + name = "Nude" + icon_state = null + gender = NEUTER + +//plain color shirts +/datum/sprite_accessory/undershirt/shirt_white + name = "White Shirt" + icon_state = "shirt_white" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_black + name = "Black Shirt" + icon_state = "shirt_black" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_grey + name = "Grey Shirt" + icon_state = "shirt_grey" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_red + name = "Red Shirt" + icon_state = "shirt_red" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_blue + name = "Blue Shirt" + icon_state = "shirt_blue" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_yellow + name = "Yellow Shirt" + icon_state = "shirt_yellow" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_green + name = "Green Shirt" + icon_state = "shirt_green" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_darkblue + name = "Dark Blue Shirt" + icon_state = "shirt_darkblue" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_darkred + name = "Dark Red Shirt" + icon_state = "shirt_darkred" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_darkgreen + name = "Dark Green Shirt" + icon_state = "shirt_darkgreen" + gender = NEUTER +//end plain color shirts + +/datum/sprite_accessory/undershirt/shirt_heart + name = "Heart Shirt" + icon_state = "shirt_heart" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_corgi + name = "Corgi Shirt" + icon_state = "shirt_corgi" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_jack + name = "Union Jack Shirt" + icon_state = "shirt_jack" + gender = NEUTER + +/datum/sprite_accessory/undershirt/love_nt + name = "I Love NT Shirt" + icon_state = "shirt_lovent" + gender = NEUTER + +/datum/sprite_accessory/undershirt/peace + name = "Peace Shirt" + icon_state = "shirt_peace" + gender = NEUTER + +/datum/sprite_accessory/undershirt/mondmondjaja + name = "Band Shirt" + icon_state = "shirt_band" + gender = NEUTER + +/datum/sprite_accessory/undershirt/pacman + name = "Pogoman Shirt" + icon_state = "shirt_pogoman" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_ss13 + name = "SS13 Shirt" + icon_state = "shirt_ss13" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_question + name = "Question Mark Shirt" + icon_state = "shirt_question" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_skull + name = "Skull Shirt" + icon_state = "shirt_skull" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_commie + name = "Communist Shirt" + icon_state = "shirt_commie" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_nano + name = "Nanotrasen Shirt" + icon_state = "shirt_nano" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_meat + name = "Meat Shirt" + icon_state = "shirt_meat" + gender = NEUTER + +/datum/sprite_accessory/undershirt/shirt_tiedie + name = "Tiedie Shirt" + icon_state = "shirt_tiedie" + gender = NEUTER + +/datum/sprite_accessory/undershirt/blue_striped + name = "Striped Blue Shirt" + icon_state = "shirt_bluestripe" + gender = NEUTER + +/datum/sprite_accessory/undershirt/brightblue_striped + name = "Striped Bright Blue Shirt" + icon_state = "shirt_brightbluestripe" + gender = NEUTER + + +//short sleeved +/datum/sprite_accessory/undershirt/short_white + name = "White Short-sleeved Shirt" + icon_state = "short_white" + gender = NEUTER + +/datum/sprite_accessory/undershirt/short_purple + name = "Purple Short-sleeved Shirt" + icon_state = "short_purple" + gender = NEUTER + +/datum/sprite_accessory/undershirt/short_blue + name = "Blue Short-sleeved Shirt" + icon_state = "short_blue" + gender = NEUTER + +/datum/sprite_accessory/undershirt/short_green + name = "Green Short-sleeved Shirt" + icon_state = "short_green" + gender = NEUTER + +/datum/sprite_accessory/undershirt/short_black + name = "Black Short-sleeved Shirt" + icon_state = "short_black" + gender = NEUTER +//end short sleeved + +//polo shirts +/datum/sprite_accessory/undershirt/polo_blue + name = "Blue Polo Shirt" + icon_state = "polo_blue" + gender = NEUTER + +/datum/sprite_accessory/undershirt/polo_red + name = "Red Polo Shirt" + icon_state = "polo_red" + gender = NEUTER + +/datum/sprite_accessory/undershirt/polo_greyelllow + name = "Grey-Yellow Polo Shirt" + icon_state = "polo_greyellow" + gender = NEUTER +//end polo shirts + +//sport shirts +/datum/sprite_accessory/undershirt/sport_green + name = "Green Sports Shirt" + icon_state = "sport_green" + gender = NEUTER + +/datum/sprite_accessory/undershirt/sport_red + name = "Red Sports Shirt" + icon_state = "sport_red" + gender = NEUTER + +/datum/sprite_accessory/undershirt/sport_blue + name = "Blue Sports Shirt" + icon_state = "sport_blue" + gender = NEUTER +//end sport shirts + +/datum/sprite_accessory/undershirt/jersey_red + name = "Red Jersey" + icon_state = "jersey_red" + gender = NEUTER + +/datum/sprite_accessory/undershirt/jersey_blue + name = "Blue Jersey" + icon_state = "jersey_blue" + gender = NEUTER + + +//tanktops +/datum/sprite_accessory/undershirt/tank_white + name = "White Tank-Top" + icon_state = "tank_white" + gender = NEUTER + +/datum/sprite_accessory/undershirt/tank_black + name = "Black Tank-Top" + icon_state = "tank_black" + gender = NEUTER + +/datum/sprite_accessory/undershirt/tank_grey + name = "Grey Tank-Top" + icon_state = "tank_grey" + gender = NEUTER + +/datum/sprite_accessory/undershirt/tank_fire + name = "Fire Tank-Top" + icon_state = "tank_fire" + gender = NEUTER +//end tanktops \ No newline at end of file diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index bd2734c5134..93aa753e446 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -121,8 +121,9 @@ O.add_ai_verbs() O.rename_self("ai",1) - . = O - qdel(src) + spawn + qdel(src) + return O /mob/living/carbon/human/make_into_mask(var/should_gib = 0) for(var/t in organs) @@ -481,7 +482,7 @@ return 1 //Friendly Creatures! - if(ispath(MP, /mob/living/carbon/primitive/diona) && !jobban_isbanned(src, "Dionaea")) + if(ispath(MP, /mob/living/simple_animal/diona) && !jobban_isbanned(src, "Dionaea")) return 1 //Not in here? Must be untested! diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 08a946e547c..01b95c09ddf 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -58,39 +58,59 @@ var/list/organ_cache = list() if(status & ORGAN_ROBOT) return damage = max_damage + status |= ORGAN_DEAD processing_objects -= src if(dead_icon) icon_state = dead_icon + if(owner && vital) + owner.death() /obj/item/organ/process() + if(loc != owner) + owner = null + //dead already, no need for more processing + if(status & ORGAN_DEAD) + return + // Don't process if we're in a freezer, an MMI or a stasis bag. //TODO: ambient temperature? if(istype(loc,/obj/item/device/mmi) || istype(loc,/obj/item/bodybag/cryobag) || istype(loc,/obj/structure/closet/crate/freezer)) return //Process infections - if (robotic >= 2 || (owner && owner.species && (owner.species.flags & IS_PLANT))) + if ((status & ORGAN_ROBOT) || (owner && owner.species && (owner.species.flags & IS_PLANT))) germ_level = 0 return - - if(loc != owner) - owner = null - + if(!owner) if(reagents) var/datum/reagent/blood/B = locate(/datum/reagent/blood) in reagents.reagent_list if(B && prob(40)) reagents.remove_reagent("blood",0.1) blood_splatter(src,B,1) - if(prob(5)) //How about we not have organs become completely useless less than a minute after removal? - damage += 1 + + germ_level += rand(2,6) + if(germ_level >= INFECTION_LEVEL_TWO) + germ_level += rand(2,6) + if(germ_level >= INFECTION_LEVEL_THREE) + die() if(damage >= max_damage) die() + else if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs //** Handle antibiotics and curing infections handle_antibiotics() handle_germ_effects() + + //check if we've hit max_damage + if(damage >= max_damage) + die() + +/obj/item/organ/examine(mob/user) + ..(user) + if(status & ORGAN_DEAD) + user << "The decay has set in." /obj/item/organ/proc/handle_germ_effects() //** Handle the effects of infections @@ -188,31 +208,17 @@ var/list/organ_cache = list() min_broken_damage = 35 /obj/item/organ/emp_act(severity) - switch(robotic) - if(0) + if(!(status & ORGAN_ROBOT)) + return + switch (severity) + if (1.0) + take_damage(0,20) return - if(1) - switch (severity) - if (1.0) - take_damage(20,0) - return - if (2.0) - take_damage(7,0) - return - if(3.0) - take_damage(3,0) - return - if(2) - switch (severity) - if (1.0) - take_damage(40,0) - return - if (2.0) - take_damage(15,0) - return - if(3.0) - take_damage(10,0) - return + if (2.0) + take_damage(0,7) + return + if(3.0) + take_damage(0,3) /obj/item/organ/proc/removed(var/mob/living/user) @@ -236,9 +242,9 @@ var/list/organ_cache = list() if(owner && vital) if(user) - user.attack_log += "\[[time_stamp()]\] removed a vital organ ([src]) from [owner.name] ([owner.ckey]) (INTENT: [uppertext(user.a_intent)])" - owner.attack_log += "\[[time_stamp()]\] had a vital organ ([src]) removed by [user.name] ([user.ckey]) (INTENT: [uppertext(user.a_intent)])" - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] removed a vital organ ([src]) from [owner.name] ([owner.ckey]) (INTENT: [uppertext(user.a_intent)]) (JMP)") + user.attack_log += "\[[time_stamp()]\] removed a vital organ ([src]) from [key_name(owner)] (INTENT: [uppertext(user.a_intent)])" + owner.attack_log += "\[[time_stamp()]\] had a vital organ ([src]) removed by [key_name(user)] (INTENT: [uppertext(user.a_intent)])" + msg_admin_attack("[key_name_admin(user)] removed a vital organ ([src]) from [key_name_admin(owner)]") owner.death() owner = null diff --git a/code/modules/organs/organ_alien.dm b/code/modules/organs/organ_alien.dm deleted file mode 100644 index 0031fffead4..00000000000 --- a/code/modules/organs/organ_alien.dm +++ /dev/null @@ -1,388 +0,0 @@ -/* -/proc/spawn_diona_nymph_from_organ(var/obj/item/organ/organ) - if(!istype(organ)) - return - - //This is a terrible hack and I should be ashamed. - var/datum/seed/diona = plant_controller.seeds["diona"] - if(!diona) - del(src) - - spawn(1) // So it has time to be thrown about by the gib() proc. - var/mob/living/carbon/primitive/diona/D = new(get_turf(organ)) - diona.request_player(D) - del(organ) -*/ - -/obj/item/organ/external/diona - name = "tendril" - cannot_break = 1 - amputation_point = "branch" - -/obj/item/organ/external/diona/chest - name = "core trunk" - limb_name = "chest" - icon_name = "torso" - health = 200 - min_broken_damage = 50 - body_part = UPPER_TORSO - vital = 1 - cannot_amputate = 1 - parent_organ = null - -/obj/item/organ/external/diona/groin - name = "fork" - limb_name = "groin" - icon_name = "groin" - health = 100 - min_broken_damage = 50 - body_part = LOWER_TORSO - vital = 1 - parent_organ = "chest" - -/obj/item/organ/external/diona/arm - name = "left upper tendril" - limb_name = "l_arm" - icon_name = "l_arm" - health = 35 - min_broken_damage = 20 - body_part = ARM_LEFT - parent_organ = "chest" - can_grasp = 1 - -/obj/item/organ/external/diona/arm/right - name = "right upper tendril" - limb_name = "r_arm" - icon_name = "r_arm" - body_part = ARM_RIGHT - -/obj/item/organ/external/diona/leg - name = "left lower tendril" - limb_name = "l_leg" - icon_name = "l_leg" - health = 35 - min_broken_damage = 20 - body_part = LEG_LEFT - icon_position = LEFT - parent_organ = "groin" - can_stand = 1 - -/obj/item/organ/external/diona/leg/right - name = "right lower tendril" - limb_name = "r_leg" - icon_name = "r_leg" - body_part = LEG_RIGHT - icon_position = RIGHT - -/obj/item/organ/external/diona/foot - name = "left foot" - limb_name = "l_foot" - icon_name = "l_foot" - health = 20 - min_broken_damage = 10 - body_part = FOOT_LEFT - icon_position = LEFT - parent_organ = "l_leg" - can_stand = 1 - -/obj/item/organ/external/diona/foot/right - name = "right foot" - limb_name = "r_foot" - icon_name = "r_foot" - body_part = FOOT_RIGHT - icon_position = RIGHT - parent_organ = "r_leg" - amputation_point = "right ankle" - -/obj/item/organ/external/diona/hand - name = "left grasper" - limb_name = "l_hand" - icon_name = "l_hand" - health = 30 - min_broken_damage = 15 - body_part = HAND_LEFT - parent_organ = "l_arm" - can_grasp = 1 - -/obj/item/organ/external/diona/hand/right - name = "right grasper" - limb_name = "r_hand" - icon_name = "r_hand" - body_part = HAND_RIGHT - parent_organ = "r_arm" - -/obj/item/organ/external/diona/head - limb_name = "head" - icon_name = "head" - name = "head" - health = 50 - min_broken_damage = 25 - body_part = HEAD - vital = 1 - parent_organ = "chest" - -/obj/item/organ/external/diona/head/removed() - if(owner) - owner.unEquip(owner.head) - owner.unEquip(owner.l_ear) - ..() - -/* -//DIONA ORGANS. -/obj/item/organ/external/diona/removed() - ..() - if(!istype(owner)) - del(src) - - if(!owner.organs.len) - owner.death() - - if(prob(50)) - spawn_diona_nymph_from_organ(src) -*/ -/obj/item/organ/diona/process() - return - -/obj/item/organ/diona/strata - name = "neural strata" - parent_organ = "chest" - -/obj/item/organ/diona/bladder - name = "gas bladder" - parent_organ = "head" - -/obj/item/organ/diona/polyp - name = "polyp segment" - parent_organ = "groin" - -/obj/item/organ/diona/ligament - name = "anchoring ligament" - parent_organ = "groin" - -/obj/item/organ/diona/node - name = "receptor node" - parent_organ = "head" - -/obj/item/organ/diona/nutrients - name = "nutrient vessel" - parent_organ = "chest" - -/obj/item/organ/diona - name = "diona nymph" - icon = 'icons/obj/objects.dmi' - icon_state = "nymph" - organ_tag = "special" // Turns into a nymph instantly, no transplanting possible. -/* -/obj/item/organ/diona/removed(var/mob/living/user) - - ..() - if(!istype(owner)) - del(src) - - if(!owner.internal_organs.len) - owner.death() - - spawn_diona_nymph_from_organ(src) -*/ -// These are different to the standard diona organs as they have a purpose in other -// species (absorbing radiation and light respectively) -/obj/item/organ/diona/nutrients - name = "nutrient vessel" - organ_tag = "nutrient vessel" - icon = 'icons/mob/alien.dmi' - icon_state = "claw" - -/obj/item/organ/diona/nutrients/removed() - return - -/obj/item/organ/diona/node - name = "receptor node" - organ_tag = "receptor node" - icon = 'icons/mob/alien.dmi' - icon_state = "claw" - -/obj/item/organ/diona/node/removed() - return - -//CORTICAL BORER ORGANS. -/obj/item/organ/borer - name = "cortical borer" - parent_organ = "head" - vital = 1 - -/obj/item/organ/borer/process() - - // Borer husks regenerate health, feel no pain, and are resistant to stuns and brainloss. - for(var/chem in list("saline", "sailcylic", "meth", "mannitol")) - if(owner.reagents.get_reagent_amount(chem) < 3) - owner.reagents.add_reagent(chem, 5) - - // They're also super gross and ooze ichor. - if(prob(5)) - var/mob/living/carbon/human/H = owner - if(!istype(H)) - return - - var/datum/reagent/blood/B = locate(/datum/reagent/blood) in H.vessel.reagent_list - blood_splatter(H,B,1) - var/obj/effect/decal/cleanable/blood/splatter/goo = locate() in get_turf(owner) - if(goo) - goo.name = "husk ichor" - goo.desc = "It's thick and stinks of decay." - goo.basecolor = "#412464" - goo.update_icon() - -/obj/item/organ/borer - name = "cortical borer" - icon = 'icons/obj/objects.dmi' - icon_state = "borer" - organ_tag = "brain" - desc = "A disgusting space slug." - -/obj/item/organ/borer/removed(var/mob/living/user) - - ..() - - var/mob/living/simple_animal/borer/B = owner.has_brain_worms() - if(B) - B.leave_host() - B.ckey = owner.ckey - - spawn(0) - qdel(src) - -//XENOMORPH ORGANS -/obj/item/organ/xenos/eggsac - name = "egg sac" - parent_organ = "groin" - -/obj/item/organ/xenos/plasmavessel - name = "plasma vessel" - parent_organ = "chest" - var/stored_plasma = 0 - var/max_plasma = 500 - -/obj/item/organ/xenos/plasmavessel/queen - name = "bloated plasma vessel" - stored_plasma = 200 - max_plasma = 500 - -/obj/item/organ/xenos/plasmavessel/sentinel - stored_plasma = 100 - max_plasma = 250 - -/obj/item/organ/xenos/plasmavessel/hunter - name = "tiny plasma vessel" - stored_plasma = 100 - max_plasma = 150 - -/obj/item/organ/xenos/acidgland - name = "acid gland" - parent_organ = "head" - -/obj/item/organ/xenos/hivenode - name = "hive node" - parent_organ = "chest" - -/obj/item/organ/xenos/resinspinner - name = "resin spinner" - parent_organ = "head" - -/obj/item/organ/xenos - name = "xeno organ" - icon = 'icons/effects/blood.dmi' - desc = "It smells like an accident in a chemical factory." - -/obj/item/organ/xenos/eggsac - name = "egg sac" - icon_state = "xgibmid1" - organ_tag = "egg sac" - -/obj/item/organ/xenos/plasmavessel - name = "plasma vessel" - icon_state = "xgibdown1" - organ_tag = "plasma vessel" - -/obj/item/organ/xenos/acidgland - name = "acid gland" - icon_state = "xgibtorso" - organ_tag = "acid gland" - -/obj/item/organ/xenos/hivenode - name = "hive node" - icon_state = "xgibmid2" - organ_tag = "hive node" - -/obj/item/organ/xenos/resinspinner - name = "hive node" - icon_state = "xgibmid2" - organ_tag = "resin spinner" - -//VOX ORGANS. -/obj/item/organ/stack - name = "cortical stack" - icon_state = "brain-prosthetic" - parent_organ = "head" - organ_tag = "stack" - robotic = 2 - vital = 1 - var/backup_time = 0 - var/datum/mind/backup - -/obj/item/organ/stack/process() - if(owner && owner.stat != 2 && !is_broken()) - backup_time = world.time - if(owner.mind) backup = owner.mind - -/obj/item/organ/stack/vox - name = "vox cortical stack" - -/obj/item/organ/stack/vox/stack - - -//WRYN ORGAN - -/obj/item/organ/wryn/hivenode - name = "antennae" - parent_organ = "head" - -/obj/item/organ/wryn/hivenode - name = "antennae" - organ_tag = "antennae" - icon = 'icons/mob/human_races/r_wryn.dmi' - icon_state = "antennae" - - -//NUCLEATION ORGAN - -/obj/item/organ/nucleation - name = "nucleation organ" - icon = 'icons/obj/surgery.dmi' - desc = "A crystalized human organ. /red It has a strangely iridescent glow." - -/obj/item/organ/nucleation/resonant_crystal - name = "resonant crystal" - icon_state = "resonant-crystal" - organ_tag = "resonant crystal" - parent_organ = "head" - -/obj/item/organ/nucleation/strange_crystal - name = "strange crystal" - icon_state = "strange-crystal" - organ_tag = "strange crystal" - parent_organ = "chest" - -/obj/item/organ/eyes/luminescent_crystal - name = "luminescent eyes" - icon_state = "crystal-eyes" - organ_tag = "luminescent eyes" - light_color = "#1C1C00" - parent_organ = "head" - - New() - set_light(2) - -/obj/item/organ/brain/crystal - name = "crystalized brain" - icon_state = "crystal-brain" - organ_tag = "crystalized brain" \ No newline at end of file diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index fdccbd826a7..92af27ee01a 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -7,6 +7,10 @@ max_damage = 0 dir = SOUTH organ_tag = "limb" + + var/brute_mod = 1 + var/burn_mod = 1 + var/icon_name = null var/body_part = null var/icon_position = 0 @@ -102,6 +106,7 @@ /obj/item/organ/external/replaced(var/mob/living/carbon/human/target) owner = target + status = status & ~ORGAN_DESTROYED if(istype(owner)) owner.organs_by_name[limb_name] = src owner.organs |= src @@ -115,6 +120,12 @@ if(!parent.children) parent.children = list() parent.children.Add(src) + +/obj/item/organ/external/robotize() + ..() + //robot limbs take reduced damage + brute_mod = 0.66 + burn_mod = 0.66 /**************************************************** DAMAGE PROCS @@ -126,22 +137,12 @@ if(status & ORGAN_DESTROYED) return 0 - if(status & ORGAN_ROBOT ) - - var/brmod = 0.66 - var/bumod = 0.66 - - if(istype(owner,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = owner - if(H.species && H.species.flags & IS_SYNTHETIC) // No need for this - the modifer is being applied in the species' code already. Leaving it in, in case it ever changes. - brmod = 1 //H.species.brute_mod - bumod = 1 //H.species.burn_mod - - brute *= brmod //~2/3 damage for ROBOLIMBS - burn *= bumod //~2/3 damage for ROBOLIMBS + + brute *= brute_mod + burn *= burn_mod // High brute damage or sharp objects may damage internal organs - if(internal_organs && ((brute_dam >= max_damage) || (sharp && brute >= 5) || brute >= 10) && prob(5)) + if(internal_organs && (brute_dam >= max_damage || (((sharp && brute >= 5) || brute >= 10) && prob(5)))) // Damage an internal organ if(internal_organs && internal_organs.len) var/obj/item/organ/I = pick(internal_organs) @@ -301,12 +302,16 @@ This function completely restores a damaged organ to perfect condition. var/datum/wound/W = pick(compatible_wounds) W.open_wound(damage) if(prob(25)) - //maybe have a separate message for BRUISE type damage? - owner.visible_message("\red The wound on [owner.name]'s [name] widens with a nasty ripping voice.",\ - "\red The wound on your [name] widens with a nasty ripping voice.",\ - "You hear a nasty ripping noise, as if flesh is being torn apart.") + if(status & ORGAN_ROBOT) + owner.visible_message("The damage to [owner.name]'s [name] worsens.",\ + "The damage to your [name] worsens.",\ + "You hear the screech of abused metal.") + else + owner.visible_message("The wound on [owner.name]'s [name] widens with a nasty ripping noise.",\ + "The wound on your [name] widens with a nasty ripping noise.",\ + "You hear a nasty ripping noise, as if flesh is being torn apart.") return - + //Creating wound var/wound_type = get_wound_type(type, damage) @@ -329,7 +334,7 @@ This function completely restores a damaged organ to perfect condition. //Determines if we even need to process this organ. /obj/item/organ/external/proc/need_process() - if(status && status != ORGAN_ROBOT) // If it's robotic, that's fine it will have a status. + if(status & (ORGAN_CUT_AWAY|ORGAN_GAUZED|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_DESTROYED|ORGAN_SPLINTED|ORGAN_DEAD|ORGAN_MUTATED)) return 1 if(brute_dam || burn_dam) return 1 @@ -344,11 +349,6 @@ This function completely restores a damaged organ to perfect condition. /obj/item/organ/external/process() if(owner) - //Dismemberment - if(status & ORGAN_DESTROYED) - if(config.limbs_can_break) - droplimb(0,DROPLIMB_EDGE) //Might be worth removing this check since take_damage handles it. - return if(parent) if(parent.status & ORGAN_DESTROYED) status |= ORGAN_DESTROYED @@ -366,10 +366,6 @@ This function completely restores a damaged organ to perfect condition. if(trace_chemicals[chemID] <= 0) trace_chemicals.Remove(chemID) - //Bone fractures - if(config.bones_can_break && brute_dam > min_broken_damage * config.organ_health_multiplier && !(status & ORGAN_ROBOT)) - src.fracture() - if(!(status & ORGAN_BROKEN)) perma_injury = 0 @@ -537,6 +533,11 @@ Note that amputating the affected organ does in fact remove the infection from t burn_dam = 0 status &= ~ORGAN_BLEEDING var/clamped = 0 + + var/mob/living/carbon/human/H + if(istype(owner,/mob/living/carbon/human)) + H = owner + for(var/datum/wound/W in wounds) if(W.damage_type == CUT || W.damage_type == BRUISE) brute_dam += W.damage @@ -551,9 +552,12 @@ Note that amputating the affected organ does in fact remove the infection from t number_wounds += W.amount - if (open && !clamped) //things tend to bleed if they are CUT OPEN + if (open && !clamped && (H && !(H.species.flags & NO_BLOOD))) status |= ORGAN_BLEEDING - + + //Bone fractures + if(config.bones_can_break && brute_dam > min_broken_damage * config.organ_health_multiplier && !(status & ORGAN_ROBOT)) + src.fracture() // new damage icon system // returns just the brute/burn damage code @@ -599,10 +603,24 @@ Note that amputating the affected organ does in fact remove the infection from t switch(disintegrate) if(DROPLIMB_EDGE) if(!clean) + var/gore_sound = "[(status & ORGAN_ROBOT) ? "tortured metal" : "ripping tendons and flesh"]" owner.visible_message( "\The [owner]'s [src.name] flies off in an arc!",\ "Your [src.name] goes flying off!",\ - "You hear a terrible sound of ripping tendons and flesh.") + "You hear a terrible sound of [gore_sound].") + if(DROPLIMB_BURN) + var/gore = "[(status & ORGAN_ROBOT) ? "": " of burning flesh"]" + owner.visible_message( + "\The [owner]'s [src.name] flashes away into ashes!",\ + "Your [src.name] flashes away into ashes!",\ + "You hear a crackling sound[gore].") + if(DROPLIMB_BLUNT) + var/gore = "[(status & ORGAN_ROBOT) ? "": " in shower of gore"]" + var/gore_sound = "[(status & ORGAN_ROBOT) ? "rending sound of tortured metal" : "sickening splatter of gore"]" + owner.visible_message( + "\The [owner]'s [src.name] explodes[gore]!",\ + "Your [src.name] explodes[gore]!",\ + "You hear the [gore_sound].") var/mob/living/carbon/human/victim = owner //Keep a reference for post-removed(). removed(null, ignore_children) @@ -610,17 +628,15 @@ Note that amputating the affected organ does in fact remove the infection from t wounds.Cut() if(parent && !nodamage) - var/datum/wound/W - if(clean || max_damage < 50) - W = new/datum/wound/lost_limb/small(max_damage) - else - W = new/datum/wound/lost_limb(max_damage) + var/datum/wound/lost_limb/W = new (src, disintegrate, clean) parent.children -= src if(clean) parent.wounds |= W parent.update_damages() else var/obj/item/organ/external/stump/stump = new (victim, 0, src) + if(status & ORGAN_ROBOT) + stump.robotize() stump.wounds |= W victim.organs |= stump stump.update_damages() @@ -705,15 +721,18 @@ Note that amputating the affected organ does in fact remove the infection from t return rval /obj/item/organ/external/proc/fracture() + if(status & ORGAN_ROBOT) + return //ORGAN_BROKEN doesn't have the same meaning for robot limbs + if((status & ORGAN_BROKEN) || cannot_break) return - owner.visible_message(\ - "\red You hear a loud cracking sound coming from \the [owner].",\ - "\red Something feels like it shattered in your [name]!",\ - "You hear a sickening crack.") - - if(owner.species && !(owner.species.flags & NO_PAIN)) - owner.emote("scream") + if(owner) + owner.visible_message(\ + "\red You hear a loud cracking sound coming from \the [owner].",\ + "\red Something feels like it shattered in your [name]!",\ + "You hear a sickening crack.") + if(owner.species && !(owner.species.flags & NO_PAIN)) + owner.emote("scream") status |= ORGAN_BROKEN broken_description = pick("broken","fracture","hairline fracture") @@ -751,11 +770,11 @@ Note that amputating the affected organ does in fact remove the infection from t /obj/item/organ/external/proc/mutate() src.status |= ORGAN_MUTATED - owner.update_body() + if(owner) owner.update_body() /obj/item/organ/external/proc/unmutate() src.status &= ~ORGAN_MUTATED - owner.update_body() + if(owner) owner.update_body() /obj/item/organ/external/proc/get_damage() //returns total damage return max(brute_dam + burn_dam - perma_injury, perma_injury) //could use health? @@ -767,13 +786,15 @@ Note that amputating the affected organ does in fact remove the infection from t return 0 /obj/item/organ/external/proc/is_usable() + if((status & ORGAN_ROBOT) && get_damage() >= max_damage) //robot limbs just become inoperable at max damage + return return !(status & (ORGAN_DESTROYED|ORGAN_MUTATED|ORGAN_DEAD)) /obj/item/organ/external/proc/is_malfunctioning() return ((status & ORGAN_ROBOT) && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam)) /obj/item/organ/external/proc/embed(var/obj/item/weapon/W, var/silent = 0) - if(loc != owner) + if(!owner || loc != owner) return if(!silent) owner.visible_message("\The [W] sticks in the wound!") @@ -806,12 +827,12 @@ Note that amputating the affected organ does in fact remove the infection from t for(var/obj/item/organ/external/O in children) O.removed() if(O) - O.loc = src + O.forceMove(src) // Grab all the internal giblets too. for(var/obj/item/organ/organ in internal_organs) organ.removed() - organ.loc = src + organ.forceMove(src) release_restraints(victim) victim.organs -= src @@ -845,153 +866,3 @@ Note that amputating the affected organ does in fact remove the infection from t "\red Your [name] melts away!", \ "\red You hear a sickening sizzle.") disfigured = 1 - -/**************************************************** - ORGAN DEFINES -****************************************************/ - -/obj/item/organ/external/chest - name = "upper body" - limb_name = "chest" - icon_name = "torso" - max_damage = 100 - min_broken_damage = 50 - body_part = UPPER_TORSO - vital = 1 - amputation_point = "spine" - gendered_icon = 1 - cannot_amputate = 1 - parent_organ = null - encased = "ribcage" - -/obj/item/organ/external/groin - name = "lower body" - limb_name = "groin" - icon_name = "groin" - max_damage = 100 - min_broken_damage = 50 - body_part = LOWER_TORSO - vital = 1 - parent_organ = "chest" - amputation_point = "lumbar" - gendered_icon = 1 - -/obj/item/organ/external/arm - limb_name = "l_arm" - name = "left arm" - icon_name = "l_arm" - max_damage = 60 - min_broken_damage = 30 - body_part = ARM_LEFT - parent_organ = "chest" - amputation_point = "left shoulder" - can_grasp = 1 - -/obj/item/organ/external/arm/right - limb_name = "r_arm" - name = "right arm" - icon_name = "r_arm" - body_part = ARM_RIGHT - amputation_point = "right shoulder" - -/obj/item/organ/external/leg - limb_name = "l_leg" - name = "left leg" - icon_name = "l_leg" - max_damage = 60 - min_broken_damage = 30 - body_part = LEG_LEFT - icon_position = LEFT - parent_organ = "groin" - amputation_point = "left hip" - can_stand = 1 - -/obj/item/organ/external/leg/right - limb_name = "r_leg" - name = "right leg" - icon_name = "r_leg" - body_part = LEG_RIGHT - icon_position = RIGHT - amputation_point = "right hip" - -/obj/item/organ/external/foot - limb_name = "l_foot" - name = "left foot" - icon_name = "l_foot" - max_damage = 30 - min_broken_damage = 15 - body_part = FOOT_LEFT - icon_position = LEFT - parent_organ = "l_leg" - amputation_point = "left ankle" - can_stand = 1 - -/obj/item/organ/external/foot/removed() - if(owner) owner.unEquip(owner.shoes) - ..() - -/obj/item/organ/external/foot/right - limb_name = "r_foot" - name = "right foot" - icon_name = "r_foot" - body_part = FOOT_RIGHT - icon_position = RIGHT - parent_organ = "r_leg" - amputation_point = "right ankle" - -/obj/item/organ/external/hand - limb_name = "l_hand" - name = "left hand" - icon_name = "l_hand" - max_damage = 30 - min_broken_damage = 15 - body_part = HAND_LEFT - parent_organ = "l_arm" - amputation_point = "left wrist" - can_grasp = 1 - -/obj/item/organ/external/hand/removed() - if(owner) owner.unEquip(owner.gloves) - ..() - -/obj/item/organ/external/hand/right - limb_name = "r_hand" - name = "right hand" - icon_name = "r_hand" - body_part = HAND_RIGHT - parent_organ = "r_arm" - amputation_point = "right wrist" - -/obj/item/organ/external/head - limb_name = "head" - icon_name = "head" - name = "head" - max_damage = 70 - min_broken_damage = 35 - body_part = HEAD - vital = 1 - parent_organ = "chest" - amputation_point = "neck" - gendered_icon = 1 - encased = "skull" - -/obj/item/organ/external/head/removed() - if(owner) - name = "[owner.real_name]'s head" - owner.unEquip(owner.glasses) - owner.unEquip(owner.head) - owner.unEquip(owner.l_ear) - owner.unEquip(owner.r_ear) - owner.unEquip(owner.wear_mask) - spawn(1) - owner.update_hair() - ..() - -/obj/item/organ/external/head/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list()) - ..(brute, burn, sharp, edge, used_weapon, forbidden_limbs) - if (!disfigured) - if (brute_dam > 40) - if (prob(50)) - disfigure("brute") - if (burn_dam > 40) - disfigure("burn") diff --git a/code/modules/organs/organ_icon.dm b/code/modules/organs/organ_icon.dm index f025e9adcd8..26ca1f5079a 100644 --- a/code/modules/organs/organ_icon.dm +++ b/code/modules/organs/organ_icon.dm @@ -87,7 +87,7 @@ var/global/list/limb_icon_cache = list() if(skeletal) mob_icon = new /icon('icons/mob/human_races/r_skeleton.dmi', "[icon_name][gender ? "_[gender]" : ""]") - else if ((status & ORGAN_ROBOT) && !(owner.species && owner.species.flags & IS_SYNTHETIC)) + else if (status & ORGAN_ROBOT) mob_icon = new /icon('icons/mob/human_races/robotic.dmi', "[icon_name][gender ? "_[gender]" : ""]") else if (status & ORGAN_MUTATED) diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index b1b3fcbc0a5..5438fdd3ec3 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -81,17 +81,6 @@ owner.b_eyes ? owner.b_eyes : 0 ) - -/obj/item/organ/eyes/process() //Eye damage replaces the old eye_stat var. - ..() - if(!owner) - return - if(is_bruised()) - owner.eye_blurry = 20 - if(is_broken()) - owner.eye_blind = 20 - - /obj/item/organ/liver name = "liver" icon_state = "liver" diff --git a/code/modules/organs/organ_stump.dm b/code/modules/organs/organ_stump.dm index 545ca746275..1f9cdb1217b 100644 --- a/code/modules/organs/organ_stump.dm +++ b/code/modules/organs/organ_stump.dm @@ -1,7 +1,6 @@ /obj/item/organ/external/stump name = "limb stump" icon_name = "" - cannot_amputate = 0 //You need to remove stumps to attach new limbs, but you can't remove stumps... What the fuck? /obj/item/organ/external/stump/New(var/mob/living/carbon/holder, var/internal, var/obj/item/organ/external/limb) if(istype(limb)) @@ -13,6 +12,8 @@ ..(holder, internal) if(istype(limb)) max_damage = limb.max_damage + if((limb.status & ORGAN_ROBOT) && (!parent || (parent.status & ORGAN_ROBOT))) + robotize() //if both limb and the parent are robotic, the stump is robotic too /obj/item/organ/external/stump/is_stump() return 1 @@ -20,3 +21,6 @@ /obj/item/organ/external/stump/removed() ..() qdel(src) + +/obj/item/organ/external/stump/is_usable() + return 0 \ No newline at end of file diff --git a/code/modules/organs/pain.dm b/code/modules/organs/pain.dm index d48592f64d9..bd9e9a9694a 100644 --- a/code/modules/organs/pain.dm +++ b/code/modules/organs/pain.dm @@ -78,8 +78,8 @@ mob/living/carbon/human/proc/handle_pain() // not when sleeping if(species && species.flags & NO_PAIN) - //While IPCs don't feel pain, they will notice their gears gunking up with residue (toxins) - if(species && species.flags & IS_SYNTHETIC) + //While synthetics don't feel pain, they will notice their gears gunking up with residue (toxins) + if(isSynthetic()) var/toxDamageMessage = null var/toxMessageProb = 1 switch(getToxLoss()) diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm index 8d19d60b491..fc4151e4fef 100644 --- a/code/modules/organs/robolimbs.dm +++ b/code/modules/organs/robolimbs.dm @@ -35,3 +35,9 @@ var/global/datum/robolimb/basic_robolimb company = "Xion Manufacturing Group" desc = "This limb has a minimalist black and red casing." icon = 'icons/mob/human_races/cyberlimbs/xion.dmi' + +/datum/robolimb/ipc + company = "Morpheus Cyberkinetics" + desc = "This limb is simple and functional; no effort has been made to make it look human." + icon = 'icons/mob/human_races/cyberlimbs/ipc.dmi' + unavailable_at_chargen = 1 diff --git a/code/modules/organs/subtypes/diona.dm b/code/modules/organs/subtypes/diona.dm new file mode 100644 index 00000000000..735b5120582 --- /dev/null +++ b/code/modules/organs/subtypes/diona.dm @@ -0,0 +1,207 @@ +/*/proc/spawn_diona_nymph_from_organ(var/obj/item/organ/organ) + if(!istype(organ)) + return 0 + + //This is a terrible hack and I should be ashamed. + var/datum/seed/diona = plant_controller.seeds["diona"] + if(!diona) + return 0 + + spawn(1) // So it has time to be thrown about by the gib() proc. + var/mob/living/simple_animal/diona/D = new(get_turf(organ)) + var/datum/ghosttrap/plant/P = get_ghost_trap("living plant") + P.request_player(D, "A diona nymph has split off from its gestalt. ") + spawn(60) + if(D) + if(!D.ckey || !D.client) + D.death() + return 1 */ + +/obj/item/organ/external/diona + name = "tendril" + cannot_break = 1 + amputation_point = "branch" + +/obj/item/organ/external/diona/chest + name = "core trunk" + limb_name = "chest" + icon_name = "torso" + max_damage = 200 + min_broken_damage = 50 + w_class = 5 + body_part = UPPER_TORSO + vital = 1 + cannot_amputate = 1 + parent_organ = null + +/obj/item/organ/external/diona/groin + name = "fork" + limb_name = "groin" + icon_name = "groin" + max_damage = 100 + min_broken_damage = 50 + w_class = 4 + body_part = LOWER_TORSO + parent_organ = "chest" + +/obj/item/organ/external/diona/arm + name = "left upper tendril" + limb_name = "l_arm" + icon_name = "l_arm" + max_damage = 35 + min_broken_damage = 20 + w_class = 3 + body_part = ARM_LEFT + parent_organ = "chest" + can_grasp = 1 + +/obj/item/organ/external/diona/arm/right + name = "right upper tendril" + limb_name = "r_arm" + icon_name = "r_arm" + body_part = ARM_RIGHT + +/obj/item/organ/external/diona/leg + name = "left lower tendril" + limb_name = "l_leg" + icon_name = "l_leg" + max_damage = 35 + min_broken_damage = 20 + w_class = 3 + body_part = LEG_LEFT + icon_position = LEFT + parent_organ = "groin" + can_stand = 1 + +/obj/item/organ/external/diona/leg/right + name = "right lower tendril" + limb_name = "r_leg" + icon_name = "r_leg" + body_part = LEG_RIGHT + icon_position = RIGHT + +/obj/item/organ/external/diona/foot + name = "left foot" + limb_name = "l_foot" + icon_name = "l_foot" + max_damage = 20 + min_broken_damage = 10 + w_class = 2 + body_part = FOOT_LEFT + icon_position = LEFT + parent_organ = "l_leg" + can_stand = 1 + +/obj/item/organ/external/diona/foot/right + name = "right foot" + limb_name = "r_foot" + icon_name = "r_foot" + body_part = FOOT_RIGHT + icon_position = RIGHT + parent_organ = "r_leg" + amputation_point = "right ankle" + +/obj/item/organ/external/diona/hand + name = "left grasper" + limb_name = "l_hand" + icon_name = "l_hand" + max_damage = 30 + min_broken_damage = 15 + w_class = 2 + body_part = HAND_LEFT + parent_organ = "l_arm" + can_grasp = 1 + +/obj/item/organ/external/diona/hand/right + name = "right grasper" + limb_name = "r_hand" + icon_name = "r_hand" + body_part = HAND_RIGHT + parent_organ = "r_arm" + +/obj/item/organ/external/diona/head + limb_name = "head" + icon_name = "head" + name = "head" + max_damage = 50 + min_broken_damage = 25 + vital = 1 + w_class = 3 + body_part = HEAD + parent_organ = "chest" + +/obj/item/organ/external/diona/head/removed() + if(owner) + owner.unEquip(owner.head) + owner.unEquip(owner.l_ear) + ..() + +//DIONA ORGANS. +/* /obj/item/organ/external/diona/removed() + var/mob/living/carbon/human/H = owner + ..() + if(!istype(H) || !H.organs || !H.organs.len) + H.death() + if(prob(50) && spawn_diona_nymph_from_organ(src)) + qdel(src) */ + +/obj/item/organ/diona/process() + return + +/obj/item/organ/diona/strata + name = "neural strata" + parent_organ = "chest" + +/obj/item/organ/diona/bladder + name = "gas bladder" + parent_organ = "head" + +/obj/item/organ/diona/polyp + name = "polyp segment" + parent_organ = "groin" + +/obj/item/organ/diona/ligament + name = "anchoring ligament" + parent_organ = "groin" + +/obj/item/organ/diona/node + name = "receptor node" + parent_organ = "head" + +/obj/item/organ/diona/nutrients + name = "nutrient vessel" + parent_organ = "chest" + +/obj/item/organ/diona + name = "diona nymph" + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + organ_tag = "special" // Turns into a nymph instantly, no transplanting possible. + +/*/obj/item/organ/diona/removed(var/mob/living/user) + var/mob/living/carbon/human/H = owner + ..() + if(!istype(H) || !H.organs || !H.organs.len) + H.death() + if(prob(50) && spawn_diona_nymph_from_organ(src)) + qdel(src) */ + +// These are different to the standard diona organs as they have a purpose in other +// species (absorbing radiation and light respectively) +/obj/item/organ/diona/nutrients + name = "nutrient vessel" + organ_tag = "nutrient vessel" + icon = 'icons/mob/alien.dmi' + icon_state = "claw" + +/obj/item/organ/diona/nutrients/removed() + return + +/obj/item/organ/diona/node + name = "receptor node" + organ_tag = "receptor node" + icon = 'icons/mob/alien.dmi' + icon_state = "claw" + +/obj/item/organ/diona/node/removed() + return diff --git a/code/modules/organs/subtypes/machine.dm b/code/modules/organs/subtypes/machine.dm new file mode 100644 index 00000000000..ee71bb59d21 --- /dev/null +++ b/code/modules/organs/subtypes/machine.dm @@ -0,0 +1,138 @@ +// IPC limbs. +/obj/item/organ/external/head/ipc + can_intake_reagents = 0 + vital = 0 + max_damage = 50 //made same as arm, since it is not vital + min_broken_damage = 30 + encased = null + +/obj/item/organ/external/head/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/external/chest/ipc + encased = null + +/obj/item/organ/external/chest/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/external/groin/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/external/arm/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/external/arm/right/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/external/leg/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/external/leg/right/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/external/foot/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/external/foot/right/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/external/hand/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/external/hand/right/ipc/New() + robotize("Morpheus Cyberkinetics") + ..() + +/obj/item/organ/cell + name = "microbattery" + desc = "A small, powerful cell for use in fully prosthetic bodies." + icon = 'icons/obj/power.dmi' + icon_state = "scell" + organ_tag = "cell" + parent_organ = "chest" + vital = 1 + +/obj/item/organ/cell/New() + robotize() + ..() + +/obj/item/organ/cell/replaced() + ..() + // This is very ghetto way of rebooting an IPC. TODO better way. + if(owner && owner.stat == DEAD) + owner.stat = CONSCIOUS + owner.visible_message("\The [owner] twitches visibly!") + +/obj/item/organ/optical_sensor + name = "optical sensor" + organ_tag = "optics" + parent_organ = "head" + icon = 'icons/obj/robot_component.dmi' + icon_state = "camera" + dead_icon = "camera_broken" + +/obj/item/organ/optical_sensor/New() + robotize() + ..() + +// Used for an MMI or posibrain being installed into a human. +/obj/item/organ/mmi_holder + name = "brain" + organ_tag = "brain" + parent_organ = "chest" + vital = 1 + var/obj/item/device/mmi/stored_mmi + +/obj/item/organ/mmi_holder/proc/update_from_mmi() + if(!stored_mmi) + return + name = stored_mmi.name + desc = stored_mmi.desc + icon = stored_mmi.icon + icon_state = stored_mmi.icon_state + +/obj/item/organ/mmi_holder/removed(var/mob/living/user) + + if(stored_mmi) + stored_mmi.loc = get_turf(src) + if(owner.mind) + owner.mind.transfer_to(stored_mmi.brainmob) + ..() + + var/mob/living/holder_mob = loc + if(istype(holder_mob)) + holder_mob.unEquip(src) + qdel(src) + +/obj/item/organ/mmi_holder/New() + ..() + // This is very ghetto way of rebooting an IPC. TODO better way. + spawn(1) + if(owner && owner.stat == DEAD) + owner.stat = 0 + owner.visible_message("\The [owner] twitches visibly!") + +/obj/item/organ/mmi_holder/posibrain/New() + robotize() + stored_mmi = new /obj/item/device/mmi/posibrain(src) + ..() + spawn(1) + if(owner) + stored_mmi.name = "positronic brain ([owner.name])" + stored_mmi.brainmob.real_name = owner.name + stored_mmi.brainmob.name = stored_mmi.brainmob.real_name + stored_mmi.icon_state = "posibrain-occupied" + update_from_mmi() + else + stored_mmi.loc = get_turf(src) + qdel(src) \ No newline at end of file diff --git a/code/modules/organs/subtypes/misc.dm b/code/modules/organs/subtypes/misc.dm new file mode 100644 index 00000000000..a2febc6d1e4 --- /dev/null +++ b/code/modules/organs/subtypes/misc.dm @@ -0,0 +1,67 @@ +//CORTICAL BORER ORGANS. +/obj/item/organ/borer + name = "cortical borer" + parent_organ = "head" + vital = 1 + +/obj/item/organ/borer/process() + + // Borer husks regenerate health, feel no pain, and are resistant to stuns and brainloss. + for(var/chem in list("saline", "sailcylic", "meth", "mannitol")) + if(owner.reagents.get_reagent_amount(chem) < 3) + owner.reagents.add_reagent(chem, 5) + + // They're also super gross and ooze ichor. + if(prob(5)) + var/mob/living/carbon/human/H = owner + if(!istype(H)) + return + + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in H.vessel.reagent_list + blood_splatter(H,B,1) + var/obj/effect/decal/cleanable/blood/splatter/goo = locate() in get_turf(owner) + if(goo) + goo.name = "husk ichor" + goo.desc = "It's thick and stinks of decay." + goo.basecolor = "#412464" + goo.update_icon() + +/obj/item/organ/borer + name = "cortical borer" + icon = 'icons/obj/objects.dmi' + icon_state = "borer" + organ_tag = "brain" + desc = "A disgusting space slug." + +/obj/item/organ/borer/removed(var/mob/living/user) + + ..() + + var/mob/living/simple_animal/borer/B = owner.has_brain_worms() + if(B) + B.leave_host() + B.ckey = owner.ckey + + spawn(0) + qdel(src) + +//VOX ORGANS. +/obj/item/organ/stack + name = "cortical stack" + icon_state = "brain-prosthetic" + parent_organ = "head" + organ_tag = "stack" + robotic = 2 + vital = 1 + var/backup_time = 0 + var/datum/mind/backup + +/obj/item/organ/stack/process() + if(owner && owner.stat != 2 && !is_broken()) + backup_time = world.time + if(owner.mind) backup = owner.mind + +/obj/item/organ/stack/vox + name = "vox cortical stack" + +/obj/item/organ/stack/vox/stack diff --git a/code/modules/organs/subtypes/nucleation.dm b/code/modules/organs/subtypes/nucleation.dm new file mode 100644 index 00000000000..40d7745d86e --- /dev/null +++ b/code/modules/organs/subtypes/nucleation.dm @@ -0,0 +1,33 @@ +//NUCLEATION ORGAN +/obj/item/organ/nucleation + name = "nucleation organ" + icon = 'icons/obj/surgery.dmi' + desc = "A crystalized human organ. /red It has a strangely iridescent glow." + +/obj/item/organ/nucleation/resonant_crystal + name = "resonant crystal" + icon_state = "resonant-crystal" + organ_tag = "resonant crystal" + parent_organ = "head" + +/obj/item/organ/nucleation/strange_crystal + name = "strange crystal" + icon_state = "strange-crystal" + organ_tag = "strange crystal" + parent_organ = "chest" + +/obj/item/organ/eyes/luminescent_crystal + name = "luminescent eyes" + icon_state = "crystal-eyes" + organ_tag = "luminescent eyes" + light_color = "#1C1C00" + parent_organ = "head" + + New() + set_light(2) + +/obj/item/organ/brain/crystal + name = "crystalized brain" + icon_state = "crystal-brain" + organ_tag = "crystalized brain" + \ No newline at end of file diff --git a/code/modules/organs/subtypes/standard.dm b/code/modules/organs/subtypes/standard.dm new file mode 100644 index 00000000000..6663f833bef --- /dev/null +++ b/code/modules/organs/subtypes/standard.dm @@ -0,0 +1,157 @@ +/**************************************************** + ORGAN DEFINES +****************************************************/ + +/obj/item/organ/external/chest + name = "upper body" + limb_name = "chest" + icon_name = "torso" + max_damage = 100 + min_broken_damage = 35 + w_class = 5 + body_part = UPPER_TORSO + vital = 1 + amputation_point = "spine" + gendered_icon = 1 + cannot_amputate = 1 + parent_organ = null + encased = "ribcage" + +/obj/item/organ/external/groin + name = "lower body" + limb_name = "groin" + icon_name = "groin" + max_damage = 100 + min_broken_damage = 35 + w_class = 4 + body_part = LOWER_TORSO + vital = 1 + parent_organ = "chest" + amputation_point = "lumbar" + gendered_icon = 1 + +/obj/item/organ/external/arm + limb_name = "l_arm" + name = "left arm" + icon_name = "l_arm" + max_damage = 50 + min_broken_damage = 30 + w_class = 3 + body_part = ARM_LEFT + parent_organ = "chest" + amputation_point = "left shoulder" + can_grasp = 1 + +/obj/item/organ/external/arm/right + limb_name = "r_arm" + name = "right arm" + icon_name = "r_arm" + body_part = ARM_RIGHT + amputation_point = "right shoulder" + +/obj/item/organ/external/leg + limb_name = "l_leg" + name = "left leg" + icon_name = "l_leg" + max_damage = 50 + min_broken_damage = 30 + w_class = 3 + body_part = LEG_LEFT + icon_position = LEFT + parent_organ = "groin" + amputation_point = "left hip" + can_stand = 1 + +/obj/item/organ/external/leg/right + limb_name = "r_leg" + name = "right leg" + icon_name = "r_leg" + body_part = LEG_RIGHT + icon_position = RIGHT + amputation_point = "right hip" + +/obj/item/organ/external/foot + limb_name = "l_foot" + name = "left foot" + icon_name = "l_foot" + max_damage = 30 + min_broken_damage = 15 + w_class = 2 + body_part = FOOT_LEFT + icon_position = LEFT + parent_organ = "l_leg" + amputation_point = "left ankle" + can_stand = 1 + +/obj/item/organ/external/foot/removed() + if(owner) owner.unEquip(owner.shoes) + ..() + +/obj/item/organ/external/foot/right + limb_name = "r_foot" + name = "right foot" + icon_name = "r_foot" + body_part = FOOT_RIGHT + icon_position = RIGHT + parent_organ = "r_leg" + amputation_point = "right ankle" + +/obj/item/organ/external/hand + limb_name = "l_hand" + name = "left hand" + icon_name = "l_hand" + max_damage = 30 + min_broken_damage = 15 + w_class = 2 + body_part = HAND_LEFT + parent_organ = "l_arm" + amputation_point = "left wrist" + can_grasp = 1 + +/obj/item/organ/external/hand/removed() + owner.unEquip(owner.gloves) + ..() + +/obj/item/organ/external/hand/right + limb_name = "r_hand" + name = "right hand" + icon_name = "r_hand" + body_part = HAND_RIGHT + parent_organ = "r_arm" + amputation_point = "right wrist" + +/obj/item/organ/external/head + limb_name = "head" + icon_name = "head" + name = "head" + max_damage = 75 + min_broken_damage = 35 + w_class = 3 + body_part = HEAD + vital = 1 + parent_organ = "chest" + amputation_point = "neck" + gendered_icon = 1 + encased = "skull" + var/can_intake_reagents = 1 + +/obj/item/organ/external/head/removed() + if(owner) + name = "[owner.real_name]'s head" + owner.unEquip(owner.glasses) + owner.unEquip(owner.head) + owner.unEquip(owner.l_ear) + owner.unEquip(owner.r_ear) + owner.unEquip(owner.wear_mask) + spawn(1) + owner.update_hair() + ..() + +/obj/item/organ/external/head/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list()) + ..(brute, burn, sharp, edge, used_weapon, forbidden_limbs) + if (!disfigured) + if (brute_dam > 40) + if (prob(50)) + disfigure("brute") + if (burn_dam > 40) + disfigure("burn") diff --git a/code/modules/organs/subtypes/unbreakable.dm b/code/modules/organs/subtypes/unbreakable.dm new file mode 100644 index 00000000000..74dc1ae3de7 --- /dev/null +++ b/code/modules/organs/subtypes/unbreakable.dm @@ -0,0 +1,34 @@ +// Slime limbs. +/obj/item/organ/external/chest/unbreakable + cannot_break = 1 + +/obj/item/organ/external/groin/unbreakable + cannot_break = 1 + +/obj/item/organ/external/arm/unbreakable + cannot_break = 1 + +/obj/item/organ/external/arm/right/unbreakable + cannot_break = 1 + +/obj/item/organ/external/leg/unbreakable + cannot_break = 1 + +/obj/item/organ/external/leg/right/unbreakable + cannot_break = 1 + +/obj/item/organ/external/foot/unbreakable + cannot_break = 1 + +/obj/item/organ/external/foot/right/unbreakable + cannot_break = 1 + +/obj/item/organ/external/hand/unbreakable + cannot_break = 1 + +/obj/item/organ/external/hand/right/unbreakable + cannot_break = 1 + +/obj/item/organ/external/head/unbreakable + cannot_break = 1 + diff --git a/code/modules/organs/subtypes/wryn.dm b/code/modules/organs/subtypes/wryn.dm new file mode 100644 index 00000000000..5d0c687f9f2 --- /dev/null +++ b/code/modules/organs/subtypes/wryn.dm @@ -0,0 +1,11 @@ +//WRYN ORGAN +/obj/item/organ/wryn/hivenode + name = "antennae" + parent_organ = "head" + +/obj/item/organ/wryn/hivenode + name = "antennae" + organ_tag = "antennae" + icon = 'icons/mob/human_races/r_wryn.dmi' + icon_state = "antennae" + \ No newline at end of file diff --git a/code/modules/organs/subtypes/xenos.dm b/code/modules/organs/subtypes/xenos.dm new file mode 100644 index 00000000000..7052237b163 --- /dev/null +++ b/code/modules/organs/subtypes/xenos.dm @@ -0,0 +1,66 @@ +//XENOMORPH ORGANS +/obj/item/organ/xenos/eggsac + name = "egg sac" + parent_organ = "groin" + +/obj/item/organ/xenos/plasmavessel + name = "plasma vessel" + parent_organ = "chest" + var/stored_plasma = 0 + var/max_plasma = 500 + +/obj/item/organ/xenos/plasmavessel/queen + name = "bloated plasma vessel" + stored_plasma = 200 + max_plasma = 500 + +/obj/item/organ/xenos/plasmavessel/sentinel + stored_plasma = 100 + max_plasma = 250 + +/obj/item/organ/xenos/plasmavessel/hunter + name = "tiny plasma vessel" + stored_plasma = 100 + max_plasma = 150 + +/obj/item/organ/xenos/acidgland + name = "acid gland" + parent_organ = "head" + +/obj/item/organ/xenos/hivenode + name = "hive node" + parent_organ = "chest" + +/obj/item/organ/xenos/resinspinner + name = "resin spinner" + parent_organ = "head" + +/obj/item/organ/xenos + name = "xeno organ" + icon = 'icons/effects/blood.dmi' + desc = "It smells like an accident in a chemical factory." + +/obj/item/organ/xenos/eggsac + name = "egg sac" + icon_state = "xgibmid1" + organ_tag = "egg sac" + +/obj/item/organ/xenos/plasmavessel + name = "plasma vessel" + icon_state = "xgibdown1" + organ_tag = "plasma vessel" + +/obj/item/organ/xenos/acidgland + name = "acid gland" + icon_state = "xgibtorso" + organ_tag = "acid gland" + +/obj/item/organ/xenos/hivenode + name = "hive node" + icon_state = "xgibmid2" + organ_tag = "hive node" + +/obj/item/organ/xenos/resinspinner + name = "hive node" + icon_state = "xgibmid2" + organ_tag = "resin spinner" \ No newline at end of file diff --git a/code/modules/organs/wound.dm b/code/modules/organs/wound.dm index bd044163ff3..55a2f3f5cee 100644 --- a/code/modules/organs/wound.dm +++ b/code/modules/organs/wound.dm @@ -36,9 +36,8 @@ var/list/stages // internal wounds can only be fixed through surgery var/internal = 0 - // maximum stage at which bleeding should still happen, counted from the right rather than the left of the list - // 1 means all stages except the last should bleed - var/max_bleeding_stage = 1 + // maximum stage at which bleeding should still happen. Beyond this stage bleeding is prevented. + var/max_bleeding_stage = 0 // one of CUT, BRUISE, BURN var/damage_type = CUT // whether this wound needs a bandage/salve to heal at all @@ -64,8 +63,6 @@ src.damage = damage - max_bleeding_stage = src.desc_list.len - max_bleeding_stage - // initialize with the appropriate stage src.init_stage(damage) @@ -247,8 +244,9 @@ /** CUTS **/ /datum/wound/cut/small - // link wound descriptions to amounts of damage - max_bleeding_stage = 2 + // Minor cuts have max_bleeding_stage set to the stage that bears the wound type's name. + // The major cut types have the max_bleeding_stage set to the clot stage (which is accordingly given the "blood soaked" descriptor). + max_bleeding_stage = 3 stages = list("ugly ripped cut" = 20, "ripped cut" = 10, "cut" = 5, "healing cut" = 2, "small scab" = 0) damage_type = CUT @@ -263,25 +261,25 @@ damage_type = CUT /datum/wound/cut/gaping - max_bleeding_stage = 2 - stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "large clot" = 15, "small angry scar" = 5, "small straight scar" = 0) + max_bleeding_stage = 3 + stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "blood soaked clot" = 15, "small angry scar" = 5, "small straight scar" = 0) damage_type = CUT /datum/wound/cut/gaping_big - max_bleeding_stage = 2 - stages = list("big gaping wound" = 60, "healing gaping wound" = 40, "large angry scar" = 10, "large straight scar" = 0) + max_bleeding_stage = 3 + stages = list("big gaping wound" = 60, "healing gaping wound" = 40, "large blood soaked clot" = 25, "large angry scar" = 10, "large straight scar" = 0) damage_type = CUT datum/wound/cut/massive - max_bleeding_stage = 2 - stages = list("massive wound" = 70, "massive healing wound" = 50, "massive angry scar" = 10, "massive jagged scar" = 0) + max_bleeding_stage = 3 + stages = list("massive wound" = 70, "massive healing wound" = 50, "massive blood soaked clot" = 25, "massive angry scar" = 10, "massive jagged scar" = 0) damage_type = CUT /** BRUISES **/ /datum/wound/bruise - stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30,\ + stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30, "moderate bruise" = 20, "small bruise" = 10, "tiny bruise" = 5) - max_bleeding_stage = 3 + max_bleeding_stage = 3 //only large bruise and above can bleed. autoheal_cutoff = 30 damage_type = BRUISE @@ -309,18 +307,38 @@ datum/wound/cut/massive /** INTERNAL BLEEDING **/ /datum/wound/internal_bleeding internal = 1 - stages = list("severed vein" = 30, "cut vein" = 20, "damaged vein" = 10, "bruised vein" = 5) + stages = list("severed artery" = 30, "cut artery" = 20, "damaged artery" = 10, "bruised artery" = 5) autoheal_cutoff = 5 - max_bleeding_stage = 0 //all stages bleed. It's called internal bleeding after all. + max_bleeding_stage = 4 //all stages bleed. It's called internal bleeding after all. + /** EXTERNAL ORGAN LOSS **/ /datum/wound/lost_limb - damage_type = CUT - stages = list("ripped stump" = 65, "bloody stump" = 50, "clotted stump" = 25, "scarred stump" = 0) - max_bleeding_stage = 3 - can_merge(var/datum/wound/other) - return 0 //cannot be merged +/datum/wound/lost_limb/New(var/obj/item/organ/external/lost_limb, var/losstype, var/clean) + var/damage_amt = lost_limb.max_damage + if(clean) damage_amt /= 2 + + switch(losstype) + if(DROPLIMB_EDGE, DROPLIMB_BLUNT) + damage_type = CUT + max_bleeding_stage = 3 //clotted stump and above can bleed. + stages = list( + "ripped stump" = damage_amt*1.3, + "bloody stump" = damage_amt, + "clotted stump" = damage_amt*0.5, + "scarred stump" = 0 + ) + if(DROPLIMB_BURN) + damage_type = BURN + stages = list( + "ripped charred stump" = damage_amt*1.3, + "charred stump" = damage_amt, + "scarred stump" = damage_amt*0.5, + "scarred stump" = 0 + ) + + ..(damage_amt) -/datum/wound/lost_limb/small - stages = list("ripped hole" = 40, "bloody hole" = 30, "clotted hole" = 15, "scarred hole" = 0) +/datum/wound/lost_limb/can_merge(var/datum/wound/other) + return 0 //cannot be merged diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 211cc4cfc34..efeb2e60a30 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -333,8 +333,8 @@ for(var/bad in paper_blacklist) if(findtext(t,bad)) usr << "\blue You think to yourself, \"Hm.. this is only paper...\"" - log_admin("PAPER: [usr] ([usr.ckey]) tried to use forbidden word in [src]: [bad].") - message_admins("PAPER: [usr] ([usr.ckey]) tried to use forbidden word in [src]: [bad].") + log_admin("PAPER: [key_name(usr)] tried to use forbidden word in [src]: [bad].") + message_admins("PAPER: [key_name_admin(usr)] tried to use forbidden word in [src]: [bad].") return */ t = html_encode(t) diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 7c235022c92..07c0ea13e8d 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -641,16 +641,15 @@ //Synthetic human mob goes here. if(istype(user,/mob/living/carbon/human)) var/mob/living/carbon/human/H = user - if(H.species.flags & IS_SYNTHETIC && H.a_intent == "grab") + if(!isnull(H.internal_organs_by_name["cell"]) && H.a_intent == "grab") if(emagged || stat & BROKEN) var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(3, 1, src) s.start() - H << "The APC power currents surge eratically, damaging your chassis!" + H << "The APC power currents surge erratically, damaging your chassis!" H.adjustFireLoss(10,0) else if(src.cell && src.cell.charge > 0) if(H.nutrition < 450) - if(src.cell.charge >= 500) H.nutrition += 50 src.cell.charge -= 500 @@ -659,14 +658,15 @@ src.cell.charge = 0 user << "You slot your fingers into the APC interface and siphon off some of the stored charge for your own use." - if(src.cell.charge < 0) src.cell.charge = 0 - if(H.nutrition > 500) H.nutrition = 500 + if(src.cell.charge < 0) + src.cell.charge = 0 + if(H.nutrition > 500) + H.nutrition = 500 src.charging = 1 - else user << "You are already fully charged." else - user << "There is no charge to draw from that APC." + user << "There is no charge to draw from that APC." return if(usr == user && opened && (!issilicon(user))) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 38a1c5e927e..de6fb00c621 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -496,31 +496,29 @@ obj/structure/cable/proc/cableColor(var/colorC) /////////////////////////////////// // General procedures /////////////////////////////////// - //you can use wires to heal robotics /obj/item/stack/cable_coil/attack(mob/M as mob, mob/user as mob) - if(istype(M,/mob/living/carbon/human)) + if(ishuman(M)) var/mob/living/carbon/human/H = M - var/obj/item/organ/external/S = H.get_organ(user.zone_sel.selecting) - if(!(S.status & ORGAN_ROBOT) || user.a_intent != "help") + var/obj/item/organ/external/S = H.organs_by_name[user.zone_sel.selecting] + + if(!S) + return + if(!(S.status & ORGAN_ROBOT) || user.a_intent != "help" || S.open == 2) return ..() - if(H.species.flags & IS_SYNTHETIC) - if(M == user) - user << "\red You can't repair damage to your own body - it's against OH&S." - return - - if(S.burn_dam > 0 && use(1)) - S.heal_damage(0,15,0,1) - user.visible_message("\red \The [user] repairs some burn damage on \the [M]'s [S.name] with \the [src].") - return - else - user << "Nothing to fix!" - + if(S.burn_dam) + if(S.burn_dam < ROBOLIMB_SELF_REPAIR_CAP) + S.heal_damage(0,15,0,1) + user.visible_message("\The [user] repairs some burn damage on \the [M]'s [S.name] with \the [src].") + else if(S.open != 2) + user << "The damage is far too severe to patch over externally." + return 1 + else if(S.open != 2) + user << "Nothing to fix!" else return ..() - /obj/item/stack/cable_coil/update_icon() if (!color) color = pick(COLOR_RED, COLOR_BLUE, COLOR_GREEN, COLOR_ORANGE, COLOR_WHITE, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN) diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 795990fef40..863bdc19b32 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -215,10 +215,17 @@ var/const/GRAV_NEEDS_WRENCH = 3 /obj/machinery/gravity_generator/main/attack_hand(mob/user as mob) if(!..()) return interact(user) + +/obj/machinery/gravity_generator/main/attack_ai(mob/user as mob) + return 1 + +/obj/machinery/gravity_generator/main/attack_ghost(mob/user as mob) + return interact(user) /obj/machinery/gravity_generator/main/interact(mob/user as mob) if(stat & BROKEN) return + var/dat = "Gravity Generator Breaker: " if(breaker) dat += "ON OFF" @@ -241,9 +248,8 @@ var/const/GRAV_NEEDS_WRENCH = 3 /obj/machinery/gravity_generator/main/Topic(href, href_list) - if(..()) - return + return 1 if(href_list["gentoggle"]) breaker = !breaker diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index a30d2de451e..4b2763c0d86 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -107,17 +107,17 @@ if(src.active==1) src.active = 0 user << "You turn off the [src]." - msg_admin_attack("Emitter turned off by [key_name(user, user.client)][isAntag(user) ? "(ANTAG)" : ""](?) in ([x],[y],[z] - JMP)",0,1) - log_game("Emitter turned off by [user.ckey]([user]) in ([x],[y],[z])") - investigate_log("turned off by [user.key]","singulo") + message_admins("Emitter turned off by [key_name_admin(user)] in ([x],[y],[z] - JMP)",0,1) + log_game("Emitter turned off by [key_name(user)] in ([x],[y],[z])") + investigate_log("turned off by [key_name(usr)]","singulo") else src.active = 1 user << "You turn on the [src]." src.shot_number = 0 src.fire_delay = 100 - msg_admin_attack("Emitter turned on by [key_name(user, user.client)][isAntag(user) ? "(ANTAG)" : ""](?) in ([x],[y],[z] - JMP)",0,1) - log_game("Emitter turned on by [user.ckey]([user]) in ([x],[y],[z])") - investigate_log("turned on by [user.key]","singulo") + message_admins("Emitter turned on by [key_name_admin(user)] in ([x],[y],[z] - JMP)",0,1) + log_game("Emitter turned on by [key_name(user)] in ([x],[y],[z])") + investigate_log("turned on by [key_name(usr)]","singulo") update_icon() else user << "\red The controls are locked!" @@ -276,4 +276,5 @@ if(!emagged) locked = 0 emagged = 1 - user.visible_message("[user.name] emags the [src.name].","\red You short out the lock.") + if(user) + user.visible_message("[user.name] emags the [src.name].","\red You short out the lock.") diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm index 05543580e79..490af2d6fb9 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_control.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm @@ -122,9 +122,11 @@ if(strength > strength_upper_limit) strength = strength_upper_limit else - msg_admin_attack("PA Control Computer increased to [strength] by [key_name(usr, usr.client)][isAntag(usr) ? "(ANTAG)" : ""](?) in ([x],[y],[z] - JMP)",0,1) - log_game("PA Control Computer increased to [strength] by [usr.ckey]([usr]) in ([x],[y],[z])") - use_log += text("\[[time_stamp()]\] [usr.name] ([usr.ckey]) has increased the PA Control Computer to [strength].") + message_admins("PA Control Computer increased to [strength] by [key_name_admin(usr)] in ([x],[y],[z] - JMP)",0,1) + log_game("PA Control Computer increased to [strength] by [key_name(usr)] in ([x],[y],[z])") + investigate_log("increased to [strength] by [key_name(usr)]","singulo") + use_log += text("\[[time_stamp()]\] [usr.name] ([key_name(usr)]) has increased the PA Control Computer to [strength].") + investigate_log("increased to [strength] by [usr.key]","singulo") strength_change() @@ -134,8 +136,11 @@ if(strength < 0) strength = 0 else - investigate_log("decreased to [strength] by [usr.key]","singulo") - use_log += text("\[[time_stamp()]\] [usr.name] ([usr.ckey]) has decreased the PA Control Computer to [strength].") + message_admins("PA Control Computer decreased to [strength] by [key_name_admin(usr)] in ([x],[y],[z] - JMP)",0,1) + log_game("PA Control Computer decreased to [strength] by [key_name(usr)] in ([x],[y],[z])") + investigate_log("decreased to [strength] by [key_name(usr)]","singulo") + use_log += text("\[[time_stamp()]\] [usr.name] ([key_name(usr)]) has decreased the PA Control Computer to [strength].") + strength_change() /obj/machinery/particle_accelerator/control_box/power_change() @@ -215,7 +220,7 @@ src.active = !src.active investigate_log("turned [active?"ON":"OFF"] by [usr ? usr.key : "outside forces"]","singulo") if (active) - msg_admin_attack("PA Control Computer turned ON by [key_name(usr, usr.client)][isAntag(usr) ? "(ANTAG)" : ""](?) in ([x],[y],[z] - JMP)",0,1) + msg_admin_attack("PA Control Computer turned ON by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) log_game("PA Control Computer turned ON by [usr.ckey]([usr]) in ([x],[y],[z])") use_log += text("\[[time_stamp()]\] [usr.name] ([usr.ckey]) has turned on the PA Control Computer.") if(src.active) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index fa8c14fe1b0..a61c4dff501 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -113,7 +113,7 @@ /obj/singularity/proc/admin_investigate_setup() last_warning = world.time var/count = locate(/obj/machinery/containment_field) in orange(30, src) - if(!count) message_admins("A singulo has been created without containment fields active ([x],[y],[z])",1) + if(!count) message_admins("A singularity has been created without containment fields active at [x], [y], [z] (JMP)") investigate_log("was created. [count?"":"No containment fields were active"]","singulo") /obj/singularity/proc/dissipate() diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 5fc9e1ae4b0..12dd496303d 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -313,7 +313,7 @@ var/mob/living/user = AM user.dust() power += 200 - message_admins("[src] has consumed [key_name_admin(user)]? (FLW) (JMP).") + message_admins("[src] has consumed [key_name_admin(user)] (JMP).") investigate_log("has consumed [key_name(user)].", "supermatter") else if(isobj(AM) && !istype(AM, /obj/effect)) investigate_log("has consumed [AM].", "supermatter") diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index c279baaa290..f236200337b 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -98,7 +98,7 @@ qdel(src) return - if (!user.IsAdvancedToolUser() || istype(user, /mob/living/carbon/primitive/diona)) + if (!user.IsAdvancedToolUser() || istype(user, /mob/living/simple_animal/diona)) user << "\red You don't have the dexterity to do this!" return if(istype(user, /mob/living)) diff --git a/code/modules/projectiles/guns/energy/hos.dm b/code/modules/projectiles/guns/energy/hos.dm index e523ceb50bf..2fbb0dfd730 100644 --- a/code/modules/projectiles/guns/energy/hos.dm +++ b/code/modules/projectiles/guns/energy/hos.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/energy/hos - name = "HoS Energy Gun" - desc = "This is a modern recreation of the captain's antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time." + name = "head of security's energy gun" + desc = "This is a modern recreation of the captain's antique laser gun. This gun has several unique fire modes, but lacks the ability to recharge over time." icon_state = "hoslaser" item_state = null //so the human update icon uses the icon_state instead. icon_override = 'icons/mob/in-hand/guns.dmi' diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 79ebef8774a..0eee855c3da 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -308,7 +308,7 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. flags = CONDUCT | OPENCONTAINER attack_verb = list("attacked", "slashed", "cut", "sliced") charge_cost = 250 - fire_delay = 10 + fire_delay = 15 icon_override = 'icons/mob/in-hand/guns.dmi' can_charge = 0 @@ -336,7 +336,7 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. modifystate = "adv_plasmacutter" origin_tech = "combat=3;materials=4;magnets=3;plasmatech=3;engineering=2" projectile_type = /obj/item/projectile/plasma/adv - fire_delay = 8 + fire_delay = 10 charge_cost = 100 /obj/item/weapon/gun/energy/disabler diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 9453212b48d..8542729e3d1 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -130,6 +130,11 @@ forcedodge = -1 else */ + if(ishuman(A)) + var/mob/living/carbon/human/H = A + var/obj/item/organ/external/organ = H.get_organ(check_zone(def_zone)) + if(isnull(organ)) + return if(silenced) playsound(loc, hitsound, 5, 1, -1) M << "\red You've been shot in the [parse_zone(def_zone)] by the [src.name]!" @@ -137,18 +142,18 @@ playsound(loc, hitsound, 20, 1, -1) visible_message("\red [A.name] is hit by the [src.name] in the [parse_zone(def_zone)]!")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter if(istype(firer, /mob)) - M.attack_log += "\[[time_stamp()]\] [firer]/[firer.ckey] shot [M]/[M.ckey] with a [src.type][reagent_note]" - firer.attack_log += "\[[time_stamp()]\] [firer]/[firer.ckey] shot [M]/[M.ckey] with a [src.type][reagent_note]" + M.attack_log += "\[[time_stamp()]\] [key_name(firer)] shot [M]/[M.ckey] with a [src.type][reagent_note]" + firer.attack_log += "\[[time_stamp()]\] [key_name(firer)] shot [M]/[M.ckey] with a [src.type][reagent_note]" if(M.ckey && chatlog_attacks) - msg_admin_attack("[firer] ([firer.ckey])[isAntag(firer) ? "(ANTAG)" : ""] shot [M] ([M.ckey]) with a [src][reagent_note] (JMP)") //BS12 EDIT ALG + msg_admin_attack("[key_name_admin(firer)] shot [key_name_admin(M)] with a [src][reagent_note]") //BS12 EDIT ALG if(!iscarbon(firer)) M.LAssailant = null else M.LAssailant = firer else - M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [M]/[M.ckey] with a [src][reagent_note]" + M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [key_name(M)] with a [src][reagent_note]" if(M.ckey && chatlog_attacks) - msg_admin_attack("UNKNOWN shot [M] ([M.ckey]) with a [src][reagent_note] (JMP)") //BS12 EDIT ALG + msg_admin_attack("UNKNOWN shot [key_name_admin(M)] with a [src][reagent_note] (JMP)") //BS12 EDIT ALG spawn(0) if(A) diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index 6304ba6b2bd..b263e03afeb 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -244,29 +244,31 @@ obj/item/projectile/kinetic/New() icon_state = "plasmacutter" damage_type = BRUTE damage = 5 - range = 1 + range = 3 /obj/item/projectile/plasma/New() var/turf/proj_turf = get_turf(src) if(!istype(proj_turf, /turf)) return var/datum/gas_mixture/environment = proj_turf.return_air() - var/pressure = environment.return_pressure() - if(pressure < 30) - name = "full strength plasma blast" - damage *= 3 - range += 3 + if(environment) + var/pressure = environment.return_pressure() + if(pressure < 30) + name = "full strength plasma blast" + damage *= 3 ..() -/obj/item/projectile/plasma/on_hit(var/atom/target) +/obj/item/projectile/plasma/on_hit(atom/target) + . = ..() if(istype(target, /turf/simulated/mineral)) var/turf/simulated/mineral/M = target M.gets_drilled(firer) - return ..() + range = max(range - 1, 1) + return -1 /obj/item/projectile/plasma/adv - range = 2 + range = 5 /obj/item/projectile/plasma/adv/mech damage = 10 - range = 3 + range = 6 diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index 6ffa7a03a46..03dd8cfbcf6 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -562,6 +562,7 @@ var/count = 1 if (href_list["createpill_multiple"]) count = isgoodnumber(input("Select the number of pills to make.", 10, pillamount) as num) if (count > 20) count = 20 //Pevent people from creating huge stacks of pills easily. Maybe move the number to defines? + if (count <= 0) return var/amount_per_pill = reagents.total_volume/count if (amount_per_pill > 50) amount_per_pill = 50 var/name = reject_bad_text(input(usr,"Name:","Name your pill!","[reagents.get_master_reagent_name()] ([amount_per_pill] units)")) diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index 6aa10fd29bb..615eefbcf5a 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -2231,9 +2231,9 @@ datum adj_drowsy = -3 adj_sleepy = -2 adj_temp = 25 + overdose_threshold = 45 on_mob_life(var/mob/living/M as mob) - M.Jitter(5) if(adj_temp > 0 && holder.has_reagent("frostoil")) holder.remove_reagent("frostoil", 10*REAGENTS_METABOLISM) if(prob(50)) @@ -2242,6 +2242,13 @@ datum M.AdjustWeakened(-1) ..() return + + overdose_process(var/mob/living/M as mob) + if(volume > 45) + M.Jitter(5) + + ..() + return icecoffee name = "Iced Coffee" diff --git a/code/modules/reagents/dartgun.dm b/code/modules/reagents/dartgun.dm index 75825c4939c..585e468c70e 100644 --- a/code/modules/reagents/dartgun.dm +++ b/code/modules/reagents/dartgun.dm @@ -180,15 +180,15 @@ M.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] shot [M]/[M.ckey] with a dartgun ([R])" user.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] shot [M]/[M.ckey] with a dartgun ([R])" if(M.ckey) - msg_admin_attack("[user] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] shot [M] ([M.ckey]) with a dartgun ([R]) (JMP)") + msg_admin_attack("[key_name_admin(user)] shot [M] ([M.ckey]) with a dartgun ([R]).") if(!iscarbon(user)) M.LAssailant = null else M.LAssailant = user else - M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [M]/[M.ckey] with a dartgun ([R])" - msg_admin_attack("UNKNOWN shot [M] ([M.ckey]) with a dartgun ([R]) (JMP)") + M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [key_name_admin(M)] with a dartgun ([R])" + msg_admin_attack("UNKNOWN shot [key_name(M)] with a dartgun ([R]) (JMP)") if(D.reagents) D.reagents.trans_to(M, 15) diff --git a/code/modules/reagents/newchem/toxins.dm b/code/modules/reagents/newchem/toxins.dm index bf1d964c971..00135ad0c05 100644 --- a/code/modules/reagents/newchem/toxins.dm +++ b/code/modules/reagents/newchem/toxins.dm @@ -125,7 +125,7 @@ datum/reagent/neurotoxin2/on_mob_life(var/mob/living/M as mob) if(current_cycle >= 5) if(prob(5)) M.emote("drool") - if(M.brainloss < 60) + if(M.getBrainLoss() < 60) M.adjustBrainLoss(1*REM) M.adjustToxLoss(1*REM) if(current_cycle >= 9) @@ -610,8 +610,8 @@ datum/reagent/atrazine/reaction_mob(var/mob/living/M, var/method=TOUCH, var/volu H.adjustToxLoss(50) ..() return - else if(istype(M,/mob/living/carbon/primitive/diona)) //plantmen monkeys (diona) take EVEN MORE damage - var/mob/living/carbon/primitive/diona/D = M + else if(istype(M,/mob/living/simple_animal/diona)) //plantmen monkeys (diona) take EVEN MORE damage + var/mob/living/simple_animal/diona/D = M D.adjustToxLoss(100) ..() return diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm index 98366e36e22..e5f1345f8fd 100644 --- a/code/modules/reagents/reagent_containers/borghydro.dm +++ b/code/modules/reagents/reagent_containers/borghydro.dm @@ -70,18 +70,29 @@ /obj/item/weapon/reagent_containers/borghypo/attack(mob/living/M as mob, mob/user as mob) var/datum/reagents/R = reagent_list[mode] if(!R.total_volume) - user << "\red The injector is empty." + user << "The injector is empty." return - if (!(istype(M))) + if (!istype(M)) return + + var/mob/living/carbon/human/H = M + if(istype(H)) + var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting) + if(!affected) + user << "\The [H] is missing that limb!" + return + else if(affected.status & ORGAN_ROBOT) + user << "You cannot inject a robotic limb." + return + if (R.total_volume && M.can_inject(user,1)) - user << "\blue You inject [M] with the injector." - M << "\red You feel a tiny prick!" + user << "You inject [M] with the injector." + M << "You feel a tiny prick!" R.add_reagent(M) if(M.reagents) var/trans = R.trans_to(M, amount_per_transfer_from_this) - user << "\blue [trans] units injected. [R.total_volume] units remaining." + user << "[trans] units injected. [R.total_volume] units remaining." return /obj/item/weapon/reagent_containers/borghypo/attack_self(mob/user as mob) diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm index 253613a7360..0097cf45907 100644 --- a/code/modules/reagents/reagent_containers/dropper.dm +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -70,10 +70,10 @@ for(var/datum/reagent/R in src.reagents.reagent_list) injected += R.name var/contained = english_list(injected) - M.attack_log += text("\[[time_stamp()]\] Has been squirted with [src.name] by [user.name] ([user.ckey]). Reagents: [contained]") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to squirt [M.name] ([M.key]). Reagents: [contained]") + M.attack_log += text("\[[time_stamp()]\] Has been squirted with [src.name] by [key_name(user)]. Reagents: [contained]") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to squirt [key_name(M)]. Reagents: [contained]") if(M.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] squirted [M.name] ([M.key]) with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)]) (JMP)") + msg_admin_attack("[key_name_admin(user)] squirted [key_name_admin(M)] with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)])") if(!iscarbon(user)) M.LAssailant = null else @@ -88,8 +88,8 @@ badshit += reagents_to_log[bad_reagent] if(badshit.len) var/hl="\red ([english_list(badshit)]) \black" - message_admins("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl] (JMP)") - log_game("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].") + message_admins("[key_name_admin(user)] added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl]") + log_game("[key_name(user)] added [reagents.get_reagent_ids(1)] to \a [target] with [src].") trans = src.reagents.trans_to(target, amount_per_transfer_from_this) user << "\blue You transfer [trans] units of the solution." diff --git a/code/modules/reagents/reagent_containers/drugs.dm b/code/modules/reagents/reagent_containers/drugs.dm index d6804f54778..312cbf297a2 100644 --- a/code/modules/reagents/reagent_containers/drugs.dm +++ b/code/modules/reagents/reagent_containers/drugs.dm @@ -67,8 +67,8 @@ badshit += reagents_to_log[bad_reagent] if(badshit.len) var/hl="\red ([english_list(badshit)]) \black" - message_admins("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl] (JMP)") - log_game("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].") + message_admins("[key_name_admin(user)] added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl]") + log_game("[key_name(user)] added [reagents.get_reagent_ids(1)] to \a [target] with [src].") var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this) user << "\blue You transfer [trans] units of the solution to [target]." diff --git a/code/modules/reagents/reagent_containers/food/condiment.dm b/code/modules/reagents/reagent_containers/food/condiment.dm index f79dc8ded09..309f928288b 100644 --- a/code/modules/reagents/reagent_containers/food/condiment.dm +++ b/code/modules/reagents/reagent_containers/food/condiment.dm @@ -48,10 +48,10 @@ for(var/mob/O in viewers(world.view, user)) O.show_message("\red [user] feeds [M] [src].", 1) - M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [user.name] ([user.ckey]) Reagents: [reagentlist(src)]") - user.attack_log += text("\[[time_stamp()]\] Fed [src.name] by [M.name] ([M.ckey]) Reagents: [reagentlist(src)]") + M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [key_name(user)] Reagents: [reagentlist(src)]") + user.attack_log += text("\[[time_stamp()]\] Fed [src.name] by [key_name(M)] Reagents: [reagentlist(src)]") if(M.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] fed [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") + msg_admin_attack("[key_name_admin(user)] fed [key_name_admin(M)] with [src.name] (INTENT: [uppertext(user.a_intent)])") if(!iscarbon(user)) M.LAssailant = null else diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm index 15f585051e6..8528e364dc7 100644 --- a/code/modules/reagents/reagent_containers/food/drinks.dm +++ b/code/modules/reagents/reagent_containers/food/drinks.dm @@ -30,8 +30,8 @@ if(istype(M,/mob/living/carbon/human)) var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) - H << "\red You have a monitor for a head, where do you think you're going to put that?" + if(!H.check_has_mouth()) + user << "Where do you intend to put \the [src]? You don't have a mouth!" return M << "\blue You swallow a gulp of [src]." @@ -45,8 +45,8 @@ else if( istype(M, /mob/living/carbon/human) ) var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) - user << "\red They have a monitor for a head, where do you think you're going to put that?" + if(!H.check_has_mouth()) + user << "Where do you intend to put \the [src]? \The [H] doesn't have a mouth!" return for(var/mob/O in viewers(world.view, user)) @@ -55,9 +55,9 @@ for(var/mob/O in viewers(world.view, user)) O.show_message("\red [user] feeds [M] [src].", 1) - M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [user.name] ([user.ckey]) Reagents: [reagentlist(src)]") - user.attack_log += text("\[[time_stamp()]\] Fed [M.name] by [M.name] ([M.ckey]) Reagents: [reagentlist(src)]") - log_attack("[user.name] ([user.ckey]) fed [M.name] ([M.ckey]) with [src.name] Reagents: [reagentlist(src)] (INTENT: [uppertext(user.a_intent)]) (JMP)") + M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [key_name(user)] Reagents: [reagentlist(src)]") + user.attack_log += text("\[[time_stamp()]\] Fed [M.name] by [key_name(M)] Reagents: [reagentlist(src)]") + log_attack("[key_name_admin(user)] fed [key_name_admin(M)] with [src.name] Reagents: [reagentlist(src)] (INTENT: [uppertext(user.a_intent)])") if(!iscarbon(user)) M.LAssailant = null else diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm index 20da18a668f..205837633de 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -97,10 +97,10 @@ else O.show_message(text("\red [target] has attacked himself with a bottle of [src.name]!"), 1) //Attack logs - user.attack_log += text("\[[time_stamp()]\] Has attacked [target.name] ([target.ckey]) with a bottle!") - target.attack_log += text("\[[time_stamp()]\] Has been smashed with a bottle by [user.name] ([user.ckey])") + user.attack_log += text("\[[time_stamp()]\] Has attacked [key_name(target)] with a bottle!") + target.attack_log += text("\[[time_stamp()]\] Has been smashed with a bottle by [key_name(user)]") if(target.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] attacked [target.name] ([target.ckey]) with a bottle. (INTENT: [uppertext(user.a_intent)]) (JMP)") + msg_admin_attack("[key_name_admin(user)] attacked [key_name_admin(target)] with a bottle. (INTENT: [uppertext(user.a_intent)])") if(!iscarbon(user)) target.LAssailant = null else diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index d77edbb6903..760988b4977 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -48,8 +48,8 @@ if(M == user) //If you're eating it yourself if(istype(M,/mob/living/carbon/human)) var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) - H << "\red You have a monitor for a head, where do you think you're going to put that?" + if(!H.check_has_mouth()) + user << "Where do you intend to put \the [src]? You don't have a mouth!" return if (fullness <= 50) M << "\red You hungrily chew out a piece of [src] and gobble it!" @@ -65,8 +65,8 @@ else if(istype(M,/mob/living/carbon/human)) var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) - H << "\red They have a monitor for a head, where do you think you're going to put that?" + if(!H.check_has_mouth()) + user << "Where do you intend to put \the [src]? \The [H] doesn't have a mouth!" return if(!istype(M, /mob/living/carbon/slime)) //If you're feeding it to someone else. diff --git a/code/modules/reagents/reagent_containers/glass_containers.dm b/code/modules/reagents/reagent_containers/glass_containers.dm index cf4f8794bf0..608fbc405be 100644 --- a/code/modules/reagents/reagent_containers/glass_containers.dm +++ b/code/modules/reagents/reagent_containers/glass_containers.dm @@ -85,10 +85,10 @@ for(var/datum/reagent/R in src.reagents.reagent_list) injected += R.name var/contained = english_list(injected) - M.attack_log += text("\[[time_stamp()]\] Has been splashed with [src.name] by [user.name] ([user.ckey]). Reagents: [contained]") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to splash [M.name] ([M.key]). Reagents: [contained]") + M.attack_log += text("\[[time_stamp()]\] Has been splashed with [src.name] by [key_name(user)]. Reagents: [contained]") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to splash [key_name(M)]. Reagents: [contained]") if(M.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] splashed [M.name] ([M.key]) with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)]) (JMP)") + msg_admin_attack("[key_name_admin(user)] splashed [key_name_admin(M)] with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)])") if(!iscarbon(user)) M.LAssailant = null else @@ -129,8 +129,8 @@ badshit += reagents_to_log[bad_reagent] if(badshit.len) var/hl="\red ([english_list(badshit)]) \black" - message_admins("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl] (JMP)") - log_game("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].") + message_admins("[key_name_admin(user)] added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl]") + log_game("[key_name(user)] added [reagents.get_reagent_ids(1)] to \a [target] with [src].") var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this) user << "\blue You transfer [trans] units of the solution to [target]." diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index e24378fb137..72d4c18297c 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -33,10 +33,10 @@ for(var/datum/reagent/R in src.reagents.reagent_list) injected += R.name var/contained = english_list(injected) - M.attack_log += text("\[[time_stamp()]\] Has been injected with [src.name] by [user.name] ([user.ckey]). Reagents: [contained]") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to inject [M.name] ([M.key]). Reagents: [contained]") + M.attack_log += text("\[[time_stamp()]\] Has been injected with [src.name] by [key_name(user)]. Reagents: [contained]") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to inject [key_name(M)]. Reagents: [contained]") if(M.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] injected [M.name] ([M.key]) with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)]) (JMP)") + msg_admin_attack("[key_name_admin(user)] injected [key_name_admin(M)] with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)])") if(!iscarbon(user)) M.LAssailant = null else diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index e56d26560f7..534de035872 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -23,8 +23,8 @@ if(M == user) if(istype(M,/mob/living/carbon/human)) var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) - H << "You have a monitor for a head, where do you think you're going to put that?" + if(!H.check_has_mouth()) + user << "Where do you intend to put \the [src]? You don't have a mouth!" return M << "You [apply_method] [src]." @@ -41,8 +41,8 @@ else if(istype(M, /mob/living/carbon/human) ) var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) - user << "They have a monitor for a head, where do you think you're going to put that?" + if(!H.check_has_mouth()) + user << "Where do you intend to put \the [src]? \The [H] doesn't have a mouth!" return for(var/mob/O in viewers(world.view, user)) @@ -54,10 +54,10 @@ for(var/mob/O in viewers(world.view, user)) O.show_message("[user] forces [M] to [apply_method] [src].", 1) - M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [user.name] ([user.ckey]) Reagents: [reagentlist(src)]") - user.attack_log += text("\[[time_stamp()]\] Fed [M.name] by [M.name] ([M.ckey]) Reagents: [reagentlist(src)]") + M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [key_name(user)] Reagents: [reagentlist(src)]") + user.attack_log += text("\[[time_stamp()]\] Fed [src.name] to [key_name(M)]) Reagents: [reagentlist(src)]") if(M.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] fed [M.name] ([M.ckey]) with [src.name] Reagents: [reagentlist(src)] (INTENT: [uppertext(user.a_intent)]) (JMP)") + msg_admin_attack("[key_name_admin(user)] fed [key_name_admin(M)] with [src.name] Reagents: [reagentlist(src)] (INTENT: [uppertext(user.a_intent)])") if(!iscarbon(user)) M.LAssailant = null else diff --git a/code/modules/reagents/reagent_containers/robodropper.dm b/code/modules/reagents/reagent_containers/robodropper.dm index 8f2a1d4e9e5..c5da1639304 100644 --- a/code/modules/reagents/reagent_containers/robodropper.dm +++ b/code/modules/reagents/reagent_containers/robodropper.dm @@ -33,8 +33,8 @@ badshit += reagents_to_log[bad_reagent] if(badshit.len) var/hl="\red ([english_list(badshit)]) \black" - message_admins("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl] (JMP)") - log_game("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].") + message_admins("[key_name_admin(user)] added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl]") + log_game("[key_name(user)] added [reagents.get_reagent_ids(1)] to \a [target] with [src].") else if(ismob(target)) if(istype(target , /mob/living/carbon/human)) @@ -78,10 +78,10 @@ for(var/datum/reagent/R in src.reagents.reagent_list) injected += R.name var/contained = english_list(injected) - M.attack_log += text("\[[time_stamp()]\] Has been squirted with [src.name] by [user.name] ([user.ckey]). Reagents: [contained]") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to squirt [M.name] ([M.key]). Reagents: [contained]") + M.attack_log += text("\[[time_stamp()]\] Has been squirted with [src.name] by [key_name(user)]. Reagents: [contained]") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to squirt [key_name(M)]. Reagents: [contained]") if(M.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] squirted [M.name] ([M.key]) with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)]) (JMP)") + msg_admin_attack("[key_name_admin(user)] squirted [key_name_admin(M)] with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)])") if(!iscarbon(user)) M.LAssailant = null else diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index fe255c9caf7..252f7ed0208 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -51,10 +51,10 @@ message_admins("[key_name_admin(user)] fired sulphuric acid from \a [src].") log_game("[key_name(user)] fired sulphuric acid from \a [src].") if(reagents.has_reagent("facid")) - message_admins("[key_name_admin(user)] fired Fluorosulfuric Acid from \a [src].") + message_admins("[key_name_admin(user)] fired fluorosulfuric acid from \a [src].") log_game("[key_name(user)] fired Fluorosulfuric Acid from \a [src].") if(reagents.has_reagent("lube")) - message_admins("[key_name_admin(user)] fired Space lube from \a [src].") + message_admins("[key_name_admin(user)] fired space lube from \a [src].") log_game("[key_name(user)] fired Space lube from \a [src].") return diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index ab2040ffd1a..408076341ee 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -168,11 +168,20 @@ if(target.reagents.total_volume >= target.reagents.maximum_volume) user << "\red [target] is full." return + + var/mob/living/carbon/human/H = target + if(istype(H)) + var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting) + if(!affected) + user << "\The [H] is missing that limb!" + return + /* else if(affected.status & ORGAN_ROBOT) + user << "You cannot inject a robotic limb." + return */ if(ismob(target) && target != user) var/time = 30 //Injecting through a hardsuit takes longer due to needing to find a port. if(istype(target,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = target if(H.wear_suit && istype(H.wear_suit,/obj/item/clothing/suit/space)) time = 60 @@ -193,10 +202,10 @@ for(var/datum/reagent/R in src.reagents.reagent_list) injected += R.name var/contained = english_list(injected) - M.attack_log += text("\[[time_stamp()]\] Has been injected with [src.name] by [user.name] ([user.ckey]). Reagents: [contained]") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to inject [M.name] ([M.key]). Reagents: [contained]") + M.attack_log += text("\[[time_stamp()]\] Has been injected with [src.name] by [key_name(user)]. Reagents: [contained]") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to inject [key_name(M)]. Reagents: [contained]") if(M.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] injected [M.name] ([M.key]) with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)]) (JMP)") + msg_admin_attack("[key_name_admin(user)] injected [key_name_admin(M)] with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)])") if(!iscarbon(user)) M.LAssailant = null else @@ -215,8 +224,8 @@ badshit += reagents_to_log[bad_reagent] if(badshit.len) var/hl="\red ([english_list(badshit)]) \black" - message_admins("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl] (JMP)") - log_game("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].") + message_admins("[key_name_admin(user)] added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl] ") + log_game("[key_name(user)] added [reagents.get_reagent_ids(1)] to \a [target] with [src].") spawn(5) var/datum/reagent/blood/B @@ -281,7 +290,7 @@ user.attack_log += "\[[time_stamp()]\] Attacked [target.name] ([target.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" target.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" if(target.ckey) - msg_admin_attack("[user.name] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] attacked [target.name] ([target.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") + msg_admin_attack("[key_name_admin(user)] attacked [key_name_admin(target)] with [src.name] (INTENT: [uppertext(user.a_intent)])") if(!iscarbon(user)) target.LAssailant = null else diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index eb13ba91b21..b0d3a7e4a85 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -135,8 +135,8 @@ var/obj/item/device/assembly_holder/H = W if (istype(H.a_left,/obj/item/device/assembly/igniter) || istype(H.a_right,/obj/item/device/assembly/igniter)) - msg_admin_attack("[key_name_admin(user)][isAntag(user) ? "(ANTAG)" : ""] rigged fueltank at ([loc.x],[loc.y],[loc.z]) for explosion.") - log_game("[key_name(user)] rigged fueltank at ([loc.x],[loc.y],[loc.z]) for explosion.") + msg_admin_attack("[key_name_admin(user)] rigged a fueltank for explosion (JMP)") + log_game("[key_name(user)] rigged fueltank a fueltank for explosion at [loc.x], [loc.y], [loc.z]") rig = W user.drop_item() diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 4c042f04a12..e6a16f00765 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -50,11 +50,9 @@ // attack by item places it in to disposal /obj/machinery/disposal/attackby(var/obj/item/I, var/mob/user, params) - if(stat & BROKEN || !I || !user || (I.flags & NODROP)) + if(stat & BROKEN || !I || !user || ((I.flags & NODROP) && !istype(I, /obj/item/weapon/storage/bag/trash/cyborg))) return - if(isrobot(user) && !istype(I, /obj/item/weapon/storage/bag/trash)) - return src.add_fingerprint(user) if(mode<=0) // It's off if(istype(I, /obj/item/weapon/screwdriver)) @@ -124,10 +122,10 @@ for (var/mob/C in viewers(src)) C.show_message("\red [GM.name] has been placed in the [src] by [user].", 3) qdel(G) - usr.attack_log += text("\[[time_stamp()]\] Has placed [GM.name] ([GM.ckey]) in disposals.") - GM.attack_log += text("\[[time_stamp()]\] Has been placed in disposals by [usr.name] ([usr.ckey])") + usr.attack_log += text("\[[time_stamp()]\] Has placed [key_name(GM)] in disposals.") + GM.attack_log += text("\[[time_stamp()]\] Has been placed in disposals by [key_name(user)]") if(GM.ckey) - msg_admin_attack("[usr] ([usr.ckey])[isAntag(usr) ? "(ANTAG)" : ""] placed [GM] ([GM.ckey]) in a disposals unit. (JMP)") + msg_admin_attack("[key_name_admin(user)] placed [key_name_admin(GM)] in a disposals unit. (JMP)") return if(!I) return @@ -171,10 +169,10 @@ msg = "[user.name] stuffs [target.name] into the [src]!" user << "You stuff [target.name] into the [src]!" - user.attack_log += text("\[[time_stamp()]\] Has placed [target.name] ([target.ckey]) in disposals.") - target.attack_log += text("\[[time_stamp()]\] Has been placed in disposals by [user.name] ([user.ckey])") + user.attack_log += text("\[[time_stamp()]\] Has placed [key_name(target)] in disposals.") + target.attack_log += text("\[[time_stamp()]\] Has been placed in disposals by [key_name(user)]") if(target.ckey) - msg_admin_attack("[user] ([user.ckey])[isAntag(user) ? "(ANTAG)" : ""] placed [target] ([target.ckey]) in a disposals unit. (JMP)") + msg_admin_attack("[key_name_admin(user)] placed [key_name_admin(target)] in a disposals unit") else return if (target.client) diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index 21182bd0e10..ac92bd70b33 100755 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -284,14 +284,12 @@ if(deliveryCheck == 0) H.destinationTag = 1 - air_contents = new() // new empty gas resv. - sleep(10) playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0) sleep(5) // wait for animation to finish H.init(src) // copy the contents of disposer to holder - + air_contents = new() // The holder just took our gas; replace it H.start(src) // start the holder processing movement flushing = 0 // now reset disposal state diff --git a/code/modules/research/designs/equipment_designs.dm b/code/modules/research/designs/equipment_designs.dm index 10a6a18ee31..ab78834a877 100644 --- a/code/modules/research/designs/equipment_designs.dm +++ b/code/modules/research/designs/equipment_designs.dm @@ -99,4 +99,15 @@ build_type = PROTOLATHE materials = list("$metal" = 4000, "$glass" = 1000) build_path = /obj/item/clothing/mask/gas/welding + category = list("Equipment") + +/datum/design/detective_scanner + name = "Forensic Scanner" + desc = "A high tech scanner designed for forensic evidence collection, DNA recovery, and fiber analysis." + id = "detectivescanner" + req_tech = list("biotech" = 2, "magnets" = 4) + build_type = PROTOLATHE + materials = list("$metal" = 6000, "$glass" = 2000) + build_path = /obj/item/device/detective_scanner + locked = 1 //no validhunting scientists. category = list("Equipment") \ No newline at end of file diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm index da6bf1244bf..34a10b97f1d 100644 --- a/code/modules/research/message_server.dm +++ b/code/modules/research/message_server.dm @@ -295,7 +295,7 @@ var/obj/machinery/blackbox_recorder/blackbox if(!dbcon.IsConnected()) return var/round_id - var/DBQuery/query = dbcon.NewQuery("SELECT MAX(round_id) AS round_id FROM erro_feedback") + var/DBQuery/query = dbcon.NewQuery("SELECT MAX(round_id) AS round_id FROM [format_table_name("feedback")]") query.Execute() while(query.NextRow()) round_id = query.item[1] @@ -305,7 +305,7 @@ var/obj/machinery/blackbox_recorder/blackbox round_id++ for(var/datum/feedback_variable/FV in feedback) - var/sql = "INSERT INTO erro_feedback VALUES (null, Now(), [round_id], \"[FV.get_variable()]\", [FV.get_value()], \"[FV.get_details()]\")" + var/sql = "INSERT INTO [format_table_name("feedback")] VALUES (null, Now(), [round_id], \"[FV.get_variable()]\", [FV.get_value()], \"[FV.get_details()]\")" var/DBQuery/query_insert = dbcon.NewQuery(sql) query_insert.Execute() diff --git a/code/modules/research/xenoarchaeology/tools/ano_device_battery.dm b/code/modules/research/xenoarchaeology/tools/ano_device_battery.dm index bb1d7e30c4f..6df826f3792 100644 --- a/code/modules/research/xenoarchaeology/tools/ano_device_battery.dm +++ b/code/modules/research/xenoarchaeology/tools/ano_device_battery.dm @@ -210,6 +210,6 @@ M.lastattacker = user if(inserted_battery.battery_effect) - user.attack_log += "\[[time_stamp()]\] Tapped [M.name] ([M.ckey]) with [name] (EFFECT: [inserted_battery.battery_effect.effecttype])" - M.attack_log += "\[[time_stamp()]\] Tapped by [user.name] ([user.ckey]) with [name] (EFFECT: [inserted_battery.battery_effect.effecttype])" - msg_admin_attack("[key_name(user)][isAntag(user) ? "(ANTAG)" : ""] tapped [key_name(M)] with [name] (EFFECT: [inserted_battery.battery_effect.effecttype])" ) + user.attack_log += "\[[time_stamp()]\] Tapped [key_name(M)] with [name] (EFFECT: [inserted_battery.battery_effect.effecttype])" + M.attack_log += "\[[time_stamp()]\] Tapped by [key_name(user)] with [name] (EFFECT: [inserted_battery.battery_effect.effecttype])" + msg_admin_attack("[key_name_admin(user)] tapped [key_name_admin(M)] with [name] (EFFECT: [inserted_battery.battery_effect.effecttype])" ) diff --git a/code/modules/scripting/IDE.dm b/code/modules/scripting/IDE.dm index b9b53b274d2..1733895a91f 100644 --- a/code/modules/scripting/IDE.dm +++ b/code/modules/scripting/IDE.dm @@ -11,7 +11,6 @@ client/verb/tcssave() var/tcscode=winget(src, "tcscode", "text") var/msg="[mob.name] is adding script to server [Server]: [tcscode]" diary << msg - message_admins("[mob.name] has uploaded a NTLS script to [Machine.SelectedServer] ([mob.x],[mob.y],[mob.z] - JMP)",0,1) Server.setcode( tcscode ) // this actually saves the code from input to the server src << output(null, "tcserror") // clear the errors else @@ -36,7 +35,7 @@ client/verb/tcscompile() if(Machine.SelectedServer) var/obj/machinery/telecomms/server/Server = Machine.SelectedServer Server.setcode( winget(src, "tcscode", "text") ) // save code first - var/list/compileerrors = Server.compile() // then compile the code! + var/list/compileerrors = Server.compile(usr) // then compile the code! // Output all the compile-time errors src << output(null, "tcserror") diff --git a/code/modules/security levels/keycard authentication.dm b/code/modules/security levels/keycard authentication.dm index 0950f5d1594..87f478938f3 100644 --- a/code/modules/security levels/keycard authentication.dm +++ b/code/modules/security levels/keycard authentication.dm @@ -122,7 +122,7 @@ confirmed = 0 trigger_event(event) log_game("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]") - message_admins("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]", 1) + message_admins("[key_name_admin(event_triggered_by)] ([admin_jump_link(event_triggered_by, "holder")]) triggered and [key_name_admin(event_confirmed_by)] ([admin_jump_link(event_confirmed_by, "holder")]) confirmed event [event]", 1) reset() /obj/machinery/keycard_auth/proc/receive_request(var/obj/machinery/keycard_auth/source) @@ -174,8 +174,7 @@ var/global/maint_all_access = 0 for(var/obj/machinery/door/airlock/D in A) D.emergency = 1 D.update_icon(0) - world << "Attention!" - world << "The maintenance access requirement has been revoked on all airlocks." + minor_announcement.Announce("The maintenance access requirement has been revoked on all airlocks.") maint_all_access = 1 /proc/revoke_maint_all_access() @@ -183,6 +182,5 @@ var/global/maint_all_access = 0 for(var/obj/machinery/door/airlock/D in A) D.emergency = 0 D.update_icon(0) - world << "Attention!" - world << "The maintenance access requirement has been readded on all maintenance airlocks." + minor_announcement.Announce("The maintenance access requirement has been readded on all maintenance airlocks.") maint_all_access = 0 \ No newline at end of file diff --git a/code/modules/surgery/bones.dm b/code/modules/surgery/bones.dm index 2aac7c6ab91..9bfb67034ab 100644 --- a/code/modules/surgery/bones.dm +++ b/code/modules/surgery/bones.dm @@ -16,7 +16,7 @@ can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) - return affected && affected.open == 2 && affected.stage == 0 + return affected && !(affected.status & ORGAN_ROBOT) && affected.open == 2 && affected.stage == 0 begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) @@ -48,7 +48,7 @@ can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) - return affected && affected.limb_name != "head" && affected.open == 2 && affected.stage == 1 + return affected && !(affected.status & ORGAN_ROBOT) && affected.limb_name != "head" && affected.open == 2 && affected.stage == 1 begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) @@ -85,7 +85,7 @@ can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) - return affected && affected.limb_name == "head" && affected.open == 2 && affected.stage == 1 + return affected && !(affected.status & ORGAN_ROBOT) && affected.limb_name == "head" && affected.open == 2 && affected.stage == 1 begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) user.visible_message("[user] is beginning piece together [target]'s skull with \the [tool]." , \ @@ -119,7 +119,7 @@ can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) - return affected && affected.open == 2 && affected.stage == 2 + return affected && !(affected.status & ORGAN_ROBOT) && affected.open == 2 && affected.stage == 2 begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) diff --git a/code/modules/surgery/braincore.dm b/code/modules/surgery/braincore.dm index a11df776f3a..3a12e06abbe 100644 --- a/code/modules/surgery/braincore.dm +++ b/code/modules/surgery/braincore.dm @@ -92,9 +92,9 @@ if(borer) borer.detatch() //Should remove borer if the brain is removed - RR - user.attack_log += "\[[time_stamp()]\] Debrained [target.name] ([target.ckey]) with [tool.name] (INTENT: [uppertext(user.a_intent)])" - target.attack_log += "\[[time_stamp()]\] Debrained by [user.name] ([user.ckey]) with [tool.name] (INTENT: [uppertext(user.a_intent)])" - msg_admin_attack("[user.name] ([user.ckey]) debrained [target.name] ([target.ckey]) with [tool.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") + user.attack_log += "\[[time_stamp()]\] Debrained [key_name(target)] with [tool.name] (INTENT: [uppertext(user.a_intent)])" + target.attack_log += "\[[time_stamp()]\] Debrained by [key_name(user)] with [tool.name] (INTENT: [uppertext(user.a_intent)])" + msg_admin_attack("[key_name_admin(user)] debrained [key_name_admin(target)] with [tool.name]") var/obj/item/organ/brain/B = target.internal_organs_by_name["brain"] if(B && istype(B)) diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm index fedf5bbc1c0..48baea91d3b 100644 --- a/code/modules/surgery/encased.dm +++ b/code/modules/surgery/encased.dm @@ -12,7 +12,7 @@ return 0 var/obj/item/organ/external/affected = target.get_organ(target_zone) - return affected && affected.encased && affected.open >= 2 + return affected && !(affected.status & ORGAN_ROBOT) && affected.encased && affected.open >= 2 /datum/surgery_step/open_encased/saw diff --git a/code/modules/surgery/eye.dm b/code/modules/surgery/eye.dm index 072d95b001b..327a90170d9 100644 --- a/code/modules/surgery/eye.dm +++ b/code/modules/surgery/eye.dm @@ -10,7 +10,7 @@ if (!hasorgans(target)) return 0 var/obj/item/organ/external/affected = target.get_organ(target_zone) - if (!affected) + if (!affected || (affected.status & ORGAN_ROBOT)) return 0 return target_zone == "eyes" diff --git a/code/modules/surgery/face.dm b/code/modules/surgery/face.dm index c5779936966..9513bbe8f07 100644 --- a/code/modules/surgery/face.dm +++ b/code/modules/surgery/face.dm @@ -10,7 +10,7 @@ if (!hasorgans(target)) return 0 var/obj/item/organ/external/affected = target.get_organ(target_zone) - if (!affected) + if (!affected || (affected.status & ORGAN_ROBOT)) return 0 return target_zone == "mouth" diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm index 6f8e8f537d0..5c503a035ac 100644 --- a/code/modules/surgery/generic.dm +++ b/code/modules/surgery/generic.dm @@ -15,8 +15,6 @@ return 0 if (affected.status & ORGAN_DESTROYED) return 0 - if (target_zone == "head" && target.species && (target.species.flags & IS_SYNTHETIC)) - return 1 if (affected.status & ORGAN_ROBOT) return 0 return 1 diff --git a/code/modules/surgery/headreattach.dm b/code/modules/surgery/headreattach.dm deleted file mode 100644 index 4be43c44fd6..00000000000 --- a/code/modules/surgery/headreattach.dm +++ /dev/null @@ -1,33 +0,0 @@ -//This is an uguu head restoration surgery TOTALLY not yoinked from chinsky's limb reattacher -/datum/surgery_step/attach_head/ - priority = 3 // Must be higher than /datum/surgery_step/internal - allowed_tools = list(/obj/item/organ/external/head = 100) - can_infect = 0 - - min_duration = 80 - max_duration = 100 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/head = target.get_organ(target_zone) - return isnull(head) && target_zone == "head" && !isnull(target.species.has_limbs["head"]) - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts attaching [tool] to [target]'s neck.", \ - "You start attaching [tool] to [target]'s neck.") - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] has attached [target]'s head to the body.", \ - "\blue You have attached [target]'s head to the body.") - var/obj/item/organ/external/head = tool - user.unEquip(head) - head.replaced(target) - head.loc = target - head.status = 0 - target.update_body() - target.updatehealth() - target.UpdateDamageIcon() - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, damaging [target]'s neck!", \ - "\red Your hand slips, damaging [target]'s neck!") - target.apply_damage(10, BRUTE, null, sharp=1) diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index 083f5e3c6d7..d4d51e41f76 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -31,6 +31,12 @@ if ("groin") return "abdominal" return "" + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) + user.visible_message("\red [user]'s hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!", \ + "\red Your hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!") + affected.createwound(CUT, 20) /datum/surgery_step/cavity/make_space allowed_tools = list( @@ -59,12 +65,6 @@ user.visible_message("\blue [user] makes some space inside [target]'s [get_cavity(affected)] cavity with \the [tool].", \ "\blue You make some space inside [target]'s [get_cavity(affected)] cavity with \the [tool]." ) - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) - user.visible_message("\red [user]'s hand slips, scraping tissue inside [target]'s [affected.name] with \the [tool]!", \ - "\red Your hand slips, scraping tissue inside [target]'s [affected.name] with \the [tool]!") - affected.createwound(CUT, 20) - /datum/surgery_step/cavity/close_space priority = 2 allowed_tools = list( @@ -94,12 +94,6 @@ user.visible_message("\blue [user] mends [target]'s [get_cavity(affected)] cavity walls with \the [tool].", \ "\blue You mend [target]'s [get_cavity(affected)] cavity walls with \the [tool]." ) - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) - user.visible_message("\red [user]'s hand slips, scraping tissue inside [target]'s [affected.name] with \the [tool]!", \ - "\red Your hand slips, scraping tissue inside [target]'s [affected.name] with \the [tool]!") - affected.createwound(CUT, 20) - /datum/surgery_step/cavity/place_item priority = 0 allowed_tools = list(/obj/item = 100) @@ -129,7 +123,7 @@ else user.visible_message("\blue [user] puts \the [tool] inside [target]'s [get_cavity(affected)] cavity.", \ "\blue You put \the [tool] inside [target]'s [get_cavity(affected)] cavity." ) - if (tool.w_class > get_max_wclass(affected)/2 && prob(50)) + if (tool.w_class > get_max_wclass(affected)/2 && prob(50) && !(affected.status & ORGAN_ROBOT)) user << "\red You tear some vessels trying to fit such big object in this cavity." var/datum/wound/internal_bleeding/I = new () affected.wounds += I @@ -139,12 +133,6 @@ tool.loc = target affected.cavity = 0 - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) - user.visible_message("\red [user]'s hand slips, scraping tissue inside [target]'s [affected.name] with \the [tool]!", \ - "\red Your hand slips, scraping tissue inside [target]'s [affected.name] with \the [tool]!") - affected.createwound(CUT, 20) - ////////////////////////////////////////////////////////////////// // IMPLANT/ITEM REMOVAL SURGERY // ////////////////////////////////////////////////////////////////// @@ -161,9 +149,9 @@ begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] starts poking around inside the incision on [target]'s [affected.name] with \the [tool].", \ - "You start poking around inside the incision on [target]'s [affected.name] with \the [tool]" ) - target.custom_pain("The pain in your chest is living hell!",1) + user.visible_message("[user] starts poking around inside [target]'s [affected.name] with \the [tool].", \ + "You start poking around inside [target]'s [affected.name] with \the [tool]." ) + target.custom_pain("The pain in your [affected.name] is living hell!",1) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -185,8 +173,8 @@ find_prob +=50 if (prob(find_prob)) - user.visible_message("\blue [user] takes something out of incision on [target]'s [affected.name] with \the [tool].", \ - "\blue You take [obj] out of incision on [target]'s [affected.name]s with \the [tool]." ) + user.visible_message("\blue [user] takes something out of [target]'s [affected.name] with \the [tool].", \ + "\blue You take [obj] out of [target]'s [affected.name]s with \the [tool]." ) affected.implants -= obj target.hud_updateflag |= 1 << IMPLOYAL_HUD @@ -221,10 +209,8 @@ "\blue You could not find anything inside [target]'s [affected.name]." ) fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + ..() var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) - user.visible_message("\red [user]'s hand slips, scraping tissue inside [target]'s [affected.name] with \the [tool]!", \ - "\red Your hand slips, scraping tissue inside [target]'s [affected.name] with \the [tool]!") - affected.createwound(CUT, 20) if (affected.implants.len) var/fail_prob = 10 fail_prob += 100 - tool_quality(tool) diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm new file mode 100644 index 00000000000..e264753633f --- /dev/null +++ b/code/modules/surgery/limb_reattach.dm @@ -0,0 +1,129 @@ +//Procedures in this file: Robotic limbs attachment, meat limbs attachment +////////////////////////////////////////////////////////////////// +// LIMB SURGERY // +////////////////////////////////////////////////////////////////// + +/datum/surgery_step/limb/ + priority = 3 // Must be higher than /datum/surgery_step/internal + can_infect = 0 + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if (affected) + return 0 + var/list/organ_data = target.species.has_limbs["[target_zone]"] + return !isnull(organ_data) + +/datum/surgery_step/limb/attach + allowed_tools = list(/obj/item/organ/external = 100) + + min_duration = 50 + max_duration = 70 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = tool + user.visible_message("[user] starts attaching [E.name] to [target]'s [E.amputation_point].", \ + "You start attaching [E.name] to [target]'s [E.amputation_point].") + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = tool + user.visible_message("[user] has attached [target]'s [E.name] to the [E.amputation_point].", \ + "You have attached [target]'s [E.name] to the [E.amputation_point].") + user.unEquip(E) + E.replaced(target) + E.forceMove(target) + target.update_body() + target.updatehealth() + target.UpdateDamageIcon() + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = tool + user.visible_message("[user]'s hand slips, damaging [target]'s [E.amputation_point]!", \ + "Your hand slips, damaging [target]'s [E.amputation_point]!") + target.apply_damage(10, BRUTE, null, sharp=1) + +/datum/surgery_step/limb/connect + allowed_tools = list( + /obj/item/weapon/hemostat = 100, \ + /obj/item/stack/cable_coil = 75, \ + /obj/item/device/assembly/mousetrap = 20 + ) + can_infect = 1 + + min_duration = 100 + max_duration = 120 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = target.get_organ(target_zone) + return E && !E.is_stump() && (E.status & ORGAN_DESTROYED) + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = target.get_organ(target_zone) + user.visible_message("[user] starts connecting tendons and muscles in [target]'s [E.amputation_point] with [tool].", \ + "You start connecting tendons and muscle in [target]'s [E.amputation_point].") + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = target.get_organ(target_zone) + user.visible_message("[user] has connected tendons and muscles in [target]'s [E.amputation_point] with [tool].", \ + "You have connected tendons and muscles in [target]'s [E.amputation_point] with [tool].") + E.status &= ~ORGAN_DESTROYED + if(E.children) + for(var/obj/item/organ/external/C in E.children) + C.status &= ~ORGAN_DESTROYED + target.update_body() + target.updatehealth() + target.UpdateDamageIcon() + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = tool + user.visible_message("[user]'s hand slips, damaging [target]'s [E.amputation_point]!", \ + "Your hand slips, damaging [target]'s [E.amputation_point]!") + target.apply_damage(10, BRUTE, null, sharp=1) + +/datum/surgery_step/limb/mechanize + allowed_tools = list(/obj/item/robot_parts = 100) + + min_duration = 80 + max_duration = 100 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/robot_parts/p = tool + if (p.part) + if (!(target_zone in p.part)) + return 0 + return isnull(target.get_organ(target_zone)) + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts attaching \the [tool] to [target].", \ + "You start attaching \the [tool] to [target].") + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/robot_parts/L = tool + user.visible_message("[user] has attached \the [tool] to [target].", \ + "You have attached \the [tool] to [target].") + + if(L.part) + for(var/part_name in L.part) + if(!isnull(target.get_organ(part_name))) + continue + var/list/organ_data = target.species.has_limbs["[part_name]"] + if(!organ_data) + continue + var/new_limb_type = organ_data["path"] + var/obj/item/organ/external/new_limb = new new_limb_type(target) + new_limb.robotize(L.model_info) + if(L.sabotaged) + new_limb.sabotaged = 1 + + target.update_body() + target.updatehealth() + target.UpdateDamageIcon() + + qdel(tool) + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, damaging [target]'s flesh!", \ + "Your hand slips, damaging [target]'s flesh!") + target.apply_damage(10, BRUTE, null, sharp=1) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index f3d50555bb0..6fe84897c3b 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -178,75 +178,6 @@ if(I && I.damage > 0) I.take_damage(dam_amt,0) -/datum/surgery_step/internal/fix_organ_robotic //For artificial organs - allowed_tools = list( - /obj/item/stack/nanopaste = 100, \ - /obj/item/weapon/bonegel = 30, \ - /obj/item/weapon/screwdriver = 70, \ - ) - - min_duration = 70 - max_duration = 90 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - - if (!hasorgans(target)) - return - var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(!affected) return - var/is_organ_damaged = 0 - for(var/obj/item/organ/I in affected.internal_organs) - if(I.damage > 0 && I.robotic >= 2) - is_organ_damaged = 1 - break - return ..() && is_organ_damaged - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - - if (!hasorgans(target)) - return - var/obj/item/organ/external/affected = target.get_organ(target_zone) - - for(var/obj/item/organ/I in affected.internal_organs) - if(I && I.damage > 0) - if(I.robotic >= 2) - user.visible_message("[user] starts mending the damage to [target]'s [I.name]'s mechanisms.", \ - "You start mending the damage to [target]'s [I.name]'s mechanisms." ) - - target.custom_pain("The pain in your [affected.name] is living hell!",1) - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - - if (!hasorgans(target)) - return - var/obj/item/organ/external/affected = target.get_organ(target_zone) - - for(var/obj/item/organ/I in affected.internal_organs) - - if(I && I.damage > 0) - if(I.robotic >= 2) - user.visible_message("\blue [user] repairs [target]'s [I.name] with [tool].", \ - "\blue You repair [target]'s [I.name] with [tool]." ) - I.damage = 0 - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - - if (!hasorgans(target)) - return - var/obj/item/organ/external/affected = target.get_organ(target_zone) - - user.visible_message("\red [user]'s hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!", \ - "\red Your hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!") - - target.adjustToxLoss(5) - affected.createwound(CUT, 5) - - for(var/obj/item/organ/I in affected.internal_organs) - if(I) - I.take_damage(rand(3,5),0) - - /datum/surgery_step/internal/detatch_organ allowed_tools = list( @@ -262,13 +193,18 @@ if (!..()) return 0 + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + if(!(affected && !(affected.status & ORGAN_ROBOT))) + return 0 target.op_stage.current_organ = null var/list/attached_organs = list() for(var/organ in target.internal_organs_by_name) var/obj/item/organ/I = target.internal_organs_by_name[organ] - if(I && !I.status && I.parent_organ == target_zone) + if(I && !(I.status & ORGAN_CUT_AWAY) && I.parent_organ == target_zone) attached_organs |= organ var/organ_to_remove = input(user, "Which organ do you want to prepare for removal?") as null|anything in attached_organs @@ -323,7 +259,7 @@ var/list/removable_organs = list() for(var/organ in target.internal_organs_by_name) var/obj/item/organ/I = target.internal_organs_by_name[organ] - if(I.status & ORGAN_CUT_AWAY && I.parent_organ == target_zone) + if((I.status & ORGAN_CUT_AWAY) && I.parent_organ == target_zone) removable_organs |= organ var/organ_to_remove = input(user, "Which organ do you want to remove?") as null|anything in removable_organs @@ -352,8 +288,8 @@ fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("\red [user]'s hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!", \ - "\red Your hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!") + user.visible_message("\red [user]'s hand slips, damaging [target]'s [affected.name] with \the [tool]!", \ + "\red Your hand slips, damaging [target]'s [affected.name] with \the [tool]!") affected.createwound(BRUISE, 20) /datum/surgery_step/internal/replace_organ @@ -374,6 +310,10 @@ if(!istype(O)) return 0 + + if((affected.status & ORGAN_ROBOT) && !(O.status & ORGAN_ROBOT)) + user << "You cannot install a naked organ into a robotic body." + return 2 if(!target.species) user << "\red You have no idea what species this person is. Report this on the bug tracker." @@ -450,7 +390,7 @@ var/list/removable_organs = list() for(var/organ in target.internal_organs_by_name) var/obj/item/organ/I = target.internal_organs_by_name[organ] - if(I && I.status & ORGAN_CUT_AWAY && I.parent_organ == target_zone) + if(I && (I.status & ORGAN_CUT_AWAY) && !(I.status & ORGAN_ROBOT) && I.parent_organ == target_zone) removable_organs |= organ var/organ_to_replace = input(user, "Which organ do you want to reattach?") as null|anything in removable_organs diff --git a/code/modules/surgery/robolimbs.dm b/code/modules/surgery/robolimbs.dm deleted file mode 100644 index 17d92cf9b4e..00000000000 --- a/code/modules/surgery/robolimbs.dm +++ /dev/null @@ -1,60 +0,0 @@ -//Procedures in this file: Robotic limbs attachment -////////////////////////////////////////////////////////////////// -// LIMB SURGERY // -////////////////////////////////////////////////////////////////// - -/datum/surgery_step/limb/ - can_infect = 0 - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if (!hasorgans(target)) - return 0 - var/obj/item/organ/external/affected = target.get_organ(target_zone) - if (affected) - return 0 - var/list/organ_data = target.species.has_limbs["[target_zone]"] - return !isnull(organ_data) && !(target_zone in list("head","groin","chest")) - -/datum/surgery_step/limb/attach - allowed_tools = list(/obj/item/robot_parts = 100) - - min_duration = 80 - max_duration = 100 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if(..()) - var/obj/item/robot_parts/p = tool - if (p.part) - if (!(target_zone in p.part)) - return 0 - return isnull(target.get_organ(target_zone)) - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts attaching \the [tool] to [target].", \ - "You start attaching \the [tool] to [target].") - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/robot_parts/L = tool - user.visible_message("\blue [user] has attached \the [tool] to [target].", \ - "\blue You have attached \the [tool] to [target].") - - if(L.part) - for(var/part_name in L.part) - if(!isnull(target.get_organ(part_name))) continue - var/list/organ_data = target.species.has_limbs["[part_name]"] - if(!organ_data) continue - var/new_limb_type = organ_data["path"] - var/obj/item/organ/external/new_limb = new new_limb_type(target) - new_limb.robotize(L.model_info) - if(L.sabotaged) - new_limb.sabotaged = 1 - - target.update_body() - target.updatehealth() - target.UpdateDamageIcon() - - qdel(tool) - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, damaging [target]'s flesh!", \ - "\red Your hand slips, damaging [target]'s flesh!") - target.apply_damage(10, BRUTE, null, sharp=1) diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm new file mode 100644 index 00000000000..f0da9944abf --- /dev/null +++ b/code/modules/surgery/robotics.dm @@ -0,0 +1,430 @@ +//Procedures in this file: Generic surgery steps for robots +////////////////////////////////////////////////////////////////// +// COMMON STEPS // +////////////////////////////////////////////////////////////////// + +/datum/surgery_step/robotics/ + can_infect = 0 + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (isslime(target)) + return 0 + if (target_zone == "eyes") //there are specific steps for eye surgery + return 0 + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if (affected == null) + return 0 + if (affected.status & ORGAN_DESTROYED) + return 0 + if (!(affected.status & ORGAN_ROBOT)) + return 0 + return 1 + +/datum/surgery_step/robotics/unscrew_hatch + allowed_tools = list( + /obj/item/weapon/screwdriver = 100, + /obj/item/weapon/coin = 50, + /obj/item/weapon/kitchen/utensil/knife = 50 + ) + + min_duration = 90 + max_duration = 110 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.open == 0 && target_zone != "mouth" + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts to unscrew the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ + "You start to unscrew the maintenance hatch on [target]'s [affected.name] with \the [tool].") + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\blue [user] has opened the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ + "\blue You have opened the maintenance hatch on [target]'s [affected.name] with \the [tool].",) + affected.open = 1 + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\red [user]'s [tool.name] slips, failing to unscrew [target]'s [affected.name].", \ + "\red Your [tool] slips, failing to unscrew [target]'s [affected.name].") + +/datum/surgery_step/robotics/open_hatch + allowed_tools = list( + /obj/item/weapon/retractor = 100, + /obj/item/weapon/crowbar = 100, + /obj/item/weapon/kitchen/utensil/ = 50 + ) + + min_duration = 30 + max_duration = 40 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.open == 1 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts to pry open the maintenance hatch on [target]'s [affected.name] with \the [tool].", + "You start to pry open the maintenance hatch on [target]'s [affected.name] with \the [tool].") + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\blue [user] opens the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ + "\blue You open the maintenance hatch on [target]'s [affected.name] with \the [tool]." ) + affected.open = 2 + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\red [user]'s [tool.name] slips, failing to open the hatch on [target]'s [affected.name].", + "\red Your [tool] slips, failing to open the hatch on [target]'s [affected.name].") + +/datum/surgery_step/robotics/close_hatch + allowed_tools = list( + /obj/item/weapon/retractor = 100, + /obj/item/weapon/crowbar = 100, + /obj/item/weapon/kitchen/utensil = 50 + ) + + min_duration = 70 + max_duration = 100 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && affected.open && target_zone != "mouth" + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] begins to close and secure the hatch on [target]'s [affected.name] with \the [tool]." , \ + "You begin to close and secure the hatch on [target]'s [affected.name] with \the [tool].") + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\blue [user] closes and secures the hatch on [target]'s [affected.name] with \the [tool].", \ + "\blue You close and secure the hatch on [target]'s [affected.name] with \the [tool].") + affected.open = 0 + affected.germ_level = 0 + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\red [user]'s [tool.name] slips, failing to close the hatch on [target]'s [affected.name].", + "\red Your [tool.name] slips, failing to close the hatch on [target]'s [affected.name].") + +/datum/surgery_step/robotics/repair_brute + allowed_tools = list( + /obj/item/weapon/weldingtool = 100, + /obj/item/weapon/gun/energy/plasmacutter = 50 + ) + + min_duration = 50 + max_duration = 60 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(istype(tool,/obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/welder = tool + if(!welder.isOn() || !welder.remove_fuel(1,user)) + return 0 + return affected && affected.open == 2 && affected.brute_dam > 0 && target_zone != "mouth" + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] begins to patch damage to [target]'s [affected.name]'s support structure with \the [tool]." , \ + "You begin to patch damage to [target]'s [affected.name]'s support structure with \the [tool].") + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\blue [user] finishes patching damage to [target]'s [affected.name] with \the [tool].", \ + "\blue You finish patching damage to [target]'s [affected.name] with \the [tool].") + affected.heal_damage(rand(30,50),0,1,1) + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\red [user]'s [tool.name] slips, damaging the internal structure of [target]'s [affected.name].", + "\red Your [tool.name] slips, damaging the internal structure of [target]'s [affected.name].") + target.apply_damage(rand(5,10), BURN, affected) + +/datum/surgery_step/robotics/repair_burn + allowed_tools = list( + /obj/item/stack/cable_coil = 100 + ) + + min_duration = 50 + max_duration = 60 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/stack/cable_coil/C = tool + var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/limb_can_operate = (affected && affected.open == 2 && affected.burn_dam > 0 && target_zone != "mouth") + if(limb_can_operate) + if(istype(C)) + if(!C.get_amount() >= 3) + user << "You need three or more cable pieces to repair this damage." + return 2 + C.use(3) + return 1 + return 0 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] begins to splice new cabling into [target]'s [affected.name]." , \ + "You begin to splice new cabling into [target]'s [affected.name].") + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\blue [user] finishes splicing cable into [target]'s [affected.name].", \ + "\blue You finishes splicing new cable into [target]'s [affected.name].") + affected.heal_damage(0,rand(30,50),1,1) + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\red [user] causes a short circuit in [target]'s [affected.name]!", + "\red You cause a short circuit in [target]'s [affected.name]!") + target.apply_damage(rand(5,10), BURN, affected) + +/datum/surgery_step/robotics/fix_organ_robotic //For artificial organs + allowed_tools = list( + /obj/item/stack/nanopaste = 100, \ + /obj/item/weapon/bonegel = 30, \ + /obj/item/weapon/screwdriver = 70, \ + ) + + min_duration = 70 + max_duration = 90 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!affected) return + var/is_organ_damaged = 0 + for(var/obj/item/organ/I in affected.internal_organs) + if(I.damage > 0 && I.robotic >= 2) + is_organ_damaged = 1 + break + return affected.open == 2 && is_organ_damaged + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + for(var/obj/item/organ/I in affected.internal_organs) + if(I && I.damage > 0) + if(I.robotic >= 2) + user.visible_message("[user] starts mending the damage to [target]'s [I.name]'s mechanisms.", \ + "You start mending the damage to [target]'s [I.name]'s mechanisms." ) + + target.custom_pain("The pain in your [affected.name] is living hell!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + for(var/obj/item/organ/I in affected.internal_organs) + + if(I && I.damage > 0) + if(I.robotic >= 2) + user.visible_message("\blue [user] repairs [target]'s [I.name] with [tool].", \ + "\blue You repair [target]'s [I.name] with [tool]." ) + I.damage = 0 + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("\red [user]'s hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!", \ + "\red Your hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!") + + target.adjustToxLoss(5) + affected.createwound(CUT, 5) + + for(var/obj/item/organ/I in affected.internal_organs) + if(I) + I.take_damage(rand(3,5),0) + +/datum/surgery_step/robotics/detatch_organ_robotic + + allowed_tools = list( + /obj/item/device/multitool = 100 + ) + + min_duration = 90 + max_duration = 110 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!(affected && (affected.status & ORGAN_ROBOT))) + return 0 + if(affected.open != 2) + return 0 + + target.op_stage.current_organ = null + + var/list/attached_organs = list() + for(var/organ in target.internal_organs_by_name) + var/obj/item/organ/I = target.internal_organs_by_name[organ] + if(I && !(I.status & ORGAN_CUT_AWAY) && I.parent_organ == target_zone) + attached_organs |= organ + + var/organ_to_remove = input(user, "Which organ do you want to prepare for removal?") as null|anything in attached_organs + if(!organ_to_remove) + return 0 + + target.op_stage.current_organ = organ_to_remove + + return ..() && organ_to_remove + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts to decouple [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You start to decouple [target]'s [target.op_stage.current_organ] with \the [tool]." ) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\blue [user] has decoupled [target]'s [target.op_stage.current_organ] with \the [tool]." , \ + "\blue You have decoupled [target]'s [target.op_stage.current_organ] with \the [tool].") + + var/obj/item/organ/I = target.internal_organs_by_name[target.op_stage.current_organ] + if(I && istype(I)) + I.status |= ORGAN_CUT_AWAY + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\red [user]'s hand slips, disconnecting \the [tool].", \ + "\red Your hand slips, disconnecting \the [tool].") + +/datum/surgery_step/robotics/attach_organ_robotic + allowed_tools = list( + /obj/item/weapon/screwdriver = 100, + ) + + min_duration = 100 + max_duration = 120 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!(affected && (affected.status & ORGAN_ROBOT))) + return 0 + if(affected.open != 2) + return 0 + + target.op_stage.current_organ = null + + var/list/removable_organs = list() + for(var/organ in target.internal_organs_by_name) + var/obj/item/organ/I = target.internal_organs_by_name[organ] + if(I && (I.status & ORGAN_CUT_AWAY) && (I.status & ORGAN_ROBOT) && I.parent_organ == target_zone) + removable_organs |= organ + + var/organ_to_replace = input(user, "Which organ do you want to reattach?") as null|anything in removable_organs + if(!organ_to_replace) + return 0 + + target.op_stage.current_organ = organ_to_replace + return ..() + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] begins reattaching [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You start reattaching [target]'s [target.op_stage.current_organ] with \the [tool].") + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\blue [user] has reattached [target]'s [target.op_stage.current_organ] with \the [tool]." , \ + "\blue You have reattached [target]'s [target.op_stage.current_organ] with \the [tool].") + + var/obj/item/organ/I = target.internal_organs_by_name[target.op_stage.current_organ] + if(I && istype(I)) + I.status &= ~ORGAN_CUT_AWAY + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\red [user]'s hand slips, disconnecting \the [tool].", \ + "\red Your hand slips, disconnecting \the [tool].") + +/datum/surgery_step/robotics/install_mmi + allowed_tools = list( + /obj/item/device/mmi = 100 + ) + + min_duration = 60 + max_duration = 80 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if(target_zone != "head") + return + + var/obj/item/device/mmi/M = tool + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(!(affected && affected.open == 2)) + return 0 + + if(!istype(M)) + return 0 + + if(!M.brainmob || !M.brainmob.client || !M.brainmob.ckey || M.brainmob.stat >= DEAD) + user << "That brain is not usable." + return 2 + + if(!(affected.status & ORGAN_ROBOT)) + user << "You cannot install a computer brain into a meat skull." + return 2 + + if(!target.species) + user << "You have no idea what species this person is. Report this on the bug tracker." + return 2 + + if(!target.species.has_organ["brain"]) + user << "You're pretty sure [target.species.name_plural] don't normally have a brain." + return 2 + + if(!isnull(target.internal_organs["brain"])) + user << "Your subject already has a brain." + return 2 + + return 1 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts installing \the [tool] into [target]'s [affected.name].", \ + "You start installing \the [tool] into [target]'s [affected.name].") + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\blue [user] has installed \the [tool] into [target]'s [affected.name].", \ + "\blue You have installed \the [tool] into [target]'s [affected.name].") + + var/obj/item/device/mmi/M = tool + var/obj/item/organ/mmi_holder/holder = new(target, 1) + target.internal_organs_by_name["brain"] = holder + user.unEquip(tool) + tool.loc = holder + holder.stored_mmi = tool + holder.update_from_mmi() + + if(M.brainmob && M.brainmob.mind) + M.brainmob.mind.transfer_to(target) + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\red [user]'s hand slips.", \ + "\red Your hand slips.") \ No newline at end of file diff --git a/code/modules/surgery/slime.dm b/code/modules/surgery/slime.dm index 048c6d3e3c1..02cf0219366 100644 --- a/code/modules/surgery/slime.dm +++ b/code/modules/surgery/slime.dm @@ -87,7 +87,6 @@ if(target.cores <= 0) target.icon_state = "[target.colour] baby slime dead-nocore" - fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) user.visible_message("\red [user]'s hand slips, causing \him to miss the core!", \ "\red Your hand slips, causing you to miss the core!") \ No newline at end of file diff --git a/code/modules/vehicle/train/train.dm b/code/modules/vehicle/train/train.dm index e180b52ee0f..aaf88bdbd18 100644 --- a/code/modules/vehicle/train/train.dm +++ b/code/modules/vehicle/train/train.dm @@ -55,7 +55,7 @@ if(istype(load, /mob/living/carbon/human)) var/mob/living/D = load D << "\red You hit [M]!" - msg_admin_attack("[D.name] ([D.ckey])[isAntag(D) ? "(ANTAG)" : ""] hit [M.name] ([M.ckey]) with [src]. (JMP)") + msg_admin_attack("[key_name_admin(D)] hit [key_name_admin(M)] with [src].") //------------------------------------------- diff --git a/code/modules/vehicle/train/trains/ambulance.dm b/code/modules/vehicle/train/trains/ambulance.dm index a6ba690d166..36baeecd86a 100644 --- a/code/modules/vehicle/train/trains/ambulance.dm +++ b/code/modules/vehicle/train/trains/ambulance.dm @@ -162,10 +162,10 @@ var/mob/living/carbon/human/D = load D << "\red \b You ran over [H]!" visible_message("\red \The [src] ran over [H]!") - attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey]), driven by [D.name] ([D.ckey])") - msg_admin_attack("[D.name] ([D.ckey])[isAntag(D) ? "(ANTAG)" : ""] ran over [H.name] ([H.ckey]). (JMP)") + attack_log += text("\[[time_stamp()]\] ran over [key_name(H)], driven by [key_name(D)]") + msg_admin_attack("[key_name_admin(D)] ran over [key_name_admin(H)]") else - attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])") + attack_log += text("\[[time_stamp()]\] ran over [key_name(H)]") //------------------------------------------- diff --git a/code/modules/vehicle/train/trains/cargo/cargo_train.dm b/code/modules/vehicle/train/trains/cargo/cargo_train.dm index 1daee673201..a8f50cd5463 100644 --- a/code/modules/vehicle/train/trains/cargo/cargo_train.dm +++ b/code/modules/vehicle/train/trains/cargo/cargo_train.dm @@ -144,7 +144,7 @@ /obj/vehicle/train/cargo/trolley/RunOver(var/mob/living/carbon/human/H) ..() - attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])") + attack_log += text("\[[time_stamp()]\] ran over [key_name(H)]") /obj/vehicle/train/cargo/engine/RunOver(var/mob/living/carbon/human/H) ..() @@ -153,10 +153,10 @@ var/mob/living/carbon/human/D = load D << "\red \b You ran over [H]!" visible_message("\red \The [src] ran over [H]!") - attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey]), driven by [D.name] ([D.ckey])") - msg_admin_attack("[D.name] ([D.ckey])[isAntag(D) ? "(ANTAG)" : ""] ran over [H.name] ([H.ckey]). (JMP)") + attack_log += text("\[[time_stamp()]\] ran over [key_name(H)], driven by [key_name(D)]") + msg_admin_attack("[key_name_admin(D)] ran over [key_name_admin(H)]") else - attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])") + attack_log += text("\[[time_stamp()]\] ran over [key_name(H)]") //------------------------------------------- diff --git a/code/modules/vehicle/train/trains/janicart.dm b/code/modules/vehicle/train/trains/janicart.dm index 11fdf993b0b..0894d1b9e44 100644 --- a/code/modules/vehicle/train/trains/janicart.dm +++ b/code/modules/vehicle/train/trains/janicart.dm @@ -212,10 +212,10 @@ var/mob/living/carbon/human/D = load D << "\red \b You ran over [H]!" visible_message("\red \The [src] ran over [H]!") - attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey]), driven by [D.name] ([D.ckey])") - msg_admin_attack("[D.name] ([D.ckey])[isAntag(D) ? "(ANTAG)" : ""] ran over [H.name] ([H.ckey]). (JMP)") + attack_log += text("\[[time_stamp()]\] ran over [key_name(H)], driven by [key_name(D)]") + msg_admin_attack("[key_name_admin(D)] ran over [key_name_admin(H)]") else - attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])") + attack_log += text("\[[time_stamp()]\] ran over [key_name(H)]") //------------------------------------------- diff --git a/code/modules/virus2/disease2.dm b/code/modules/virus2/disease2.dm index a72b66e88e1..f685bbe2b12 100644 --- a/code/modules/virus2/disease2.dm +++ b/code/modules/virus2/disease2.dm @@ -40,7 +40,7 @@ var/list/res = list() for (var/specie in all_species) var/datum/species/S = all_species[specie] - if(!(S.flags & IS_SYNTHETIC)) + if(!(S.virus_immune)) meat += S.name if(meat.len) var/num = rand(1,meat.len) @@ -58,10 +58,11 @@ if(mob.stat == 2) return - var/mob/living/carbon/human/MS = mob - if(istype(MS)) - if(MS.species.flags & IS_SYNTHETIC) - return + // Some species are flat out immune to organic viruses. + var/mob/living/carbon/human/H = mob + if(istype(H) && H.species.virus_immune) + cure(mob) + return if(stage <= 1 && clicks == 0) // with a certain chance, the mob may become immune to the disease before it starts properly if(prob(5)) diff --git a/code/modules/virus2/helpers.dm b/code/modules/virus2/helpers.dm index cfc6bd1bdb6..91a287044e9 100644 --- a/code/modules/virus2/helpers.dm +++ b/code/modules/virus2/helpers.dm @@ -3,6 +3,11 @@ proc/get_infection_chance(var/mob/living/carbon/M, var/vector = "Airborne") var/score = 0 if (!istype(M)) return 0 + + var/mob/living/carbon/human/H = M + if(istype(H) && H.species.virus_immune) + return 0 + if(istype(M, /mob/living/carbon/human)) if (vector == "Airborne") if(M.internal) //not breathing infected air helps greatly diff --git a/code/world.dm b/code/world.dm index 2adf9da3032..a26b926ef9a 100644 --- a/code/world.dm +++ b/code/world.dm @@ -68,7 +68,7 @@ var/global/datum/global_init/init = new () processScheduler.setup() master_controller.setup() - + #ifdef MAP_NAME map_name = "[MAP_NAME]" #else @@ -267,13 +267,13 @@ var/world_topic_spam_protect_time = world.timeofday sleep(600) if(!C.client && C.stat != DEAD && C.brain_op_stage!=4.0) job_master.FreeRole(C.job) - message_admins("[C.name] ([C.ckey]), the [C.job] has been freed due to (Client disconnect for 10 minutes)\n") + message_admins("[key_name_admin(C)], the [C.job] has been freed due to (Client disconnect for 10 minutes)\n") for(var/obj/item/W in C) C.unEquip(W) del(C) else if(!C.key && C.stat != DEAD && C.brain_op_stage!=4.0) job_master.FreeRole(C.job) - message_admins("[C.name] ([C.ckey]), the [C.job] has been freed due to (Client quit BYOND)\n") + message_admins("[key_name_admin(C)], the [C.job] has been freed due to (Client quit BYOND)\n") for(var/obj/item/W in C) C.unEquip(W) del(C) diff --git a/config/example/dbconfig.txt b/config/example/dbconfig.txt index 4bb4e58b096..01d38fd1c56 100644 --- a/config/example/dbconfig.txt +++ b/config/example/dbconfig.txt @@ -20,6 +20,8 @@ PASSWORD mypassword FEEDBACK_DATABASE paradise FEEDBACK_LOGIN mylogin FEEDBACK_PASSWORD mypassword +# Table prefix - make sure you properly prefix the tables currently marked as erro_ in the .sql file as this is not fully implemented +FEEDBACK_TABLEPREFIX erro # Track population and death statistics # Comment this out to disable diff --git a/html/create_object.html b/html/create_object.html index a1f115b7839..ac47cc7769b 100644 --- a/html/create_object.html +++ b/html/create_object.html @@ -27,7 +27,7 @@
- Type
+ Type
Offset: A @@ -39,12 +39,12 @@ Where:


- +