diff --git a/_maps/map_files/tgstation.2.1.3.dmm b/_maps/map_files/tgstation.2.1.3.dmm index 4bd259aa73a..d52354c6d5e 100644 --- a/_maps/map_files/tgstation.2.1.3.dmm +++ b/_maps/map_files/tgstation.2.1.3.dmm @@ -393,7 +393,7 @@ "ahC" = (/obj/machinery/seed_extractor,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/prison) "ahD" = (/turf/simulated/floor{icon_state = "red"; dir = 1},/area/security/brig) "ahE" = (/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/security/prison) -"ahF" = (/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/manifold/supply/hidden{tag = "icon-manifold-b-f (NORTH)"; dir = 1},/turf/simulated/floor/plating,/area/maintenance/fsmaint) +"ahF" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 5},/obj/machinery/meter,/turf/simulated/floor/plating,/area/maintenance/fsmaint) "ahG" = (/obj/item/weapon/wrench,/obj/machinery/atmospherics/pipe/manifold/supply/hidden{tag = "icon-manifold-b-f (EAST)"; dir = 4},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 4},/area/maintenance/fsmaint) "ahH" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor{dir = 8; icon_state = "redcorner"},/area/hallway/primary/fore) "ahI" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = "90Curve"},/obj/machinery/camera{c_tag = "Labor Shuttle Dock South"; dir = 1},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 9},/turf/simulated/floor{icon_state = "red"; dir = 6},/area/security/processing) @@ -640,7 +640,7 @@ "amp" = (/turf/simulated/floor{icon_state = "whitehall"; dir = 2},/area/security/prison) "amq" = (/obj/structure/extinguisher_cabinet{pixel_x = 1; pixel_y = -27},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor{icon_state = "whitehall"; dir = 2},/area/security/prison) "amr" = (/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/fsmaint) -"ams" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 5},/turf/simulated/floor/plating,/area/maintenance/fsmaint) +"ams" = (/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/manifold/supply/hidden{tag = "icon-manifold-b-f (NORTH)"; dir = 1},/obj/machinery/meter,/turf/simulated/floor/plating,/area/maintenance/fsmaint) "amt" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/plating{icon_state = "warnplate"},/area/security/prison) "amu" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/wall,/area/maintenance/fsmaint) "amv" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 10},/turf/simulated/wall,/area/maintenance/fsmaint) @@ -786,9 +786,9 @@ "apf" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "apg" = (/obj/machinery/door/airlock/external{name = "External Access"; req_access = null; req_access_txt = "13"},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aph" = (/obj/structure/stool,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/fpmaint2) -"api" = (/obj/machinery/atmospherics/pipe/simple/general/visible{dir = 5},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"api" = (/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (NORTHEAST)"; icon_state = "intact"; dir = 5},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "apj" = (/obj/machinery/atmospherics/valve{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) -"apk" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 10},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"apk" = (/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (SOUTHWEST)"; icon_state = "intact"; dir = 10},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "apl" = (/obj/structure/closet,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "apm" = (/obj/structure/closet/emcloset,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "apn" = (/obj/machinery/power/apc{dir = 1; name = "Arrivals North Maintenance APC"; pixel_x = -1; pixel_y = 26},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) @@ -898,7 +898,7 @@ "arn" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aro" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "arp" = (/obj/structure/table,/obj/item/weapon/kitchen/utensil/fork,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "bar"},/area/crew_quarters/bar) -"arq" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"arq" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (EAST)"; icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "arr" = (/obj/structure/stool{pixel_y = 8},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "bar"},/area/crew_quarters/bar) "ars" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "bar"},/area/crew_quarters/bar) "art" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) @@ -1078,7 +1078,7 @@ "auL" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 6},/turf/simulated/floor{icon_state = "dark"},/area/chapel/office) "auM" = (/obj/structure/table,/obj/item/weapon/shard,/obj/item/weapon/shard{icon_state = "medium"},/obj/item/weapon/shard{icon_state = "small"},/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "auN" = (/obj/machinery/light/small{dir = 4},/obj/structure/stool,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) -"auO" = (/turf/simulated/floor{icon_state = "red"; dir = 8},/area/security/checkpoint2) +"auO" = (/obj/structure/closet,/obj/item/weapon/crowbar,/obj/item/device/flash/handheld,/turf/simulated/floor{icon_state = "red"; dir = 8},/area/security/checkpoint2) "auP" = (/obj/structure/disposalpipe/segment,/obj/machinery/door/airlock/maintenance{name = "Hydroponics Maintenance"; req_access_txt = "35"},/turf/simulated/floor/plating,/area/hydroponics) "auQ" = (/obj/machinery/navbeacon{codes_txt = "delivery;dir=2"; freq = 1400; location = "Kitchen"},/obj/structure/plasticflaps{opacity = 1},/turf/simulated/floor{dir = 2; icon_state = "bot"},/area/crew_quarters/kitchen) "auR" = (/obj/machinery/door/airlock/maintenance{name = "Kitchen Maintenance"; req_access_txt = "28"},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/crew_quarters/kitchen) @@ -1566,8 +1566,8 @@ "aEf" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aEg" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 10},/turf/simulated/wall,/area/maintenance/fpmaint2) "aEh" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor,/area/hallway/primary/port) -"aEi" = (/obj/item/weapon/paper,/obj/structure/table/reinforced,/obj/machinery/door/window/brigdoor{dir = 1; name = "Arrivals Security Checkpoint"; pixel_y = -32; req_access_txt = "1"},/turf/simulated/floor{icon_state = "red"},/area/security/checkpoint2) -"aEj" = (/obj/machinery/recharger{pixel_y = 4},/obj/structure/table/reinforced,/turf/simulated/floor{icon_state = "red"},/area/security/checkpoint2) +"aEi" = (/obj/machinery/recharger{pixel_y = 4},/obj/structure/table/reinforced,/turf/simulated/floor{icon_state = "red"},/area/security/checkpoint2) +"aEj" = (/obj/item/device/radio/off,/turf/simulated/floor{icon_state = "red"; dir = 6},/area/security/checkpoint2) "aEk" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/wall,/area/maintenance/fpmaint2) "aEl" = (/obj/structure/table,/obj/item/weapon/minihoe,/obj/item/weapon/hatchet,/obj/item/weapon/crowbar,/obj/item/device/analyzer/plant_analyzer,/obj/item/weapon/reagent_containers/glass/bucket,/turf/simulated/floor{icon_state = "green"; dir = 4},/area/hallway/secondary/construction{name = "\improper Garden"}) "aEm" = (/obj/machinery/atmospherics/pipe/manifold/supply/hidden{tag = "icon-manifold-b-f (NORTH)"; dir = 1},/turf/simulated/wall,/area/maintenance/fpmaint2) @@ -1616,7 +1616,7 @@ "aFd" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aFe" = (/obj/machinery/light_switch{pixel_x = 27},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "freezerfloor"},/area/crew_quarters/toilet) "aFf" = (/obj/structure/table/woodentable,/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/wood,/area/security/vacantoffice) -"aFg" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/manifold/supply/hidden{tag = "icon-manifold-b-f (WEST)"; dir = 8},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"aFg" = (/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (NORTHEAST)"; icon_state = "intact"; dir = 5},/turf/simulated/wall,/area/maintenance/fpmaint2) "aFh" = (/obj/machinery/power/apc{dir = 1; name = "Law Office APC"; pixel_y = 24},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/plating,/area/lawoffice) "aFi" = (/obj/machinery/power/apc{dir = 8; name = "Detective APC"; pixel_x = -24},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/security/detectives_office) "aFj" = (/obj/machinery/light_switch{pixel_y = 28},/obj/machinery/light{dir = 1},/obj/structure/table/woodentable,/obj/item/weapon/lipstick,/turf/simulated/floor/wood,/area/crew_quarters/theatre) @@ -1685,7 +1685,7 @@ "aGu" = (/obj/structure/table,/obj/item/weapon/weldingtool,/obj/item/weapon/crowbar,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/turf/simulated/floor,/area/storage/primary) "aGv" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 6},/turf/simulated/wall,/area/maintenance/fpmaint2) "aGw" = (/obj/machinery/light/small{dir = 1},/obj/machinery/alarm{pixel_y = 23},/turf/simulated/floor{icon_state = "vault"},/area/ai_monitored/nuke_storage) -"aGx" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 5},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"aGx" = (/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (EAST)"; icon_state = "intact"; dir = 4},/turf/simulated/wall,/area/maintenance/fpmaint2) "aGy" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aGz" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'HIGH VOLTAGE'"; icon_state = "shock"; name = "HIGH VOLTAGE"; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/wall,/area/maintenance/electrical) "aGA" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/maintenance/fsmaint2) @@ -1869,7 +1869,7 @@ "aJW" = (/turf/simulated/floor{icon_state = "neutral"; dir = 4},/area/hallway/primary/central) "aJX" = (/obj/structure/table/woodentable,/obj/structure/mirror{pixel_x = -28},/obj/item/weapon/lipstick/random,/turf/simulated/floor{icon_state = "whitehall"; dir = 4},/area/crew_quarters/theatre) "aJY" = (/turf/simulated/floor/wood,/area/crew_quarters/theatre) -"aJZ" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/meter,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"aJZ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (EAST)"; icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aKa" = (/obj/structure/closet/lasertag/blue,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/crew_quarters/fitness) "aKb" = (/obj/structure/closet/lasertag/red,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 10},/turf/simulated/floor{icon_state = "neutral"; dir = 5},/area/crew_quarters/fitness) "aKc" = (/turf/simulated/floor{icon_state = "bar"},/area/crew_quarters/bar) @@ -1925,12 +1925,12 @@ "aLa" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor,/area/hallway/primary/port) "aLb" = (/obj/machinery/light{dir = 1},/obj/structure/sign/securearea{desc = "A warning sign which reads 'HIGH VOLTAGE'"; icon_state = "shock"; name = "HIGH VOLTAGE"; pixel_y = 32},/turf/simulated/floor{icon_state = "warningcorner"; dir = 8},/area/hallway/primary/port) "aLc" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 6},/turf/simulated/wall,/area/lawoffice) -"aLd" = (/obj/effect/spawner/lootdrop/maintenance{lootcount = 2; name = "2maintenance loot spawner"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 10},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"aLd" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (EAST)"; icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aLe" = (/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/hallway/primary/port) -"aLf" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor/plating{tag = "icon-platingdmg3"; icon_state = "platingdmg3"},/area/maintenance/fpmaint2) +"aLf" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (EAST)"; icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aLg" = (/obj/machinery/atmospherics/unary/vent_scrubber{on = 1; scrub_N2O = 0; scrub_Toxins = 0},/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/hallway/primary/port) "aLh" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'HIGH VOLTAGE'"; icon_state = "shock"; name = "HIGH VOLTAGE"; pixel_y = 32},/turf/simulated/floor{icon_state = "warningcorner"; dir = 4},/area/hallway/primary/port) -"aLi" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"aLi" = (/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (EAST)"; icon_state = "intact"; dir = 4},/turf/simulated/floor/plating{tag = "icon-platingdmg3"; icon_state = "platingdmg3"},/area/maintenance/fpmaint2) "aLj" = (/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/unary/vent_pump{dir = 8; on = 1},/turf/simulated/floor{icon_state = "warningcorner"; dir = 8},/area/hallway/primary/port) "aLk" = (/obj/machinery/door/firedoor/border_only{dir = 4; name = "Firelock East"},/turf/simulated/floor{icon_state = "warningcorner"; dir = 4},/area/hallway/primary/port) "aLl" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/obj/machinery/door/airlock/glass{name = "Central Access"},/turf/simulated/floor,/area/hallway/primary/central) @@ -1958,11 +1958,11 @@ "aLH" = (/obj/structure/piano,/turf/simulated/floor/wood,/area/crew_quarters/theatre) "aLI" = (/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aLJ" = (/obj/structure/stool{pixel_y = 8},/turf/simulated/floor{icon_state = "bar"},/area/crew_quarters/bar) -"aLK" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"aLK" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (EAST)"; icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aLL" = (/obj/structure/disposalpipe/segment,/obj/effect/landmark{name = "xeno_spawn"; pixel_x = -1},/turf/simulated/floor/wood,/area/crew_quarters/bar) "aLM" = (/obj/machinery/vending/cola,/turf/simulated/floor/wood,/area/crew_quarters/bar) "aLN" = (/obj/machinery/vending/coffee,/turf/simulated/floor/wood,/area/crew_quarters/bar) -"aLO" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"aLO" = (/obj/effect/spawner/lootdrop/maintenance{lootcount = 2; name = "2maintenance loot spawner"},/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (SOUTHWEST)"; icon_state = "intact"; dir = 10},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aLP" = (/turf/simulated/floor,/area/crew_quarters/fitness) "aLQ" = (/obj/machinery/chem_master/condimaster{name = "CondiMaster Neo"},/obj/machinery/camera{c_tag = "Kitchen Cold Room"},/turf/simulated/floor{icon_state = "showroomfloor"},/area/crew_quarters/kitchen) "aLR" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor{icon_state = "red"; dir = 4},/area/crew_quarters/fitness) @@ -2062,7 +2062,6 @@ "aNH" = (/obj/machinery/camera{c_tag = "Port Hallway 3"; dir = 1},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/hallway/primary/port) "aNI" = (/obj/structure/disposalpipe/junction{icon_state = "pipe-j1"; dir = 4},/turf/simulated/floor,/area/hallway/primary/port) "aNJ" = (/obj/structure/disposalpipe/junction{icon_state = "pipe-j2"; dir = 4},/turf/simulated/floor,/area/hallway/primary/port) -"aNK" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 4; on = 1},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/hallway/primary/port) "aNL" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/maintenance/port) "aNM" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 1; external_pressure_bound = 101.325; on = 1; pressure_checks = 1},/turf/simulated/floor{icon_state = "barber"},/area/crew_quarters/locker) "aNN" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor{dir = 8; icon_state = "warning"},/area/crew_quarters/locker) @@ -2276,7 +2275,7 @@ "aRN" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/wall,/area/library) "aRO" = (/obj/structure/table,/obj/item/stack/sheet/glass{amount = 50},/obj/item/stack/rods{amount = 50},/turf/simulated/floor,/area/storage/tools) "aRP" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/storage/tools) -"aRQ" = (/obj/item/weapon/crowbar,/obj/item/device/flash/handheld,/turf/simulated/floor{icon_state = "red"; dir = 6},/area/security/checkpoint2) +"aRQ" = (/obj/item/weapon/paper,/obj/structure/table/reinforced,/obj/machinery/door/window/brigdoor{dir = 2; name = "Arrivals Security Checkpoint"; pixel_y = -8; req_access_txt = "1"},/turf/simulated/floor{icon_state = "red"},/area/security/checkpoint2) "aRR" = (/turf/simulated/floor{dir = 1; icon_state = "yellowcorner"},/area/bridge) "aRS" = (/obj/structure/stool/bed/chair{dir = 1; name = "Engineering Station"},/turf/simulated/floor,/area/bridge) "aRT" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/turf/simulated/floor{dir = 4; icon_state = "yellowcorner"},/area/bridge) @@ -2372,7 +2371,7 @@ "aTF" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/closet,/obj/item/clothing/under/suit_jacket/female{pixel_x = 3; pixel_y = 1},/obj/item/clothing/under/suit_jacket/really_black{pixel_x = -2; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor{icon_state = "barber"},/area/crew_quarters/locker) "aTG" = (/obj/structure/table,/obj/item/stack/sheet/rglass{amount = 50},/obj/item/stack/sheet/rglass{amount = 50},/obj/item/stack/rods{amount = 50},/obj/item/stack/rods{amount = 50},/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor{dir = 8; icon_state = "warning"},/area/ai_monitored/storage/eva) "aTH" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/machinery/atmospherics/pipe/manifold/supply/hidden{tag = "icon-manifold-b-f (NORTH)"; dir = 1},/turf/simulated/floor{icon_state = "freezerfloor"},/area/crew_quarters/toilet) -"aTI" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/plating,/area/maintenance/port) +"aTI" = (/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{tag = "icon-intact (NORTH)"; icon_state = "intact"; dir = 1},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "aTJ" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor{icon_state = "cafeteria"},/area/crew_quarters/kitchen) "aTK" = (/obj/structure/table,/obj/item/weapon/storage/toolbox/mechanical{pixel_x = -2; pixel_y = -1},/obj/machinery/light{dir = 4},/turf/simulated/floor,/area/storage/primary) "aTL" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; on = 1},/turf/simulated/floor,/area/storage/primary) @@ -3195,7 +3194,7 @@ "bjw" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/medical/chemistry) "bjx" = (/obj/structure/sign/atmosplaque{pixel_x = 0; pixel_y = -32},/obj/structure/table,/obj/item/weapon/storage/box,/obj/item/weapon/storage/box,/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor,/area/atmos) "bjy" = (/obj/effect/spawner/lootdrop/maintenance,/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/maintenance/asmaint2) -"bjz" = (/obj/machinery/meter,/turf/simulated/floor/plating,/area/maintenance/asmaint2) +"bjz" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/manifold/supplymain/hidden{tag = "icon-manifold (WEST)"; icon_state = "manifold"; dir = 8},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) "bjA" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor{dir = 2; icon_state = "whiteblue"},/area/medical/medbay) "bjB" = (/obj/machinery/door/airlock/research{name = "Testing Lab"; req_access_txt = "47"},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor{icon_state = "white"},/area/toxins/misc_lab) "bjC" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/toxins/misc_lab) @@ -3312,7 +3311,7 @@ "blJ" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/plating,/area/quartermaster/storage) "blK" = (/obj/structure/closet/emcloset,/turf/simulated/floor{dir = 8; icon_state = "warning"},/area/quartermaster/storage) "blL" = (/obj/structure/closet/emcloset,/obj/machinery/alarm{dir = 2; pixel_y = 24},/turf/simulated/floor,/area/quartermaster/storage) -"blM" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/plating,/area/maintenance/fpmaint2) +"blM" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{dir = 5},/turf/simulated/floor/plating/airless,/area/space) "blN" = (/obj/structure/closet/secure_closet/security,/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor{icon_state = "red"; dir = 9},/area/security/checkpoint2) "blO" = (/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{tag = "icon-manifold-r-f (EAST)"; dir = 4},/turf/simulated/floor{icon_state = "red"; dir = 1},/area/security/checkpoint2) "blP" = (/obj/machinery/computer/security,/obj/structure/reagent_dispensers/peppertank{pixel_x = 0; pixel_y = 30},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor{icon_state = "red"; dir = 1},/area/security/checkpoint2) @@ -3643,7 +3642,7 @@ "bsc" = (/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{tag = "icon-manifold-r-f (WEST)"; dir = 8},/turf/simulated/floor{dir = 9; icon_state = "whitehall"},/area/medical/research{name = "Research Division"}) "bsd" = (/obj/structure/sign/nosmoking_2{pixel_x = -32},/turf/simulated/floor{dir = 5; icon_state = "whitehall"},/area/medical/research{name = "Research Division"}) "bse" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor{icon_state = "bot"},/area/toxins/storage) -"bsf" = (/obj/machinery/meter,/turf/simulated/floor/plating,/area/maintenance/asmaint) +"bsf" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{dir = 4},/turf/simulated/floor/plating/airless,/area/space) "bsg" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor,/area/hallway/primary/aft) "bsh" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{tag = "icon-manifold-r-f (WEST)"; dir = 8},/turf/simulated/floor{dir = 8; icon_state = "cautioncorner"},/area/hallway/primary/aft) "bsi" = (/obj/structure/table,/obj/item/weapon/storage/box/disks{pixel_x = 2; pixel_y = 2},/turf/simulated/floor{icon_state = "white"},/area/medical/genetics) @@ -5003,7 +5002,7 @@ "bSk" = (/obj/machinery/atmospherics/pipe/simple/green/visible{dir = 5; initialize_directions = 12},/turf/simulated/floor,/area/atmos) "bSl" = (/obj/machinery/atmospherics/binary/pump{dir = 1; name = "Unfiltered to Mix"; on = 1},/obj/machinery/atmospherics/pipe/simple/green/visible{dir = 4; initialize_directions = 12},/turf/simulated/floor,/area/atmos) "bSm" = (/obj/machinery/atmospherics/pipe/simple/green/visible{dir = 4},/turf/simulated/floor{icon_state = "green"; dir = 6},/area/atmos) -"bSn" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/asmaint) +"bSn" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{dir = 4},/turf/simulated/floor/plating,/area/maintenance/incinerator) "bSo" = (/obj/structure/lattice,/obj/machinery/atmospherics/pipe/simple/green/visible{dir = 4},/turf/space,/area/space) "bSp" = (/obj/machinery/atmospherics/unary/outlet_injector/on{dir = 8; frequency = 1441; id = "waste_in"; pixel_y = 1},/turf/simulated/floor/engine{name = "vacuum floor"; nitrogen = 0.01; oxygen = 0.01},/area/atmos) "bSq" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/asmaint) @@ -5136,12 +5135,12 @@ "bUN" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/asmaint) "bUO" = (/obj/structure/disposalpipe/trunk{dir = 4},/obj/structure/disposaloutlet{dir = 8},/turf/simulated/floor/plating/airless,/area/space) "bUP" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating/airless,/area/space) -"bUQ" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/insulated{dir = 5},/turf/simulated/floor/plating/airless,/area/space) -"bUR" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/general/visible{dir = 4},/turf/simulated/floor/plating/airless,/area/space) +"bUQ" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/reagent_dispensers/fueltank,/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{tag = "icon-intact (SOUTHWEST)"; icon_state = "intact"; dir = 10},/turf/simulated/floor/plating,/area/maintenance/incinerator) +"bUR" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/closet/emcloset,/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{dir = 4},/turf/simulated/floor/plating,/area/maintenance/incinerator) "bUS" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/binary/pump{dir = 8; name = "Gas Pump"; on = 1},/turf/simulated/floor/plating/airless,/area/space) -"bUT" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/general/visible{dir = 4},/turf/simulated/floor/plating,/area/maintenance/incinerator) -"bUU" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/general/visible{dir = 4},/obj/structure/closet/emcloset,/turf/simulated/floor/plating,/area/maintenance/incinerator) -"bUV" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/insulated{dir = 10},/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plating,/area/maintenance/incinerator) +"bUT" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,/turf/simulated/floor/plating,/area/maintenance/incinerator) +"bUU" = (/obj/machinery/atmospherics/pipe/simple/yellow/visible{dir = 4},/turf/simulated/wall/r_wall,/area/maintenance/incinerator) +"bUV" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,/obj/machinery/atmospherics/pipe/simple/yellow/visible{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "bUW" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 8},/obj/structure/sign/deathsposal{pixel_y = 32},/turf/simulated/floor/plating,/area/maintenance/incinerator) "bUX" = (/obj/machinery/atmospherics/pipe/tank/toxins{volume = 3200},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "bUY" = (/obj/machinery/atmospherics/pipe/tank/oxygen{volume = 3200},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) @@ -5204,7 +5203,7 @@ "bWd" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating{tag = "icon-platingdmg3"; icon_state = "platingdmg3"},/area/maintenance/asmaint2) "bWe" = (/turf/simulated/wall/r_wall,/area/maintenance/incinerator) "bWf" = (/obj/structure/sign/nosmoking_2{pixel_x = -28},/turf/simulated/floor/plating,/area/maintenance/incinerator) -"bWg" = (/obj/machinery/atmospherics/pipe/simple/insulated,/turf/simulated/floor/plating,/area/maintenance/incinerator) +"bWg" = (/obj/machinery/embedded_controller/radio/access_controller{exterior_door_tag = "incinerator_airlock_exterior"; id_tag = "incinerator_access_control"; interior_door_tag = "incinerator_airlock_interior"; name = "Incinerator Access Console"; pixel_x = -26; pixel_y = 6; req_access_txt = "12"},/obj/machinery/ignition_switch{id = "Incinerator"; pixel_x = -24; pixel_y = -6},/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/yellow/visible{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "bWh" = (/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "bWi" = (/obj/machinery/atmospherics/binary/pump,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "bWj" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/grille,/turf/simulated/floor/plating,/area/maintenance/aft) @@ -5256,8 +5255,8 @@ "bXd" = (/obj/machinery/atmospherics/unary/outlet_injector/on{dir = 4; frequency = 1443; id = "air_in"},/obj/structure/sign/securearea{desc = "A warning sign which reads 'EXTERNAL AIRLOCK'"; icon_state = "space"; layer = 4; name = "EXTERNAL AIRLOCK"; pixel_x = 0; pixel_y = 32},/turf/simulated/floor/engine/vacuum,/area/maintenance/incinerator) "bXe" = (/obj/machinery/atmospherics/pipe/simple/cyan/visible,/turf/simulated/floor{icon_state = "arrival"; dir = 10},/area/atmos) "bXf" = (/obj/machinery/atmospherics/binary/pump{dir = 8; on = 1},/obj/machinery/access_button{command = "cycle_exterior"; layer = 3.1; master_tag = "incinerator_access_control"; name = "Incinerator airlock control"; pixel_x = -22; pixel_y = -10},/obj/structure/sign/fire{pixel_y = 32},/turf/simulated/floor/plating,/area/maintenance/incinerator) -"bXg" = (/obj/machinery/atmospherics/pipe/simple/general/visible{dir = 4},/obj/machinery/embedded_controller/radio/access_controller{exterior_door_tag = "incinerator_airlock_exterior"; id_tag = "incinerator_access_control"; interior_door_tag = "incinerator_airlock_interior"; name = "Incinerator Access Console"; pixel_x = -26; pixel_y = 6; req_access_txt = "12"},/obj/machinery/ignition_switch{id = "Incinerator"; pixel_x = -24; pixel_y = -6},/obj/machinery/meter,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) -"bXh" = (/obj/machinery/atmospherics/pipe/simple/general/visible{dir = 4},/obj/machinery/atmospherics/pipe/simple/insulated,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) +"bXg" = (/obj/machinery/atmospherics/pipe/manifold/yellow/visible,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) +"bXh" = (/obj/machinery/atmospherics/pipe/simple/yellow/visible{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "bXi" = (/obj/machinery/atmospherics/pipe/simple/green/visible,/obj/machinery/portable_atmospherics/pump,/turf/simulated/floor{icon_state = "red"; dir = 10},/area/atmos) "bXj" = (/obj/machinery/atmospherics/pipe/simple/green/visible{dir = 4},/obj/machinery/atmospherics/pipe/simple/cyan/visible,/turf/simulated/floor,/area/atmos) "bXk" = (/obj/machinery/atmospherics/portables_connector/visible{dir = 8},/obj/machinery/light_switch{pixel_x = 27},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) @@ -5367,13 +5366,13 @@ "bZk" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 0; scrub_Toxins = 0},/turf/simulated/floor{tag = "icon-warningcorner (EAST)"; icon_state = "warningcorner"; dir = 4},/area/toxins/misc_lab) "bZl" = (/obj/structure/closet/crate,/obj/item/clothing/under/color/lightpurple,/obj/item/weapon/spacecash/c200,/turf/simulated/floor/plating,/area/maintenance/asmaint2) "bZm" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 4; external_pressure_bound = 0; initialize_directions = 1; internal_pressure_bound = 4000; on = 1; pressure_checks = 2; pump_direction = 0},/turf/simulated/floor/engine/vacuum,/area/maintenance/incinerator) -"bZn" = (/obj/machinery/atmospherics/pipe/simple/general/visible{dir = 4},/turf/simulated/wall/r_wall,/area/maintenance/incinerator) +"bZn" = (/obj/machinery/light,/obj/machinery/atmospherics/pipe/manifold/yellow/visible,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "bZo" = (/obj/machinery/atmospherics/binary/pump{dir = 4; on = 1},/obj/structure/sign/fire{pixel_y = -32},/obj/machinery/access_button{command = "cycle_interior"; master_tag = "incinerator_access_control"; name = "Incinerator airlock control"; pixel_x = 24; pixel_y = 8},/turf/simulated/floor/plating,/area/maintenance/incinerator) -"bZp" = (/obj/machinery/atmospherics/pipe/simple/general/visible{dir = 4},/obj/machinery/door_control{id = "disvent"; name = "Incinerator Vent Control"; pixel_x = 0; pixel_y = -24; req_access_txt = "12"},/obj/machinery/meter,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) +"bZp" = (/obj/machinery/door_control{id = "disvent"; name = "Incinerator Vent Control"; pixel_x = 0; pixel_y = -24; req_access_txt = "12"},/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/yellow/visible{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "bZq" = (/obj/structure/lattice,/obj/machinery/atmospherics/pipe/simple/cyan/visible,/turf/space,/area/space) "bZr" = (/obj/machinery/atmospherics/valve{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) -"bZs" = (/obj/machinery/atmospherics/pipe/simple/general/visible{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) -"bZt" = (/obj/machinery/atmospherics/pipe/simple/general/visible{dir = 4},/obj/item/device/radio/intercom{name = "Station Intercom (General)"; pixel_y = -29},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) +"bZs" = (/obj/machinery/atmospherics/valve/open{tag = "icon-mvalve_map (EAST)"; icon_state = "mvalve_map"; dir = 4},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 1},/area/medical/virology) +"bZt" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{tag = "icon-manifold-r-f (NORTH)"; dir = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint) "bZu" = (/obj/machinery/atmospherics/portables_connector/visible{dir = 8},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "bZv" = (/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/grille,/turf/simulated/floor/plating,/area/maintenance/aft) "bZw" = (/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/grille,/turf/simulated/floor/plating,/area/maintenance/aft) @@ -5744,7 +5743,7 @@ "cgx" = (/obj/machinery/portable_atmospherics/canister,/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor/plating,/area/maintenance/asmaint) "cgy" = (/obj/machinery/atmospherics/pipe/manifold/supply/hidden,/turf/simulated/floor/plating,/area/maintenance/port) "cgz" = (/obj/structure/disposalpipe/segment,/turf/simulated/wall,/area/maintenance/asmaint) -"cgA" = (/obj/machinery/door/airlock/maintenance{name = "Biohazard Disposals"; req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/asmaint) +"cgA" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/mob/living/simple_animal/mouse,/turf/simulated/floor/plating,/area/maintenance/asmaint) "cgB" = (/obj/machinery/power/apc{dir = 1; name = "Locker Room APC"; pixel_x = 0; pixel_y = 24},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 6},/mob/living/simple_animal/mouse,/turf/simulated/floor/plating,/area/crew_quarters/locker) "cgC" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cgD" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/maintenance/asmaint2) @@ -5782,7 +5781,7 @@ "chj" = (/obj/structure/extinguisher_cabinet{pixel_x = 27; pixel_y = 0},/obj/machinery/camera{c_tag = "Atmospherics West"; dir = 8; network = list("SS13")},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor,/area/atmos) "chk" = (/obj/machinery/computer/general_air_control/large_tank_control{frequency = 1441; input_tag = "o2_in"; name = "Oxygen Supply Control"; output_tag = "o2_out"; sensors = list("o2_sensor" = "Tank")},/turf/simulated/floor{dir = 0; icon_state = "blue"},/area/atmos) "chl" = (/obj/machinery/atmospherics/binary/pump{dir = 1; name = "O2 Outlet Pump"; on = 1},/turf/simulated/floor{icon_state = "blue"; dir = 6},/area/atmos) -"chm" = (/obj/machinery/atmospherics/pipe/manifold/general/visible,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) +"chm" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 6},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "chn" = (/obj/machinery/computer/general_air_control/large_tank_control{frequency = 1443; input_tag = "air_in"; name = "Mixed Air Supply Control"; output_tag = "air_out"; pressure_setting = 2000; sensors = list("air_sensor" = "Tank")},/turf/simulated/floor{icon_state = "arrival"},/area/atmos) "cho" = (/obj/machinery/camera{c_tag = "Atmospherics South East"; dir = 1},/obj/machinery/atmospherics/binary/pump{dir = 1; name = "Air Outlet Pump"; on = 1},/turf/simulated/floor{icon_state = "arrival"; dir = 6},/area/atmos) "chp" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/maintenance/asmaint) @@ -5838,7 +5837,7 @@ "cin" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/atmos) "cio" = (/obj/machinery/atmospherics/pipe/manifold/general/visible,/obj/machinery/meter,/turf/simulated/floor,/area/atmos) "cip" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/plating,/area/atmos) -"ciq" = (/obj/machinery/atmospherics/pipe/manifold/general/visible,/obj/machinery/light,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) +"ciq" = (/obj/machinery/atmospherics/pipe/simple/cyan/hidden{tag = "icon-intact (NORTHWEST)"; icon_state = "intact"; dir = 9},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cir" = (/obj/machinery/requests_console{department = "Atmospherics"; departmentType = 4; name = "Atmos RC"; pixel_x = 30; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor,/area/atmos) "cis" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/atmos) "cit" = (/obj/structure/disposalpipe/sortjunction{dir = 1; icon_state = "pipe-j2s"; sortType = 2},/obj/structure/noticeboard{pixel_y = 32},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor,/area/quartermaster/office) @@ -7499,6 +7498,7 @@ "cOk" = (/obj/item/weapon/shard,/obj/item/weapon/module/power_control,/turf/simulated/floor/plating/airless,/area/AIsattele) "cOl" = (/obj/structure/closet,/turf/simulated/floor/plating/airless,/area/AIsattele) "cOm" = (/obj/item/weapon/storage/toolbox/electrical{pixel_x = 1; pixel_y = -1},/turf/simulated/floor/plating/airless,/area/AIsattele) +"cOn" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/manifold/cyan/hidden,/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cOo" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plating/airless,/area/AIsattele) "cOp" = (/obj/machinery/power/solar/fake,/turf/simulated/floor/airless{icon_state = "solarpanel"},/area/djstation/solars) "cOq" = (/turf/simulated/floor/plating/airless,/area/djstation/solars) @@ -8892,12 +8892,14 @@ "dpa" = (/obj/machinery/atmospherics/pipe/manifold/supply/hidden{tag = "icon-manifold-b-f (NORTH)"; dir = 1},/turf/simulated/floor,/area/engine/break_room) "dpb" = (/obj/machinery/atmospherics/pipe/manifold{dir = 4},/obj/machinery/mineral/labor_points_checker,/turf/simulated/wall,/area/mine/laborcamp) "dpc" = (/obj/machinery/computer/shuttle/ferry/request,/turf/simulated/shuttle/floor,/area/shuttle/transport1/centcom) +"dpd" = (/obj/machinery/door/airlock/maintenance{name = "Biohazard Disposals"; req_access_txt = "12"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/maintenance/asmaint) "dpe" = (/obj/machinery/computer/mech_bay_power_console,/turf/unsimulated/floor/plating,/area/syndicate_mothership) "dpf" = (/turf/unsimulated/floor{icon_state = "recharge_floor"; name = "mech bay recharge floor"; tag = "icon-recharge_floor"},/area/syndicate_mothership) "dpg" = (/obj/machinery/door/airlock/glass_large{name = "Equipment Room"; opacity = 1; req_access_txt = "150"; text = "g"},/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) "dph" = (/obj/machinery/door/window{dir = 4; name = "EVA Storage"; req_access_txt = "150"},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/syndicate_station/start) "dpi" = (/obj/structure/stool,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/syndicate_station/start) "dpj" = (/obj/machinery/door/airlock/centcom{name = "Transport Shuttle"; opacity = 1; req_access_txt = "109"},/turf/unsimulated/floor{icon_state = "floor"},/area/centcom/ferry) +"dpk" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/manifold/general/hidden{tag = "icon-manifold (NORTH)"; icon_state = "manifold"; dir = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint) "dpl" = (/obj/item/weapon/reagent_containers/glass/bucket,/turf/simulated/floor/plating,/area/security/prison) "dpm" = (/obj/structure/table,/obj/item/weapon/c4{pixel_x = 2; pixel_y = 1},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/syndicate_station/start) "dpn" = (/obj/item/weapon/soap/syndie,/obj/structure/mopbucket,/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/syndicate_mothership) @@ -8916,7 +8918,7 @@ "dpA" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/wall/r_wall,/area/atmos) "dpB" = (/obj/machinery/atmospherics/portables_connector/visible{dir = 8},/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 6},/area/medical/virology) "dpC" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 8},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 5},/area/medical/virology) -"dpD" = (/obj/machinery/atmospherics/valve{dir = 4; icon_state = "valve1"; open = 1; openDuringInit = 1},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 1},/area/medical/virology) +"dpD" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 9},/turf/simulated/floor/plating,/area/maintenance/asmaint) "dpE" = (/obj/machinery/camera{c_tag = "Atmospherics South West"; dir = 4; network = list("SS13")},/obj/machinery/atmospherics/unary/vent_pump{dir = 8; on = 1},/turf/simulated/floor,/area/atmos) "dpF" = (/obj/structure/table,/obj/item/clothing/glasses/meson,/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/turf/simulated/floor,/area/engine/break_room) "dpG" = (/obj/machinery/bot/secbot/pingsky,/turf/simulated/floor/carpet,/area/turret_protected/aisat_interior) @@ -9189,6 +9191,12 @@ "duN" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/maintenance/aft) "duO" = (/obj/machinery/alarm{frequency = 1439; pixel_y = 23},/obj/item/weapon/wrench,/obj/machinery/atmospherics/pipe/manifold/supply/hidden{tag = "icon-manifold-b-f (WEST)"; dir = 8},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 9},/area/medical/virology) "duP" = (/obj/machinery/door/airlock/maintenance_hatch{req_access_txt = "65"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor{icon_state = "dark"},/area/turret_protected/aisat_interior) +"duQ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0},/obj/machinery/atmospherics/pipe/manifold/supply/hidden,/turf/simulated/floor/plating,/area/maintenance/asmaint2) +"duR" = (/obj/machinery/atmospherics/pipe/simple/general/hidden{dir = 9},/turf/simulated/floor/plating,/area/maintenance/asmaint) +"duS" = (/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/maintenance/asmaint) +"duT" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/maintenance/asmaint) +"duU" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/maintenance/asmaint) +"duV" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating/airless,/area/space) (1,1,1) = {" ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl @@ -9283,16 +9291,16 @@ ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlah ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahldpXdpXdpXahlahlahjahlakoakpakoahjahjahjahjdpXdpXdpXahlahlahlahlahlahlahlahlahlahlahlahjahlaiCakqajKajKaiCajgajhakrahnahkaioakvaeRafrahoafraeSakwajTakxaeSakyajTakzaeSakAajTakBaeSakCakDahrajZagqaeSakFajTakGaeRakHairakJakKakHakIaisakJahuahvahwabIabIahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahlakMakNakMahlahjahlahlahjahlahlahlahjahjahjahlahlahlahlakmakOakmahjahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahjahlahlahlahlahjahlakPakQakPahjahlahjahlahlahjahjahlahlahlahlahlahlahlahlahlahlahlahjahlaiCakRakSakTakUahlahlakVahyakWailalGaeRafragOafraeRalcaldalealfalgaldalealfalgaldalealfakEagLaljajYajWaeRaeRaeRaeRaeRalmaigalmalnalmalmaihalnahuainaimanRabIabIabIahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjalsaltalualtakkahjahjahjahjahlahjahlahlahlahjahjahlahlahlakmalvakmahjahjahjahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlahlahjalwalxalyalzalAahlahjahlahlahjahjahlahlahlahlahlahlahlahlahlahlahlahjahlaiCalBalCalCaiCajgajhalDaijalEahVahWadcaeRaeRaeRaeRalHalHalHalJalHalHalHalIalHalHalHalJalHalHalHalKalKalLalMalMalMalNalmaigalmalnalmalmaihalnabIahvalPadYalQalRalQahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjalSalTakNalUalVahjahlahlahjahlahjahlahlahlahlahjahjahlahlakmalvakmahlahlahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahlahlahlahlahjalWalXalYalZalWamaamaahlahlahjahjahlahlahlahlahlahlahlahlahlahlahlahjahlaiCalCalCalCambamcajNamcajjaiHahSaiHamgalKalKalKagEalKalKamjalKalKalKalKalKalKalKamialKagjalKamhalKalKalKalKalKalKamkalnahRamlammamnalnahUalnamramsahTamuamuamvabIahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjamwamxamyamzamwahjahlahlahjahlahjahlahjahlahlahlahjakmakmakmalvakmakmakmakmakmakmahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahlahlahlahlahjalWalXalYalZalWamaamaahlahlahjahjahlahlahlahlahlahlahlahlahlahlahlahjahlaiCalCalCalCambamcajNamcajjaiHahSaiHamgalKalKalKagEalKalKamjalKalKalKalKalKalKalKamialKagjalKamhalKalKalKalKalKalKamkalnahRamlammamnalnahUalnamrahFahTamuamuamvabIahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjamwamxamyamzamwahjahlahlahjahlahjahlahjahlahlahlahjakmakmakmalvakmakmakmakmakmakmahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlamaamaamaamaamaahjahjalWamAamBamCalWamDamaahlahlahjahjahlahlahlahlahlahlahlahlahlahlahjahjahlaiCamEamEamEaiCajgajhamFagIafZahIahLahyamKamKamKamKamKamLahHamKamKamKamKamKamKamKamNamOamOamOahNamQamOamRagDagCagBalNamSamTahuahuahuahuahuahuabIamWahPabIamYamZabIahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjamwanaanbancamwahjahlahlahjahlahjahlahjakmaknakmaknakmandalvalvalvalvalvalvaneakmahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlamaamaamaamaanfanganhamaahlahlalWaniacZankalWanlamaahlahlahjahjahlahlahlahlahlahlahlahlahlahjahjahlahlaiCanmanmanmaiCahlahjadcaebabUahyahianpanpanqanranqanpanpagZantantantanuantantanvanwanxagXamuagUamuamuamuamuagRamuamuamuamuamuahtahsahqahmanEanEahFahzanHanIahGabIahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlahlahlamwanKafDanMamwanNanNanNanNanNanOanPanQakmalralvaneakmakmalvakmakmakmakmanSakmakmahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlamaamaamaamaanfanganhamaahlahlalWaniacZankalWanlamaahlahlahjahjahlahlahlahlahlahlahlahlahlahjahjahlahlaiCanmanmanmaiCahlahjadcaebabUahyahianpanpanqanranqanpanpagZantantantanuantantanvanwanxagXamuagUamuamuamuamuagRamuamuamuamuamuahtahsahqahmanEanEamsahzanHanIahGabIahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlahlahlamwanKafDanMamwanNanNanNanNanNanOanPanQakmalralvaneakmakmalvakmakmakmakmanSakmakmahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlahlahlahjamaasianUanVanlanWanlamaanXanYalWalWanZaoaalWanlamaamaanXaobaocamaamaahlahjahlahlahlahlahlahlahjahjahlaodaoeaoeaoeaofahlahjahyaKUajNahyaIUanpaomaonaonaonaooanpaJaatXaJcaJeaJdaotantalHalKaouaGQaIPaoxaoxaoxaoxaoxaISaITaoxaoxaoxaoxaoxaIOaIJaIKaIGaIHaIEaIFabIaoIaoJabIahjaIyaANaANaIhaANaANaIgahlahlahlahlahlahjaoOaoPaoOahlanNamwamwaoQaoRamwaoSalvalvalvakmarualvarwakmalvalvalvaoWakmalvakmdtNdtLakmalvaoYakmahlahlahlahlahlahlahlahlaaeahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaoZapaapbahlapcapdapeahlahjapfapgapfahlahlahjamaaphapiapjaJZapkapVamaapmanlapnapoasGanlanlanlanlanlanlanlanlanlamaahlappahlahlahlahlahlahlahjahlahlahlahlahlahlahlahlahjahyaKUaSvahyaJDanpapuapvapwapxapyanpapsantapzapAaJGapCapDalHalKalMaGQaguaqHaqHaqHaqHaqHaJHanyaqHaqHaqHaqHaqHaqHaqHaqHapQaJsaJAaJgaJgaJgaJgaJgaJfayNapSapSapSapSapSayNapQahlahlahlahlahjapTalvapUahlanNasjapWapXapYalvalvalvakmalvakmapZalvalvakmalvaqaaqbaqcanSalvakmdtPasDakmalvasnakmahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaqfaqgbahaqgaqfaqibcpaqiaqfahjaqkanlaqlahlahlamaamaamaamaamaaLIaHgaEkaEkaLKarqaLOarqaLiaLfaLdasNamaanlamaamaamaanlamaahlahjahlahlahlahlahlahlahjahlahjahjahjahjaogaogaogaogaogaogaogaogaKDanpaquapvaqvaqwaqxanpapsaLcaKVaKFaKEaKGaqBalHalKaXOaGQaguaqHaFsaFtaKxapGaKyaKzaqHaKraqLaKsaqHaqNaKhaKiapQaKqaKlaKmaVOaKfaKaaKbaKgayNapSapSapSapSapSayNapQahjahjahjahjaqYaqZaoParaarbanNasLalvardalvandalvakmakmarfakmakmargakmakmaqcasEarialvakmalvarjarjarjarjarjarjarjarjarjbRJbRJbRJbRJdsibRJbRJahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlarkaqgarlaqgarkaqiarmaqiarkamaarnapgaroaobanYamaaNaaFdaFdaFdaFdaFdaFdaNeaNiamaamaamaamaamablMamaamaanlartamaatzanlamaamaamaahlahlahlahlahlahjahjahjahjahjahlahlaogarvauSaogarxaryarzaogaKDanpaMxaMkaMeaMeaMdarBaMIaMHarGarGaMGarGaMAalHalKarLaGQaguaqHaFHaMJaFBaMYaFDaMWaqHaMVarUaMKaqHarUaLVaLXapQaLYaLZawGaLPaLPaLPaELaLRaLUapSapSapSapSapSaMbapQapQapQahlahlashalvalvalvaoSanNauMaqcardalvatOaskaslanSalvalvalvalvasmalvalvasEasoalvaspalvarjasqbcDassarjastasuasvarjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaoZapaapbahlapcapdapeahlahjapfapgapfahlahlahjamaaphapiapjarqapkapVamaapmanlapnapoasGanlanlanlanlanlanlanlanlanlamaahlappahlahlahlahlahlahlahjahlahlahlahlahlahlahlahlahjahyaKUaSvahyaJDanpapuapvapwapxapyanpapsantapzapAaJGapCapDalHalKalMaGQaguaqHaqHaqHaqHaqHaJHanyaqHaqHaqHaqHaqHaqHaqHaqHapQaJsaJAaJgaJgaJgaJgaJgaJfayNapSapSapSapSapSayNapQahlahlahlahlahjapTalvapUahlanNasjapWapXapYalvalvalvakmalvakmapZalvalvakmalvaqaaqbaqcanSalvakmdtPasDakmalvasnakmahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaqfaqgbahaqgaqfaqibcpaqiaqfahjaqkanlaqlahlahlamaamaamaamaamaaLIaFgaGxaGxaLdaJZaLfaJZaLKaLiaLOasNamaanlamaamaamaanlamaahlahjahlahlahlahlahlahlahjahlahjahjahjahjaogaogaogaogaogaogaogaogaKDanpaquapvaqvaqwaqxanpapsaLcaKVaKFaKEaKGaqBalHalKaXOaGQaguaqHaFsaFtaKxapGaKyaKzaqHaKraqLaKsaqHaqNaKhaKiapQaKqaKlaKmaVOaKfaKaaKbaKgayNapSapSapSapSapSayNapQahjahjahjahjaqYaqZaoParaarbanNasLalvardalvandalvakmakmarfakmakmargakmakmaqcasEarialvakmalvarjarjarjarjarjarjarjarjarjbRJbRJbRJbRJdsibRJbRJahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlarkaqgarlaqgarkaqiarmaqiarkamaarnapgaroaobanYamaaNaaFdaFdaFdaFdaFdaFdaNeaNiamaamaamaamaamaaTIamaamaanlartamaatzanlamaamaamaahlahlahlahlahlahjahjahjahjahjahlahlaogarvauSaogarxaryarzaogaKDanpaMxaMkaMeaMeaMdarBaMIaMHarGarGaMGarGaMAalHalKarLaGQaguaqHaFHaMJaFBaMYaFDaMWaqHaMVarUaMKaqHarUaLVaLXapQaLYaLZawGaLPaLPaLPaELaLRaLUapSapSapSapSapSaMbapQapQapQahlahlashalvalvalvaoSanNauMaqcardalvatOaskaslanSalvalvalvalvasmalvalvasEasoalvaspalvarjasqbcDassarjastasuasvarjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlarkaswasxasyarkaszasAasBarkasCanlanlbknbknartasFaEYaGvaEkaEkaEkaEkaEkaEkaEfaEgcUbdsiakjamaavUaplasManlasFamaaoVanlanlanlapfahlahlahlahlahlahjahlahlahjahlaogaogaogapqapqaogapqapqapqaogayganpaEDaEGaEFaEIaEHatTaExaEzantasUaECasWantaEvalKalMaGQaguaqHaqHaqHaqHaqHaEsaEtaqHaEuasYaqDaqHaqHaDNaqDapQataaDMcECaDWaDWaDTaDUaDQaDSapSapSapSapSapSaDLaDKaDJatkahlahlatlalvalvatmalvanNatnalvatoatpatpatpatpatqatpatralvalvalvalvalvalvalvalvakmaskarjatsattattarjbbmavFbgharjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlarkatvatwatxarkatyatwatxarkapVbkrbkoaqoaqoaqobkDbksaEZatDatEatFatGatHamaaEYaEZdsiasIcUbatJaFgatLamaamaamaamaamaamaamaanlatMahjahlahlahlahlahjahlahjdsidsiatNaqeatNapqapqaogaogatPaogaogayganpanpanpaFkanpanpanpaFiaFhantantantantantaFralKauaaGQaguaqHaFsaFtaFnapGaFlaFmaFpaFqaujaFoaKTaulaEJaEKaunarXaDMauoauqauqauraELautauuapSapSapSapSapSauuauvauwauxahjahjakmalvalvakmakmanNanNanNanNanNanNanNanNanNakmauyauzakmakmakmakmakmakmakmaDFaBaaEPaEOaENaEMauBaEQatsauDarjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahlaqfarkauEauFaqfarkauGauFaqfamaauHamaamaamaamaamaaEYaEZanlauIaavanlanlamaaEYaEZcUZahjcUZamaaGxatLamaarhauNamaaoVapVaGvaEraEkaGlaGsaGpaGpaGpaGpaGraGpaGpaGoaGlaGnaGlaGlaGjaGlaGmaGjaGkaGiaGhauWauWauWauWauWauWauWaFSaFWauWauWauWauWaFRaFJaFOaFOaFQaFGaqHaFHaFIaFBaFCaFDaFEavhaFzavjaFAavlaviaFwaFxavmavnaFyauoauqauqauraELavpavqapSapSapSapSapSavqavrauwauxahlahlakmaqralvalvarcakmaqsaneavvavwandakmatnandakmavzalvakmavAalvakmaqaaqbavBaFuatpatpavCavDavEbjOaFvavHavIarjbRJbRJdsidsibRJbRJbRJbRJahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlarkatvatwatxarkatyatwatxarkapVbkrbkoaqoaqoaqobkDbksaEZatDatEatFatGatHamaaEYaEZdsiasIcUbatJbjzatLamaamaamaamaamaamaamaanlatMahjahlahlahlahlahjahlahjdsidsiatNaqeatNapqapqaogaogatPaogaogayganpanpanpaFkanpanpanpaFiaFhantantantantantaFralKauaaGQaguaqHaFsaFtaFnapGaFlaFmaFpaFqaujaFoaKTaulaEJaEKaunarXaDMauoauqauqauraELautauuapSapSapSapSapSauuauvauwauxahjahjakmalvalvakmakmanNanNanNanNanNanNanNanNanNakmauyauzakmakmakmakmakmakmakmaDFaBaaEPaEOaENaEMauBaEQatsauDarjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahlaqfarkauEauFaqfarkauGauFaqfamaauHamaamaamaamaamaaEYaEZanlauIaavanlanlamaaEYaEZcUZahjcUZamaapiatLamaarhauNamaaoVapVaGvaEraEkaGlaGsaGpaGpaGpaGpaGraGpaGpaGoaGlaGnaGlaGlaGjaGlaGmaGjaGkaGiaGhauWauWauWauWauWauWauWaFSaFWauWauWauWauWaFRaFJaFOaFOaFQaFGaqHaFHaFIaFBaFCaFDaFEavhaFzavjaFAavlaviaFwaFxavmavnaFyauoauqauqauraELavpavqapSapSapSapSapSavqavrauwauxahlahlakmaqralvalvarcakmaqsaneavvavwandakmatnandakmavzalvakmavAalvakmaqaaqbavBaFuatpatpavCavDavEbjOaFvavHavIarjbRJbRJdsidsibRJbRJbRJbRJahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlavJavKavKavKavLavKavKavKavMavNavOavMavMavMavPamaaHhaEZanlauJavSanlavTamaaEYaHgaEkaEkaEkaEkaEkaEkaEganlavSavVanlanlaopaHLaHFaHEaHIaHIaHIaHRaHIaHTaHIaHIaHPaHQaHOaHMaHMaHMaHMaHMaHMaHNaHlaHkaHiaHiaHiaHiaHiaHiaHiaHjaHiaGHaGHaGHaGHaGHaHuaHCaHtawkaHsaqHaqHaqHaqHaqHaHqaHraHoaHpaHmaHnaGFaGGaGIaGJawuawvaGXaGYaGZaGZaHaaHbaHcaHdapSapSapSapSapSaHeascaHfawHahlahlakmalvalvalvalvalvalvavBatpatpatpatpatpatpatpawIalvalvalvalvaspalvalvardaGAayOaGzaGDaGCaGBattattattawKarjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjawLawMawNawMawOawNawNawPawMawNawQawRawSawSawTamaaHhaEZawUanlanlawVawWamaaXzaFdaFdaFdaFdaFdaFdaWMaEZavuanlamaasCasCaWPapsaogaxbaxcaxdaxdaWRaxdaWQaxdaxdaxeaxbaGyaxgaxgaxgaxgaxgaxgaxgaopaWSawfaxiaWUaWTaXfaWVaXgaxoaXqaXpaXraxsaxtawhaXsalKaXtabIadYaqHaFsaFtaXuapGaXvaXwaXxaXxaXxaXyaXRaYaaXKaXQaunaxEaXJaxGaxHaxIaxJaDUaxLaXAapSapSapSapSapSaYiapQapQapQakmakmakmandakmakmanSakmakmardakmakmaxPakmakmanSakmardaqrakmakmaxRakmalvaqrardaGAaYnarjaxTavDaYmaxVaYjavDaxXarjahjahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlarkavJaxYavJaxZawNawNcFUavJaxYavJaybaycawOaydamaaHhaHgaEmaEkaEkaEgayeayeakmaspakmayeayeayeayeaYFaYGaGnaGlaGlaGlaGlaYSapsarvaxbahlahjahlaYrahlaIeahlahjahlaxbaGyaxgayhayiayjaykaylaxgaopaZEaZzaZyaZPaZOaZNaZMaZRaZRaZQaywaywaywayxawhaxualKaxvabIadYaqHaFHaFBaFBaZraFDaYXaZxayBayCayDayEayFayFayGayFapQbasbaGbacbajbakbarapQaZUapSapSapSapSapSaZUapQasnalvayOayPakmakmakmasnalvakmasnardakmaxaalvakmavyalvakmayUayVakmavxalvakmanOanQardbaPbaNarjayXavDbaIayZbaIavDcbBarjahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl @@ -9300,13 +9308,13 @@ ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlah ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlawLaxYaAaaAbaAbaAbaAbaAcaxYawLaAdaqfaAeaydaAfaAfbdlboCaAfaAfbdmayeazpazrcFZaAiazrazrazpayeaogbdebcZaAkaAkaAkaAkaAkaAkaAkaAlahlazzbcJbcKaGwbcPdteazzahlaxbaGyaxgazAaAraAsaAtazAaxgaHLbbPawfaAubcHaAwayobcGbbebcIaAAaywaywaABaywaACaxualKaxvabIadYaqHaFsaFtbcCapGaXvbcBayFaAEazSaAFaAFayFazRaAGazTayFaAHbdPbdNaAKaSpayfahjbdOaoLaoLaoLaoLaoLbdGahlakmalvaAPaAQakmakmakmakmakmakmaARaASakmakmakmakmakmakmbdAbdwbdxaVuaVuaVubdzbdyaPcaSibdrbdqaVubdvbdnbdubdtbdnaCoaqcaBhahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahlaBiaBjaBkaBjaBjaBlaBmaBjaBjaBkaBnaBoaqfaxZaBpblYblNblOblPaBuaBvaNCayeazpazrazraBxazrazrazpayeaByaNPaNOaBBaBCaBDaBEaBFaBGaBHaAlahjazzaObaOcaAmaOaaOdazzahjaxbaGyaxgaNQaNRaBPaNTaNSaxgapsavsawfaBSaBTazIaywazIaOgaBWaBXaBYaBZawhaCaawhaxualKaxvabIadYaqHaFHaMJaFBaOhaFDaOiayFaCcazSazSazSayGaCfaCeaCdayFaJXaOsaOPaOVaOBayfahlahjahlahjahlahjahlahjahlakmaqrbmeaPcaCoaCpakmatOalvaqrardalvakmahlakmayOaPcaPcaPvaPBaPxaPxaPxaPxaPxaPyaPAaPGaPDaPCaPCaPCaPCaPCaPCaPTaPPaCCaCDahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaBiaBnaBjaCEaCFaCFaCGaCHaCIaCJaCKaCFaCFaCLaCMavJaxZaCNaAfauOaQgbmfaCRaCQaPUayeaCTazrazrazrazraEoaRaaRcbmjaRgaRdaBGaBGaBGaBGaBGaBGaBGaAlahlazzaQyaApaQAaAnaQXazzahlaxbaGyaxgaQhaQiaDeaQqaQuaxgapsaDhawfawfaDiaDjaJMaDjaShawfawfaDmaDnawhaDoawhaxualKaxvabIadYaqHaqHaqHaqHaqHaRjaRqaRBaRJaRraDwaDwaDwaSnayFaIDayFaSlaSmaSoaAKaSpayfakmakmakmakmakmakmakmakmakmakmakmakmakmbmkakmakmakmakmayOaSiaSAaStaEwaStaSraSsaSqaSqbmlaDOaDOaDOaDOaDOaDPaSLaDRaDRaDRaDRaDRaDRaDVakmaDXayfaDVaDVaDVahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaCLaDYaDZaEaaCFaEbaCFaEbaCFaEbaCFaEbaCFaEcaEdazdaxZaEeaAfaTeaTCbmraEiaEjaRQayeaElazraSPaTaaTaaUiaUhaUgbnlaTZaTOaTNaTNaTNaTNaTNaTLaTKaAlahjazzaUraApaUpaUqaUoazzahjaxbbnmaEEaUlaUmaDeaUkaUjaGEbmwaTEawhaTGaTDaDmaDmaDmaBUaERawhaESaESawhaDmawhaETaEUaEVabIadYadYadYadYadYamraHqaFbaFcaTHaFeaFcaUIaFcaUHaFcaUKayFbeDaUJaUNaAKaULaUMaUQaVaaUOaUPaVfaCsaCsaCsaCsaVmaVkaCsaCsbnnaVpaVnaVBaVuaVsaVraUvaUwaUxaUwaUyaUzaDOaDOaFKaDOaFLaFMaFNaDOaDRaUAaDRaFPaUFaUEaUGaFTaFUaFVawaatbaFYaFZaGaahjahlahjahlahjahlahjahlahjahjahlaGbaGbaGbaGbaGbaGbaGbahlahjahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaGcahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaCLaDYaDZaEaaCFaEbaCFaEbaCFaEbaCFaEbaCFaEcaEdazdaxZaEeaAfaTeaTCbmraRQaEiaEjayeaElazraSPaTaaTaaUiaUhaUgbnlaTZaTOaTNaTNaTNaTNaTNaTLaTKaAlahjazzaUraApaUpaUqaUoazzahjaxbbnmaEEaUlaUmaDeaUkaUjaGEbmwaTEawhaTGaTDaDmaDmaDmaBUaERawhaESaESawhaDmawhaETaEUaEVabIadYadYadYadYadYamraHqaFbaFcaTHaFeaFcaUIaFcaUHaFcaUKayFbeDaUJaUNaAKaULaUMaUQaVaaUOaUPaVfaCsaCsaCsaCsaVmaVkaCsaCsbnnaVpaVnaVBaVuaVsaVraUvaUwaUxaUwaUyaUzaDOaDOaFKaDOaFLaFMaFNaDOaDRaUAaDRaFPaUFaUEaUGaFTaFUaFVawaatbaFYaFZaGaahjahlahjahlahjahlahjahlahjahjahlaGbaGbaGbaGbaGbaGbaGbahlahjahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaGcahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaGdaCFaCFaGeaCFaEbaCFaEbaGfaEbaCFaEbaCFaEcaEdazdaxZbdiaAfaAfaVFbnobnpaVCaAfayeayeayeayeaVDazrazraVSayebnAaVRaBGaBGaBGaGtaBGaBGaBGaGuaAlahlazzazzaEyaVNaEyazzazzahlaxbaGyaxgaVLaVMaVIaVJaVKaxgapsaVHawhaVGaTDaDmaDmaDmaBUaGKawhaGLaGMawhaCaawhaGNaGOaGPabIamrabIabIabIabIabIbnqaGSayFaGTazSayFaGUayFaGVayFaGWayFaWvaWwaUNaAKaWxaWyaWJaWLaWlaWlaWmaWlaWlaWnaWlaWoaWpaBaaBaaBaaBaaWqaWsaWraWuaWtalvaIRaIRaIRaIRapBaDOaHvaHwaHxaHyaHzaHAaDOaHBaWkaDRaHDaVVaVUaVZaFTaHHaFXawaaWjaDVaDVaDVahjahjahjahjahjahjahjahjahjahlaGbaGbaGbaGbaGbaGbaGbaGbaGbdsiahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaCLaHJaDZaEaaCFaEbaCFaEbaCFaEbaCFaEbaCFaEcaEdazdaHKaCwaBAaBtaBtaBwauZawNavbavdavcavaayeaukazrazraqCayeaBsaBzaBGaHXaHYaHZaIaaIbaIcaIdaAlahlahjahlaIfauYaIfahlahjahlaxbaGyaxgaDeaIiaIjaIkaIlaxgapsapqawhaImaInaDmaDmaDmaIoaIpawhahlahlaIqaIraIsaItaIuaIvaIwaIxaIqahlahlaTkaIzaAoaIBayFaICazSazSazSaCeazSazSazSayFaAKauXauVaAKaAKayfauUaIIaIIauTaMZaILaIIaIMaIIaINauRaINauQaINaIQaIRaIRauPaIRaIRaIRaIRaCkaKwaIRapBaDOaHwaIVaIWaIXaIYaIZaDOauLauAauiaumaupausaueaufaugauhaucaudaJhaJiaJjahlahlahlahlahlahlahjahlahjahlaGbaGbaGbaGbaGbaGbaGbaGbaGbahjahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaJkaJlaBjaCEaCFaCFaCFaJmaCFaCFaJnaCFaCFaCLaJoawLaxZawNaJpaJqaJqaJqaJqaJqaJqaJqaJrawNayeapraubaprayeayeaBqaJvaJwaAkaAkaAkaAkaJuaJxaJyaAlaJzaJBaJBaJCatWaJEaJBaJBaJFaxbaBraxgatZaxgaJIaJJaJKaxgazGavWawhawhawhaJLaJMaJLawhawhawhaJOaJPaJQaJRaIuaIuaIuaIuaIuaJSaJTaJPaJUaTkaJVaAoaJWayFayFayFayFayFayFayFayFayFayFaFjatQatBatAatCaPuatjaKeaIIatuaMZaKjatVaKjaINaKkatUaINatSaINaKnaKoaKpatRasXasXasXasVasTaMaaIRapBaDOasSaIVaKAaIXaIYaKBaDOaKCasRathatiatfatgatdateaVlatcasZatbaKIaKJaKKahlahjahlahlahlahlahjahlahjahlaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaJkaBjaBkaBjaBjaKLaBmaBjaBjaBkaJlaKMaqfaKNawNavJaKOaKOaKPaKOaKQarkaKRaKSawNaGgaMzaKYaKYaKXaKYaEpaKZaKYaKYaKYaKYaKYaKYaKYaLaaLbawCawDaLeaLeawBaLgaLeaLeaLeaLhaEnaLjawBaLeaLeaLeaLkaLlaLmaIuaLnaLoaIvaIwaIwaIwaItaIuaIuaLpaIuaLqaLraLsaLtaLuaLvaLwaLxaIuaIuaLybzVaEqaEWaLAaLCaLDaLEaLFaIuaLGaIuaAKaLHawraJYatQawpawoawnawmaqFdrhaIIawqaLLawjaLMaLNaINawlatUaLQaqAaINaIRaLSbgAawiaPSaLWawyawxawzaDCaIRapBaDOawAawtawsawwaMcaMfaDOaMgaMhaDRaHGaHGaHGaHGaDRaMiaMjasZatbaDVaDVaDVaMlaMlaMlaMmaMnaMoahjahlahjaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlavJaxYaMpaAbaAbaAbaAbaMqaxYavJaAdaqfaAeaMrazdaMsaMtaMuaMuaMvarkaMwaKSawgaMyaMzaweaMBaMCaMDaMEaMFaKYaKYaKYaKYaKYaKYaKYaLaaKYaMzaKYaKYaKYaDgaDfaCxaCxaCxaCxaDlaCxaEhaCxaCxaDkaMLaLlaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaLpaIuaMMaMNaMOaMPaMQaMRaMSaMTaIuaIuaLyaIuaIuaIuaIuaIuaIuaIuaIuaIuaMUaIuaAKaJYaJYaJYavGavfaveavkavgavoaQSaIIavtaMZavQaIIaIIaINaNbatUaNcaqAaNdaINaIRaIRaIRaIRaIRaIRavZaNgaNfaIRapBaDOaNhaHwavYavXaHwaNjaDOaDRaDRaDRaDRaDRaDRaNkaDRaFXaFXawaatbaNlaNmaDVaNnaNoafJaNqaNraNsahjahlahjaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjazbaqfazdatwazdaNtaNuaNvaNwazdatwaNxaNyaqfaxZawNazdaNzaNAaMuaMuaMvarkaNBaKSawNaMyaMzaKYaNDaNEaNEaNEaNFaNGaNHaNEaNIaNEaNEaNEaNJaNKaqSaNEaNEaNEaqQaqPatKasaasaaqRaqOaqMaqKaNUaKYanLaMLaLlaIuaNVaIuaNWaNWaNWaNWaNWaNWaNWaNWaNXaNWaNWaNWaNWaNWaNWaNWaNWaNWaNWaNWaNYaNWaNWaNWaNWaNWaNWaNWaNWaIuaIuaIuaAKaNZaNZaNZaNZaNZaqIaqGaPuaqFaqdaIIaqEaOeaqyaIIaOfaINaqtaqpaqqaqAaOjaINaIRaOkaqzaOmaOnaOmaqnaOoaOpaIRapBaDOaOqaOqapHapFaOtaOtaOuaDOaOvaOwaOxaDVaOyaOzaOAaFXaFXaqjaqmaDVaOCaDVaODaqhaOFaOFaOGaOHaMnaMnaOIaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjazbaqfazdatwazdaNtaNuaNvaNwazdatwaNxaNyaqfaxZawNazdaNzaNAaMuaMuaMvarkaNBaKSawNaMyaMzaKYaNDaNEaNEaNEaNFaNGaNHaNEaNIaNEaNEaNEaNJaNEaqSaNEaNEaNEaqQaqPatKasaasaaqRaqOaqMaqKaNUaKYanLaMLaLlaIuaNVaIuaNWaNWaNWaNWaNWaNWaNWaNWaNXaNWaNWaNWaNWaNWaNWaNWaNWaNWaNWaNWaNYaNWaNWaNWaNWaNWaNWaNWaNWaIuaIuaIuaAKaNZaNZaNZaNZaNZaqIaqGaPuaqFaqdaIIaqEaOeaqyaIIaOfaINaqtaqpaqqaqAaOjaINaIRaOkaqzaOmaOnaOmaqnaOoaOpaIRapBaDOaOqaOqapHapFaOtaOtaOuaDOaOvaOwaOxaDVaOyaOzaOAaFXaFXaqjaqmaDVaOCaDVaODaqhaOFaOFaOGaOHaMnaMnaOIaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlarkawLaxYawLaxZawNawNayaawLaxYawLaOJaOKaOLawNawLaOMaOMaKPaOMaKQarkaONaKSawNaOOaOOaOOaOQaOOaORaORaORaORaORaOSaOTaORaOUaORaORaORaOYaOWaOXaOWaqJapRaPaaKYaKYaPbapPaPdanjaKZaKYanLaPeaPeaIuaIuaIvaPfaJPaJPaPgaPgaPgaPgaPhaPiaPjaPkaPlaPmaPnaPmaPoaPmaPpaPkaPqaPiaPraPgaPgaPgaPgaJPaJPaPsaItaIuaIuaIIaoXaMXaKcaKcaKcaKcaKcaPuaQUaKcaIIapKaPzapNaINaINaINapLapMaINaINaINaINaIRaOmapOaPEaPEaPEapEaPFaOmaIRapBaDOaPHaHwapHapFaHwaHwaPIaDOaPJaPKaPLaDVaFXaPMaPNaPOaPOapIapJaPQaPRaDVafsaSEaOFaOEaOFaPWaPXaPXaPWaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlaaeahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaGcahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjavJaPZawNavKaOLawNawNaQaavKawNaPZaOLawNawNawNaQbaQcaQcaQcaQcaQcaQcaQcaQdawNaOOanTaOOaRDaORasQaQnaQkaQlaQmaQnaQoaQpbKEaQraQsaQtaOYaQvaQwaQxaqJaxfaPaaPaaQzaPaaPaaPeazEaQBaQCaxyaPeaPeaQDaIuaIvaQEahlahlahlahlahlahlahlaPiaQFaQGaQHaQIaQJaQKaQLaQMaQNaQOaQPaPiahlahlahlahlahlahlahlaQQaItaIuaQRaIIaPtaKcaQTaKcaKcaKcbKcaPuaQUaLJaQVaPuaQWasbaINaQYaQZasfasdaseasgaReaRfaINaOmasraRhaRhaRhasKaRiaOmaIRasOaDOaRkaRkapHapFaRlaRlaRmaDOaDOaRnaDOaDVaRoaOzaOAaRpaRpaqjaqmaDVaDVaDVaMmasHasJasPaMnaMnaMnaMnaRsaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahlahlawLaRtaRuaRuaRuaRuaRuaRuaRuaRuaRtaRuaRvawNawNaRwawNaRzawcawNaRyawbawNaRAarYaOOaRCaOOaRDaORaREaQnawdaQnaQnaQnaQoaRFaQnaQnaQnaQtaOYaRGaQwaQwaqJaxfaPaaRHaRIaRIarZaPeawZaRLaRMawYaROaRPaIuaIuaIvaQEahlahlahlahlaPiaPiaPiaPiaSOaRRaRSaRTaRUaRVaRWaRXaRYaRZaSaaPiaPiaPiaPiahlahlahlahlaQQaItaIuaIuaSbaKcaqTaqVaqUaqXaqWarparearsarrarCarAarDarEatYarFarFarHarIarJarJarKarFarMarNarOarParQarSarRaRiaOmaIRapBaDOaHwaHwapHapFaHwaHwaHwaolaSwaHwaSxaDVaKHbDuaSzaRpaRparTarVaSBaDVaSCaSDaSEaOFarWaOFaSFaPXaPXaSGaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl @@ -9314,7 +9322,7 @@ ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlah ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUdazeawOaUeaSMaWZaZSaZIazxaZIaZTaWZaZIaSMaRCaRCazFbfBaORaUsaQnaYBaYEaZoaUtaUuaSSaQnaQnaQnaQtaOYaOYaOYaOYaqJaxfaPaaPaaPaaPaaPaaPeazwaRMaRMaRMaRMaTjaIuaIuaIvaIwaIwaUBaUCaUDaPiazaayWayYazmazqazmazoayKayJayIayHayQayMayHayLayTaySaPiaURaUCaUSaUTaIwaItaIuaIuaSbaKcaPuaQTaKcaUUaKcaQTaKcaQUaLJaUVaKcaKcaKcaUWaSkazYaUXaUYaUZazVaTJaVbaINaVcaTMaVdaRhbadaRhaSuaVeaIRazUaDOaDOaDOapHapFaVgaVhaHwaViaVjaKAazQaDVaFXazNaSzaRpaRparTazMazLaDVazKaOFaSEazJazHaVwaNsahlahjahjaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaVxaVyaVzaxZaVAbjabjjbjhbjlbjkbjXbjraWZaZIaSMaDpaDqaxkaOOaORaKdbhlbhfbhkbhfbhjbhLbhjbhjbhjbhrbhJaORbhnbiRbiQbiGbiFaVWaVXaVYaOOaCyaPebiWaWbaWcaWdaWdaWeaIuaIuaIuaIuaIuaWfaWgaWhaWiaCPaCSaCUaCzaCAaCBaCOaCZaCYaDbaDaaCWaCVaCXaCUaDdaDcaWzaWAaWBaWCaWDaWEaWFaIuaIuaIIdtFaScaSgaSeaKcaSfaSdaSeaQUaLJaTBaTBaWGaWHaINaSkaSkaSkaWIaSkaSkaTJaWKaINaOmaTMaRhaRhbadaRhaTPaOmaIRaDuaDvaWNaWOaDraDtaDsaDsaDsaDsaDsaDsaDEaDHaVoaVoaVoaVoaVoaDxaDyaDzaDAaDBaVtaVvaDDaOFaWWaNsahjahjahlaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaWXatwaWXawNawNaSMberbemaXaaXaaXabfAbfjaXcaSMaXdaRCaxkaXhaXhaXhbcTbchaXhbcibcSbehbekbelbelbcVbcWaORbdIbbKbaObcebcabbZbbZaBfaBeaBeaXBaXBaXBaXBaXBaXCaPeaIuaIuaXDaXEaXFaXGaXHaXIaPiaBKaBNaXLdnJaBMbnGbnGaxqauCaxwaBJbrHaBIdnFaXLaBLaBKaPiaXSaXHaXTaXUaXEaXVaIuaIuaSbaKcaXWaTAaKcaKcaKcaTAaKcaQUaKcaLJaLJaKcaKcaXXaXYaXZaSkaSkaSkaSkaYbaYcaINaYdaYeaRhaYfbheaYgaYeaYhaIRaCvaYkaYkaYlaOraCtaCnbfUaCuaCnaCnaCnaCraCjaCmaBVaBVaBVaBVaBVaCbaBOaBQaCibbQaCgaChaOFaYoaNsahlahjahjaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaYpaYqaVzaxZawNaxlaWZaTfaXaaXaaXaaSNaYsaWZaSMaYtaSjaxkaXhaYvaYwaUfaVEaXhaUnaYAaTFaORaYCaYDaNNaOZaORaTIaNLaYHaYHaYHaYHaYIaYHaYHaYJaYKaYKaYKaYLaYKaYMaYNaYOaYOaYPaYQaYQaYQaYQaYQaYQaxmaxnaYRaxpaxqaYVbkMbkMbrIbambkMaYVaxwaxxaYWaxrbkQaYWaYWaYWaYWaYWaYWaYZaYOaYOaIIaZaaZbaZcaZdaKcaKcaKcaZeaZfaZgaKcaZhaZiaZjaINaINaINaZkaZlaZlaZlaINaINaINaZmaRhaRhaZnaVPaZpaZqaNfaIRaxjaYkaZsaDOaZtcesaZvaVQaxzaZuaTTaVhbbsaDVaxAaFXaZAaRpaRpaZAaFXaZBaDVaZCaZDaxBarWaOFaOGaZFaMnaMnaOIaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaYpaYqaVzaxZawNaxlaWZaTfaXaaXaaXaaSNaYsaWZaSMaYtaSjaxkaXhaYvaYwaUfaVEaXhaUnaYAaTFaORaYCaYDaNNaOZaORaQfaNLaYHaYHaYHaYHaYIaYHaYHaYJaYKaYKaYKaYLaYKaYMaYNaYOaYOaYPaYQaYQaYQaYQaYQaYQaxmaxnaYRaxpaxqaYVbkMbkMbrIbambkMaYVaxwaxxaYWaxrbkQaYWaYWaYWaYWaYWaYWaYZaYOaYOaIIaZaaZbaZcaZdaKcaKcaKcaZeaZfaZgaKcaZhaZiaZjaINaINaINaZkaZlaZlaZlaINaINaINaZmaRhaRhaZnaVPaZpaZqaNfaIRaxjaYkaZsaDOaZtcesaZvaVQaxzaZuaTTaVhbbsaDVaxAaFXaZAaRpaRpaZAaFXaZBaDVaZCaZDaxBarWaOFaOGaZFaMnaMnaOIaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcaUcawLaZGaOLaZHaSMaZIaFfaZIaWZaZJaFaaZKaZIaSMaZLaEXawEaXhaXhaXhaQjaRbaXhaRxbNPaNMaORaYCaYDaNNaOZaORaQfaNLaYHaZVaZWaZWaZWaZXaYHaZYaZZbaababaYNaYNaYNaYNaIuaIuaHWaIAaLzaLBaJNaKWaGRaHSawXbalbqybNHbkMbkMbnIaGqbnIbkMbkMbMVbhzbaqawJawFbatbaubavbawbaxaYWaXVaIuaIuaIIaIIaIIaIIaIIbayaSbbaybazbaAaIIaIIaIIaIIaIIbaBbaCbaCbaCbaCbaCbaCbaDbaCbaBaNfbaEbaEbaFaRKaYkaYkaYkbaBaxjaYkaZsaDOaDOaDOaZwaRNaZwaDOaZwaDOaDOaDVaDVbaJbaKbaKbaKbaKbaLaDVaDVbaMaOFaxharWaOFaOFaSGaPXaPXaSGaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahjahjaqfaqfaSHaSIaSIaSIaSIaSIaSIaSJaqfaqfarkaRzawNaSMaSMaYxaSMaSMaSMaXoaSMaSMaSMbaQaYuaxWaXhcqfbaSaQjbaTaXhbaUbaVbaUaORaYCaYDaNNaOZaORaQfaNLaYHaZWbaXbaXaZWbaXaYHaZYbaYbaZbaZbbabbbbbcaYNbbdaIuaXDbcxbbgbaibbibbjbbjaymaynbblbqyaHVbkMbkMbnIbaobnIbkMbkMbczbhzbbtayqaypaysayrbbxbaxbbyaYWaXVbbzaIubdpbbBaYkaYkaYkaYkaYkaYkaYkaYkbbCaYkaYkaYkaYkbbDaYkaYkaYkaYkaYkaYkaYkaYkbbBaYkaYkaYkaYkaRKaYkaYkaYkbbEaytaYkaYkayuaYkaYkaYkaYzaYkaYkaYkaYkaYkbbDayvaYkaYkaYkaYkaYkaYkbdSayyaSDaOFayzayAaPVbbTbbUaMnaMnbbVaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlavJavNavMavMavMavMavMavMavMavMavNavMbbWaXbawNbbXbbYaXebbZbbZbbZaWaaVTbcbaOOaoTaWYaxCaXhaXhaXhaXkbcfaXhaORaORaORaORaYCaYDaXiaXjaORaQfaNLaYHaZWbcjaZWbaXbckaYHaZYbclbaZbaZbaZbcmbcnaYNbcoaIuaXDbbpbcqbaibcsbctaxNaxOaxMbcwbqybbnbnIbkMbmiaYUbmibkMbnIbbfbhzbcAbbuaxKaxFaxDbbxbaxbaxaYWaHUaIuaIubdpbbBaYkaYkaYkaYkaYkaYkaYkaYkbcEaYkaYkaYkaYkaYkaYkbcFaXlaXlaXlaXmaYkaYkbbBaYkaYkaYkaYkaRKaYkaYkaxSaWNaxUaWNaWNaWNaWNaWNaWNaXnaWNaWNaWNaWNaWNaWNaWNaWNaWNaWNaWNaWNbcLbcMbcNbcObcOaxQarWaOFaOFbcQaPXaPXbcQaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbaGbahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl @@ -9339,36 +9347,36 @@ ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlah ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjbwSbwSbCmbCnbCnbCobwSbwSbCpbCqbENbEMbvwbvwbvwbvwbvwbvwbkHbCvaTkaTkaTkaTkbCwbCwbCwbCwbCwbCwbCwbCwbCwbCwbkGbkFbkEbCAbCAbCAbCAbCAbCCbCAbCAbqxbCAbCDbCEbCDaIzaJVbCGbuCbkSbkRbCJbkVblqbuCbCMblrblbbkXblmbldbCPbCQbCRbCSbuDbkIbkJbMzbMzbggbkObkPbkLbkNbCWbCVblWbBFbXKccNbDcbDcbDcbDcbDcbDcbDcbDcbDcbDdbDdbDdbDdbDdbDdblUblxblzbvdbvdbvdbvdbvdbvdbvdbxYbpXbpXbpXbpXbpXbpXbpXbpXbNhbLEaDGaCqbgZbgZahjahjahjdsidsidsidsidsidsidsidsiahjahjahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlbDjahlahlahlahjahlahlbwWbDkbDlbHjbGObGEbGlbIdbHvbHnbHkbIhbIvahlahlahjahlbCwcjKbDvbDwbDxbDybmnbmobmpbmqbmHbmFbmIbCAbmKbmJbmLbFhbmvbFhbFhbIIbmCbmxbmEbCDbCDbCDbCDbuCbmMbxobyTbxobnybuCbDVbDTbnvbmXbmPbmObmPbmPbnFbDYbDZbnEbnCbnCbnCbnJbnHbqMbEcbEdbEebEfbEgbBFbXKccNbDcbEhbEhbEhbEibEhbEhbEhbDcbEjbEjbElbEjbEjbDdbnLbnKbepaKtbEobEpbEqbErbEsbEtbEubEvbEwbExbEyaQebnMciIciIciObnPbEobEobgZahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlbEEbEFbEGbEFbEHahlahjahlbwWbwWbEIbylbQcbQbbQtbQebPGbPGbPPbPJbPzbppahjbEPbEQbERbESbETbDBbEUbDBbEVbDBbDBbDBbCwbQLbQMbtxbCAbtwbtubFebFfbFgbFhbFibqxbCAbFjbFkbtDbFmbuJbFobFpbuObxobFrbxoblrbuxbuEbuzbuFbuCbFvbuIbxobxobusbFzbnTbnTbnTbnTbnTbudbuobLhbupburbFCbCVbucbBFbXKccNbDcbEhbEhbEhbEhbEhbEhbEhbDcbFHbubbFJbFKbFLbDdbtUbtZbuabtXbtYbHqbtKbFQbFQbFQbFQbFRbTubFTbEybgZbLFbtIbQxbQxbtJbFVbFWahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjbFXbFYbFXahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlbFZbGabGbbGabFZbGcbGdbGebwWbGfbylbGgbQCbQvbGibwWbCvbGjbCvbCvboEbqNahlbGmbGnbGobGpbDBbDBbGqbDBdnRbGsbGtbDBbCwbQLbuQbuRbCAbuPbGybGzbGAbGBbFhbuUbqxbsfbuScdQbuTcdQbwebGKbuCbwgbmPbwfbmPbvVbsUbvSbmObvWbuCbGRbxobxobxobGSbGTbnTbGUbwjbwkbwibggbwhbqMbGYbCVbCVbGZbHabHbccPbvcbDcbEhbEhbEhbEhbEhbEhbEhbDcbHebuZbuYbvubvxbvAbvHbvIbscbvRbHobFQbvebFQbFQbFQbFQbFQbFQbFQbEybuXbuWbuVbHwbHxbHybHzbHAahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjbHBbFXbHCbFXbHBahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahjahlbEGbHDbHEbHDbEGbHFbHGbHHbwWbHIbylbHJbylbylbGibwWbHKbHLbELbCvboEboFahjbGmbHNbHObHPbHQbHRbHQbHQbHSbHTbHQbHQbHUbqubeLbHXbCAbCBbCAbCAbCAbCAbHYbPxbPmbHZbIabIbbIcbrObIcbIfbuCbrMbrLbIibrNbrGbuCbrKbrJbrpbuCbIobrEbIqbrgbIsbItbnTbgdbrbbrcbqWbqYbrabIxbIybIzbCVbCVbIAbBFbsfccNbDcbDcbICbEhbEhbIDbICbDcbDcbIEbIFbIGbsebIHbDdbsdbhibscbsabsbbrVbrVbrWbrXbrUbrVbrPbrQbqGbqDbqIbqHbqVbPybIWbIXbIYbIZahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjbJabJbbJcbJdbJebJbbJaahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlbFZbGabGbbGabFZbGcbGdbGebwWbGfbylbGgbQCbQvbGibwWbCvbGjbCvbCvboEbqNahlbGmbGnbGobGpbDBbDBbGqbDBdnRbGsbGtbDBbCwbQLbuQbuRbCAbuPbGybGzbGAbGBbFhbuUbqxbXKbuScdQbuTcdQbwebGKbuCbwgbmPbwfbmPbvVbsUbvSbmObvWbuCbGRbxobxobxobGSbGTbnTbGUbwjbwkbwibggbwhbqMbGYbCVbCVbGZbHabHbccPbvcbDcbEhbEhbEhbEhbEhbEhbEhbDcbHebuZbuYbvubvxbvAbvHbvIbscbvRbHobFQbvebFQbFQbFQbFQbFQbFQbFQbEybuXbuWbuVbHwbHxbHybHzbHAahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjbHBbFXbHCbFXbHBahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahjahlbEGbHDbHEbHDbEGbHFbHGbHHbwWbHIbylbHJbylbylbGibwWbHKbHLbELbCvboEboFahjbGmbHNbHObHPbHQbHRbHQbHQbHSbHTbHQbHQbHUbqubeLbHXbCAbCBbCAbCAbCAbCAbHYbPxbPmbHZbIabIbbIcbrObIcbIfbuCbrMbrLbIibrNbrGbuCbrKbrJbrpbuCbIobrEbIqbrgbIsbItbnTbgdbrbbrcbqWbqYbrabIxbIybIzbCVbCVbIAbBFbXKccNbDcbDcbICbEhbEhbIDbICbDcbDcbIEbIFbIGbsebIHbDdbsdbhibscbsabsbbrVbrVbrWbrXbrUbrVbrPbrQbqGbqDbqIbqHbqVbPybIWbIXbIYbIZahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjbJabJbbJcbJdbJebJbbJaahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlbFZbHDbHDbHDbJfbJgbylbylbJhbHIbylbylbylbylbGibwWbfFbELbccbCvboEbtFahlbGmbJmbJnbJobDBbDBbJpbDBbJqbJrbJsbJtbCwbshbsgbsobsmbsxbsvbsvbsvbsvbsvbsybsvbsBbszbsFbsCbsVcePchtbsUbsUbsUbsUbsUbsUbsUbsUbsUbsUbsUbsUbsUbsUbsUbsUbtbbnTbnTbnTbnTbnTbtabuAbhSbBFbBFbBFbBFbBFbBFbXKccNbDcbJQbJRbJSbJTbJUbJVbJQbJWbIEbIFbIGbtpbtqbtrbtsbthbtmaKvbEobKabKabKbcGybtdbKebFQbFQbKfbEybsHbKhbsMbEobKjbKkbKlbEoahjahlahlahjahlahlahlahlahjahlahlahlahlahjahlahlahlahlahjahlahjahjbKmbKnbKobKpbKpbKpbKqbKmbKnahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlbEGbHEbHEbHEbEGbKrbKsbKtbKubKvbylbylbKwbEKbKxbwWbCvbCvbCvbCvboEbppahjbKybEQbKzbKAbKBbDBbKCbDBbDBbDBbDBbDBbCwbQLbhhbgYbgLbgKbgKbgKbgKbgKbgKbgJbgIbgHbfLbgGbgBbfRbfQbfSbmNbfTbmNbmNbmNbmNbmNbmNbmNbmNbmNbmNbmNbmNbmNbfVbgabnTbgdbLdbMzbgebggbgibgkbglbgobgobgxbfMbfLbfKbfJbDcbLrbLsbLtbLubLvbLwbLxbJWbJWbJWbJWbJWbJWbLybfNbfObfPbLBbEobEybEybEybEybEybEybLDbFQbFQbEybgZbLFbLEbEobLGbLHbLIbLJdsidsiahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjahjbLKbLLbLKbKpbLMbKpbLNbLObFXahjahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlbFZbLPbLQbLRbFZbLSbGdbGebwWbwWbLTbLUbLVbwWbwWbwWahlahlahlbLWbqhbqNahlahlahjahlbCwbLYbLZbMabDBbMbbiEbiJbiSbKGbiDbiCbfIbMibMjbMkbMlbMmbesbMjbMjbMjbMjbMjbMobiBbMjbMjbxtbMjbFSbMjbMjbMjbMjbMjbCDbCDbCDbCDbCDbCDbCDbCDbNIbXIbnTbhHbhFbhGbhMbicbhIbqgbipbhpbhpbiobhpbhpbhsbhqbDcbhwbMNbhCbMNbhEbMNbMObMPbMQbMRbMSbMTbMUbgUbribhibepbMXahjbMYbMZbNabNbbhmbNbbNdbNebNfbEyckEbNhbiubEobEobEobEobEoahjahlahlahjahlahlahlahlahjahlahlahlahlahjahlahlahlahlahjahlahjahjbKmbKnbNjbKpbKpbKpbNkbKmbKnahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlbNlbEFbNmbEFbNnahlahjahlahjdsiahjahlahjdsiahjahlahlahlahjbHMboEboFahjahjahjahjbCwbCwbCwbCwbCwbCwbCwbCwbCwbCwbeybexbewbevbMjbMkbMlbMmbesbNrbNrbNtbNubNvbeubetbNybNzbNAbdWbNCbNDbNEbNFbOGcGaahjahlahlahlahlahlahjbCDbNIbSubNJbNJbNJbNJbNJbNKbNLboDbNJbNJbNJbNJbNJbNJbSubencGubNQbNRbNSbNRbNTbNUbNVbNWbNWbNWbNWbNWbNWbNXbeqbeobepbObahjbMYbOcbOcbOdbOebOfbOgbOhbOibEycoxbNhbPqbgZbOkayRbgZahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahlahlahlahlahjahjbJabHBbOmbOnbOobOpbJaahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlahlahlahlahlahjahlahjdsiahjahlahjdsiahjahlahlahlahlbHMboEboFahlahlahlahjbOqbOrbOrbOsbOtbOubOubOwbOwbOqbQLbfHbfIbOzbMjbOAbOBbOBbfibODbNrbOEbOFbfrbfCbfsbeMbeHbmgbeBbOGbOLbOGbOMbONbOOahjbOPbOPbOPbOPbOPahjbCDbNIbpaboQbezbOSbOTbNJbpnbpgbphbNJbOXbOYbOZbOYbOXbSubeTbDcbMNbMNbMNbeZbMNbMNbfhbeUbPcbPcbPgbPcbPcbgSbePbeNbeObPkahjbMYbOcbPlbNbbeSbNbbPnbPobPpbEyblAbNhbPqbgZblAblAbgZahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjbJbbFXbPrbFXbPsahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahlahlahlahlahlahlahlahjahjahjahjahjahjahjahjahjahjahjbCvbCvbPtbPubPvbCvbCvahlahlahlahlbHMboEboFahlahlahlahjbOqbPwbOsbOsbOsbOsbOubCsbzObBqbDIbiCbjWbPBbPCbjVbjUbjTbkabkcbkbbjUbjUbjUbkabjZbjEbjDbjMbPHbPKbTqbPMbPNbPObTnbPQbPRbPSbPTbPUbOPahjbjRbNIbSubPWbOXbOXbOXbNJbjNbeAbjPbNJbOYbQdbOYbzNbzMbyObjLbDcbQfbQgbQhbQibQjbQkbQlbQmbQnbQobQpbQqbQrbJWbSSbjBbjCbQubQubEybEybEybEybEybEybEobEobEobEybjzbNhbjyblAblAbQzbgZahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjbFXbFYbFXahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahlahlahlahlahlahlahlahjahjahjahjahjahjahjahjahjahjahjbCvbCvbPtbPubPvbCvbCvahlahlahlahlbHMboEboFahlahlahlahjbOqbPwbOsbOsbOsbOsbOubCsbzObBqbDIbiCbjWbPBbPCbjVbjUbjTbkabkcbkbbjUbjUbjUbkabjZbjEbjDbjMbPHbPKbTqbPMbPNbPObTnbPQbPRbPSbPTbPUbOPahjbjRbNIbSubPWbOXbOXbOXbNJbjNbeAbjPbNJbOYbQdbOYbzNbzMbyObjLbDcbQfbQgbQhbQibQjbQkbQlbQmbQnbQobQpbQqbQrbJWbSSbjBbjCbQubQubEybEybEybEybEybEybEobEobEobEyblAbNhbjyblAblAbQzbgZahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjbFXbFYbFXahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlbCvbQAbELbQBbELaClbCvahlahlahlahlbHMbqhboFahlahjbQDbQEbOqbQFbQGbQHbOsbOsbQIbQJbOubQKbQLbfHcerbQNbQObkubkwbkvbkBbkAbkCbkvbkxbkvbkzbkybPIbQVbQWbQXbQYbQZbRabRbbRcbTsahjbRebRfbPUbRgbOPahjcbMbNIbSubRibRjbOXbRkbNJbRlbEJbktbNJbOXbvEbRpbOXbOXbSubNIbDcbJWbJWbJWbJWbLybRtbRubRvbLybJWbJWbJWbJWbJWbRwcfbbUIbRzbRAbRBbRCcbGbRCbREbQubRFbRybRGbRHcjSbNhbPqbgZbgZbgZbgZbRJahjahjahjdsidsidsidsidsidsiahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahjahjahjahjbCvazvbELbELbELaBdbCvahlahlahlahlbHMboEbtFahlahjbTabRNbRObRPbtWbtHbtHbtHbtHbtHbujbvkbvvbfHcerbNqbjdbjcbjbbOGbjebRZbQVbSbbScbSdbSebSfbSfbSgbShbPKbSibSjbSkbSlbSmbMrbSobPRbSpbPUbPUbOPahjbiXbNIbSubdobOXbSsbNKbNJbNJbrFbNJbNJbSvbrAbStbSvbSzbSubNIbDcbSDbSEbSEbSFbSGbMNbSHbSIbSJbSKbEhbEhbEhbJWbSLbiYbiZbSMbSNbRBbSObSPbMsbSRbSSbRybSTbRybRHaDGbiUbiVbgZahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlbCvazvbELbELbSYaBgbCvahlahjahlahlbJlboEbppbCvbCvbCvbTbbOqbTcbOsbOsbOsbTdbTebTfbTgbOqbQLbfHcerbNqbQObjtbjxbOGbOGbTjbNrbTkbTlbTmbSQbOGbOGbTobTpbRdbTrbPLbTtbOJbTtbTvahjbOPbOPbOPbOPbOPahjbCDbNIbSubTwbyybyybyKbynbypbwNbjibjgbOXbvEbOXbOXbOXbSubNIbDcbEhbEhbEhbTJbTKbMNbTLbMNbTMbTNbEhbEhbEhbJWbTObjmbjqbYbbjsbTRbTSbTTbTRbTUbQubTVbRybTWbRHbgZcgFbjfbgZahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaeahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlbTXahlahjahjbTYbTYbTYbTYbTYbTYbTYbTYbCvbCvbTZbCvbCvbCvbPtbPubPvducduddujduidukdrBdudduhbvkbvkbvkbvkbvkbvkbvkbvkbvkdugduedufcerbUdbMjbNscaGbUebUfbUebNrbOGbOGbOGbSQbUibONbONbUjchfbUlbTqbUmbUpbUobTnbPQbPRbUqbUrbUrbOPahjbCDbNIcaVbPZbPZbPZcbhbUsbOXdulbOXbOXbOXbvEbOXbOXbOXbSubNIbDcbEhbEhbEhbUAbUBbSIbUCbMNbUDbUEbSEbSEbUFbJWbUGbUHbUIcbzcbjbRBbMsbUKbTRbULbQubUMbUMbUMbRHcaUbZPbjfbgZahjahjahjahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlbUObUPbUQbURbUSbURbUTbUUbUVbUWbUXbUYbUZbTYbVabVbbVbbVbbVbbVbbVbbVbbVbdsHdtidtJdrldrldrldrldtHdtpdtpdtpdtxdtpdtmbPGbPGdtkbppbQLbfHcerbVobVpbZNbZMbONbONbZLbVsbONbONbVtcgqbVvbOGbVwbVxbVybVzbOGcgrbUnbVCbTsahjbRebVDbVEbVFbOPahjcaSbZRbZQbZQbZQbZSbSubVKbTwdtRdtOdtVdtSdtYdtXduadubbSubNIbDcbJWbJWbJWbJWbVRbVSbTLbVTbVRbJWbJWbJWbJWbJWbVUbVVbVWcaCcaBbVZbVZbVZbVZcaFbSSbUMbUMbWcbRHbZObZPbjfbgZbgZbgZahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlbWebWebWebWebWebWfbWgbWhbWibWibWhbTYbELbWjbWkbWkbWkbWkbWkbWkbWlbppdcdbWnbWnbWnbWnbWnbWnbWnbWnbWobWobWobWobWocbNdumbppbQLbfHcerbVobWscceccfbWvbSfcbVbWxbSfbSfbWybWzbWAbWBbWCbWDciobWFbOGcgrbWGbWHbMrbSobPRbWJbUrbUrbOPahjcbMbXKbCDbCDbCDbjLbSubWNbOXbOXbWPduwbUtbWTcbUbWTbUtbSubNIbDcbSDbSEbSEbWUbSGbMNbSHbSIbWVbWWbEhbEhbEhbJWbWXbWYbWZbRxbjmbYbccuccwccvccibQubUMbUMbUMbRHbZObZPbjfblAblAbgZahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjbXcbXdbZnbXfbZnbXgbXhbZschmchmbXkbTYbXlbXmahlahlahjahlahlahjahlbppdcdbWnbXnbXobXpbXqbXrbXsbXnbXtbXubXvbXwbWobWodumbppdunbfHcerbXybXzcbDcbDbXCbMjbMjbMjbMjbMjbXDchjbNrbNrbNrbXFbOGbVybOGcgrbUnbXGbTsahjbOPbOPbOPbOPbOPahjbXHbXKbCDcbobXKbjLbpadusdurduvdutduqdupbXPcbUbXPbXQbSubNIbDcbEhbXRbEhbXSbTKbMNbTLbMNbTMbXTbEhbXRbEhbJWbXUbXVbXWbXXbXYbXZbYacbQcbPcbFbSSbCxbYfchUbRHbUMbZPbUwbgZblAbgZbgZbgZdsidsiahjahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlbUObUPblMbsfbUSbsfbSnbURbUQbUWbUXbUYbUZbTYbVabVbbVbbVbbVbbVbbVbbVbbVbdsHdtidtJdrldrldrldrldtHdtpdtpdtpdtxdtpdtmbPGbPGdtkbppbQLbfHcerbVobVpbZNbZMbONbONbZLbVsbONbONbVtcgqbVvbOGbVwbVxbVybVzbOGcgrbUnbVCbTsahjbRebVDbVEbVFbOPahjcaSbZRbZQbZQbZQbZSbSubVKbTwdtRdtOdtVdtSdtYdtXduadubbSubNIbDcbJWbJWbJWbJWbVRbVSbTLbVTbVRbJWbJWbJWbJWbJWbVUbVVbVWcaCcaBbVZbVZbVZbVZcaFbSSbUMbUMbWcbRHbZObZPbjfbgZbgZbgZahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlbWebWebWebWebWebWfbUTbWhbWibWibWhbTYbELbWjbWkbWkbWkbWkbWkbWkbWlbppdcdbWnbWnbWnbWnbWnbWnbWnbWnbWobWobWobWobWocbNdumbppbQLbfHcerbVobWscceccfbWvbSfcbVbWxbSfbSfbWybWzbWAbWBbWCbWDciobWFbOGcgrbWGbWHbMrbSobPRbWJbUrbUrbOPahjcbMbXKbCDbCDbCDbjLbSubWNbOXbOXbWPduwbUtbWTcbUbWTbUtbSubNIbDcbSDbSEbSEbWUbSGbMNbSHbSIbWVbWWbEhbEhbEhbJWbWXbWYbWZbRxbjmbYbccuccwccvccibQubUMbUMbUMbRHbZObZPbjfblAblAbgZahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjbXcbXdbUUbXfbUUbWgbUVbXhbXgbXgbXkbTYbXlbXmahlahlahjahlahlahjahlbppdcdbWnbXnbXobXpbXqbXrbXsbXnbXtbXubXvbXwbWobWodumbppdunbfHcerbXybXzcbDcbDbXCbMjbMjbMjbMjbMjbXDchjbNrbNrbNrbXFbOGbVybOGcgrbUnbXGbTsahjbOPbOPbOPbOPbOPahjbXHbXKbCDcbobXKbjLbpadusdurduvdutduqdupbXPcbUbXPbXQbSubNIbDcbEhbXRbEhbXSbTKbMNbTLbMNbTMbXTbEhbXRbEhbJWbXUbXVbXWbXXbXYbXZbYacbQcbPcbFbSSbCxbYfchUbRHbUMbZPbUwbgZblAbgZbgZbgZdsidsiahjahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjbXcbYjbYkbYlbYmbWhbYnbWhbYobWhbWhbYpbELbXmahlahlahjahlahlahjahlbppdcdbWnbXnbYqbYrbYsbYtbYubXnbYvbYwbYxbYybYzbWodumbppbQLbfHcerbYAbYBbMjcdvbYDbMjcdwcuLbYGbMjbYHbSQbZUbNrbYJbWFbOGbWDbYKbYLbUpbYMbTnbPQbPRbYNbYObYPbOPahjbCDbXKbCDbYQbXKbjLbSubYRduzbYTbYUduAduzcdHcdAcdHbzNbyObNIbDcbEhbEhbEhbYZbZabSIbUCbMNbUDbZbbSEbSEbUFbDcbRHbZcbZdbZebRHbRHbZfbZgcdMcdNbZjbVYbVZbZkbUMbUMbZPbjfbgZbrqbgZbZlbgZahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahjbXcbZmbZnbZobZnbZpciqbZrbZsbZtbZubTYbZvbZwahlahlahlahlahlahlahlbppdcdbWnbZxbZybZzbYsbZAbZxbZxbYvbZBbZCbYyccAbWodumbppbQLbfHbGwcbAcbAccWccBccQcdbcdlccXduxbMjbOGbSQdjybZVbYJbZWbOGbWDbYKcgrbUnbZXbTsahjbReclkbZZcaabOPahjbCDbXKbCDcabcacbjLbSubNJcadcaebNJduybNJbNJbNJbNJbNJbSubNIbDcbJWbJWbJWbJWbVRcafbTLcagbVRbJWbJWbJWbJWbDcbTRcahbTRbTRbTRbRHbZfbZgcdtcducakcalbRxbCzbRHbUMbZPbjfbgZblAblAblAcanahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaGcahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahjahjahjahjahjahjahjahjahjahjbWebWebWebWebWebTYbTYbYpbTYbTYbTYbTYahjahlahlaPYahlahlahlahlahlduNdcdbWnbZxbZxcarcasbXnbZxcatcaucavcawcaxcaybWodumduMduJduKcexcbAcaDcaEcaEceJcaHcaIceKduLbMjcaLcjIbZUbNrbYJcaNbOGcaObYKcgrcaPcaQbMrbSobPRcaRbYObYObOPahjcaSbXKbCDcaTbXKbjLceQbPZbPZceObNJduOdpDdpCbNKcaZccmbXIbNIbDcbSDbSEbSEcbbbSGbMNbSHbSIcbccbdbEhbEhbEhbDccbebTRbTRbTRbTRbRHcbfcbgceMceLbQubQubRxbQubRHbQubZPbjfbgZcbkcblcbmcbnahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahjbXcbZmbUUbZobUUbZpbZnbZrbXhbXhbZubTYbZvbZwahlahlahlahlahlahlahlbppdcdbWnbZxbZybZzbYsbZAbZxbZxbYvbZBbZCbYyccAbWodumbppbQLbfHbGwcbAcbAccWccBccQcdbcdlccXduxbMjbOGbSQdjybZVbYJbZWbOGbWDbYKcgrbUnbZXbTsahjbReclkbZZcaabOPahjbCDbXKbCDcabcacbjLbSubNJcadcaebNJduybNJbNJbNJbNJbNJbSubNIbDcbJWbJWbJWbJWbVRcafbTLcagbVRbJWbJWbJWbJWbDcbTRcahbTRbTRbTRbRHbZfbZgcdtcducakcalbRxbCzbRHbUMbZPbjfbgZblAblAblAcanahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaGcahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahjahjahjahjahjahjahjahjahjahjahjbWebWebWebWebWebTYbTYbYpbTYbTYbTYbTYahjahlahlaPYahlahlahlahlahlduNdcdbWnbZxbZxcarcasbXnbZxcatcaucavcawcaxcaybWodumduMduJduKcexcbAcaDcaEcaEceJcaHcaIceKduLbMjcaLcjIbZUbNrbYJcaNbOGcaObYKcgrcaPcaQbMrbSobPRcaRbYObYObOPahjcaSbXKbCDcaTbXKbjLceQbPZbPZceObNJduObZsdpCbNKcaZccmbXIbNIbDcbSDbSEbSEcbbbSGbMNbSHbSIcbccbdbEhbEhbEhbDccbebTRbTRbTRbTRbRHcbfcbgceMceLbQubQubRxbQubRHbQubZPbjfbgZcbkcblcbmcbnahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHaaHaaHdpXdpXaaHdpXdpXdpXaaRdpXdpXdpXaaHdpXahjahjbCvbELbELbELbELbELbELbELbELbJjcbpahjahlahlahjdsiaFFahlahlahldotdcdbWncbscbtcascbubXnbXncbvcbwcbvcbxbYycbybWoduCduBduDduEbHXcbAdpFcaEcdOcdzcbEduGcdPduFduHbPHcirbNrbNrbNrcbJbOGcbKcbLcgrbUnbOGbTsahjbOPbOPbOPbOPbOPahjcbMbXKbCDcchcbObZRbZQbZQceocepbNKduIcuYdpBbNKceabhpcdTcbWbDcbEhbEhbEhcbXbTKbMNbTLbMNbTMcbYbEhbEhbEhbDccbZbTRccabTRbTRccbcccccdcemcebbQubRxbRxccgbRHaDGbPdbWdbgZccjcckblAcclahjahlahlahlahlahlaaeahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHahlahlahjahjahlahjahjahlahlahjahjahjahldpXahlahlbCvbRKbELbCvbCvbCvbTZbCvbCvbCvbCvahlahlahldsiaDIauKdsidsiahjdotdcdbWnccpbZxbXnbXnbXnbZxcatccqccrbYyccscctbWobCvbCvbTzbTAbTBcbAcbAccxcaEdoZdoKdoMdoNdoQbMjbOGbVAccDccEccFbQWccGbVuccIbYLbUpccJbTnbPQbPRccKccLccLbOPahjbXHbXKbCDbCDbCDbXKbCDbCDccMbDbbCDbCDcuBbCDbCDbDbbSWbSXbThbDcbEhbEhbEhccRccSbSIccTbMNbUDccUbSEbSEbUFbDcbTRbTRccVbTRbTRbRHcbfcbgbTibTxbQuccYccZcdabRHbfGbPdbjfbgZbgZbgZblAbgZahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHahlcdccddcdeahlcdccddcdeahlcdccddcdeahjdpXahlahlbCvcdfcdgbCvcdhbELbELbOlaClcdkbCvahlahlahlatIdsidsiahjahlahldbVdcdbWnbZxcdncdobXncdpbZxbZxbYvcdqbYybYycdrbWocdsbSVbSCbSUbSBdoidnZdcNdctdcNdctdcvdctdcubMjcdCcdDcdEbSfbSfbShbUicdFbUmbSibUncdGbTsahjbReclhcdIcdJbOPahjbCDbXKbXKcdKbXKbXKcdLbCDccMbSabRYbSqbSnbSwbRYbSAccMbLEcdVbDcbDcbDcbDcbDcbDccdWcdXcdYbDcbDcbDcbDcbDcbDcbRHbRHbRHbRHbRHbRHcdZcdZbSxbSybRHbRHbRHbRHbRHbgZcgFbjfbgZbNibOjblAbgZahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHahlcdcceecdeahlcdcceecdeahlcdcceecdeahjahjahlahlbCvbPtbPvbCvbCvcefcegaClbELbSYbCvahlahlahlahlahjahlahlahlahlbppdcdbWnbXncehceibXncejcekbXnbYvcelbYxbYybYybVebVfbfIcercHqbVgceucevcewbVhceycezdpYcaEdqsbMjceBbOGbVAbUibONceCbWEceEceFbNFceGceHbMrbSobPRceIccLccLbOPahjbCDbXKbXKbXKbXKbXKbUzbCDbVdbUxbUNbJFbfKbJFbUJbUxbUybLEbTEbgZahlahlahlahjahlahlceVahlahjahlahlahlahlbgZceWayRceYceZceZbRHcfacfabSxbiZcfccfdblAblAblAaDGcgFbUwbgZcffblAblAbgZbgZbgZahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahldpXahjcdcceecdeahlcdcceecdeahjcdcceecdeahjahjahlahlahlahlahjahjbCvbCvbCvbCvbTZbCvbCvahlahlahlahlahjahlahlahjahlbppdcdbWnbXncfgcfhcficfjcfkbXncflcfmcfncfocfpbWocfqdpVdpPdpQdpNdpOdpTdpUdpRdpSdpsdpzdpadprdpAdpEbQZcfFbVBbOGbOGbOGbOMbVvbVBbUnbXGbTsahjbOPbOPbOPbOPbOPahjbCDcabcfHcfIcfJcacbCDbCDbCDcfKbTGcdUbXKcfMbTFbCDbCDbLEbTEbgZahlahlahlahjahlahlceVahlahjahlahlahlahlbgZblAbjzbrsbjzblAbRHcfScfSbTDbiZbRHbQubgZcfUcfVaDGcgFbTCbECbECbECcfYcfZcgacfZcgbdsiahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlcdcceecdeahjcdcceecdeahlcdcceecdeahlahjahlahlahlahlahlahlbCvaOlbCvbELbELbCvahjahlahjahlahlahjahlahlahjahlbppdcdbWnbWnbWnbWnbWnbWnbWnbWnbWobWobWobWobWobWobCvbWpbCvcggcghcghcghcgicgjcgkcghbWrdqEdqRbMjchebXEbSkbXjcgscgtcgsbXjcgubXjcgvbUicgwahjahjahjahjahjahjahjahlahjcbMbXKcbMahjahlbCDcgxbCDcgzcgzcgAcgzcgzbCDbYQbzgbTEbgZcgCcgDcgEbgZcgCcgDcuncgEbgZcgCcgDcgDcgEbgZbgZbgZcgGbgZbgZbRHbRHbRHbWabWbbRHaDGbgZcbmblAbpYcgFbWdbgZbgZcgLbgZbgZbgZbgZahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHaaHdpXahjahlcdcceecdeahjcdcceecdeahlcdcceecdeahjahjahjahjcgMcgNcgNcgNcgNbCvbCvcgObELbCvcgPbWkbWkbWkbWkbWkbWkbWkbWlbCvbppdcdbCvcgQbVPbVObVObVObVObVObVObVObVObVObVXbVXbVObVQcefcggcnjcgWcgXcgYcgZchacghdoBcmIdqxbMjchebXichgchhchibWIchkchlbOGbXechnchobOIahjahjahlahlahlahlahjahlahjchpcfIchpahjahlbCDchqbsfbVicdUbsfcdUcdUbXKbXKbzgbJEbVHbVHbVHbVHbVHbVHbVHbVIbVqbVqbVqbVqbVqbVqbVrbVqbVqbVqbVqbVGciFbVlbVkbVjbVnbgZbgZbVmciFbVJciFbVLbjfbgZchLblAblAbgZahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHahlahjahlahjahjchMahjahjahjchMahjahlahjchMahjahlahjchNchOchPchQchRchSchTcgebELchYchZciachZchZchZchZchZchZchZchZchZchZdsrdsydrBdrAbiTcicciccicciccicciccicciccicciccicciccicciccggcghciecifdsbbZDbZEbZFckUckbdspciccincfGcipceDcipcfGcipceDcipccHcipccHcisahjahjahlahlahlahlahjahlahjahlahlahlahjahlbCDchqbXKcdUcjMbYWbYVceTbFobXabXbbWQbWQbWQbWQbWQbWQbWQbWRbWSbWQbWQbWQbWQbWQbWQbYIbYEbYhchEbYCbYibYcbYcbYcbYdbXAbXxbXObXBbYYbYcbYcbYXbZhbgZbOjblAcbabgZahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahldpXahjciRciSciSciTciUciUciUciUciUciUciUciUciUciUciUciVciXciYciXciZdrvcjbcbHchZcjdcjeaClbCvcjgcjhcjhcjhcjhcjhcjhcjhcjibCvbCvdrqdrldrjdrgciccjncjncjociccjpcpFcpEcpCcpOcpNcjvcmvcjxcjycghcjzcjAdracjCcjDcjEcjHdrbdrdcicahjcbIahjcaMahjcbIahjcaMahjbZqahjbZqahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlbCDbXKcjLcjMccPcjObXJbFobSZbWqbCDbgZcgCcgDcgDcgEbgZcgCcgDcgDcgEbgZcgCcgDcgDcgEbgZcpGblAbgZbWKbWwbgZbgZcgCcgEbgZbgZcjTbPdbPbbgZcjUcjVbpWbgZbgZbgZbgZbgZahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHahlcdccddcdeahlcdccddcdeahlcdccddcdeahjdpXahlahlbCvcdfcdgbCvcdhbELbELbOlaClcdkbCvahlahlahlatIdsidsiahjahlahldbVdcdbWnbZxcdncdobXncdpbZxbZxbYvcdqbYybYycdrbWocdsbSVbSCbSUbSBdoidnZdcNdctdcNdctdcvdctdcubMjcdCcdDcdEbSfbSfbShbUicdFbUmbSibUncdGbTsahjbReclhcdIcdJbOPahjbCDbXKbXKcdKbXKbXKcdLbCDccMbSabRYbSqbZtbSwbRYbSAccMbLEcdVbDcbDcbDcbDcbDcbDccdWcdXcdYbDcbDcbDcbDcbDcbDcbRHbRHbRHbRHbRHbRHcdZcdZbSxbSybRHbRHbRHbRHbRHbgZcgFbjfbgZbNibOjblAbgZahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHahlcdcceecdeahlcdcceecdeahlcdcceecdeahjahjahlahlbCvbPtbPvbCvbCvcefcegaClbELbSYbCvahlahlahlahlahjahlahlahlahlbppdcdbWnbXncehceibXncejcekbXnbYvcelbYxbYybYybVebVfbfIcercHqbVgceucevcewbVhceycezdpYcaEdqsbMjceBbOGbVAbUibONceCbWEceEceFbNFceGceHbMrbSobPRceIccLccLbOPahjbCDbXKbXKbXKbXKbXKbUzbCDbVdbUxbUNbJFcgAbJFbUJbUxbUybLEbTEbgZahlahlahlahjahlahlceVahlahjahlahlahlahlbgZceWayRceYceZceZbRHcfacfabSxbiZcfccfdblAblAblAaDGcgFbUwbgZcffblAblAbgZbgZbgZahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahldpXahjcdcceecdeahlcdcceecdeahjcdcceecdeahjahjahlahlahlahlahjahjbCvbCvbCvbCvbTZbCvbCvahlahlahlahlahjahlahlahjahlbppdcdbWnbXncfgcfhcficfjcfkbXncflcfmcfncfocfpbWocfqdpVdpPdpQdpNdpOdpTdpUdpRdpSdpsdpzdpadprdpAdpEbQZcfFbVBbOGbOGbOGbOMbVvbVBbUnbXGbTsahjbOPbOPbOPbOPbOPahjbCDcabcfHcfIcfJcacbCDbCDbCDcfKbTGcdUbXIcfMbTFbCDbCDbLEbTEbgZahlahlahlahjahlahlceVahlahjahlahlahlahlbgZblAchmbrscOnciqbRHcfScfSbTDbiZbRHbQubgZcfUcfVaDGcgFbTCbECbECbECcfYcfZcgacfZcgbdsiahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlcdcceecdeahjcdcceecdeahlcdcceecdeahlahjahlahlahlahlahlahlbCvaOlbCvbELbELbCvahjahlahjahlahlahjahlahlahjahlbppdcdbWnbWnbWnbWnbWnbWnbWnbWnbWobWobWobWobWobWobCvbWpbCvcggcghcghcghcgicgjcgkcghbWrdqEdqRbMjchebXEbSkbXjcgscgtcgsbXjcgubXjcgvbUicgwahjahjahjahjahjahjahjahlahjcbMbXKcbMahjahlbCDcgxbCDcgzcgzdpdcgzcgzbCDbYQbzgbTEbgZcgCcgDcgEbgZcgCcgDcuncgEbgZcgCcgDcgDcgEbgZbgZcgFcgGbgZbgZbRHbRHbRHbWabWbbRHaDGbgZcbmblAbpYcgFbWdbgZbgZcgLbgZbgZbgZbgZahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHaaHdpXahjahlcdcceecdeahjcdcceecdeahlcdcceecdeahjahjahjahjcgMcgNcgNcgNcgNbCvbCvcgObELbCvcgPbWkbWkbWkbWkbWkbWkbWkbWlbCvbppdcdbCvcgQbVPbVObVObVObVObVObVObVObVObVObVXbVXbVObVQcefcggcnjcgWcgXcgYcgZchacghdoBcmIdqxbMjchebXichgchhchibWIchkchlbOGbXechnchobOIahjahjahlahlahlahlahjahlahjchpcfIchpahjahlbCDchqdpkbVichtdpDcdUcdUbXKbXKbzgbJEbVHbVHbVHbVHbVHbVHbVHbVIbVqbVqbVqbVqbVqbVqbVrbVqduQbVqbVqbVGciFbVlbVkbVjbVnbgZbgZbVmciFbVJciFbVLbjfbgZchLblAblAbgZahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHahlahjahlahjahjchMahjahjahjchMahjahlahjchMahjahlahjchNchOchPchQchRchSchTcgebELchYchZciachZchZchZchZchZchZchZchZchZchZdsrdsydrBdrAbiTcicciccicciccicciccicciccicciccicciccicciccggcghciecifdsbbZDbZEbZFckUckbdspciccincfGcipceDcipcfGcipceDcipccHcipccHcisahjahjahlahlahlahlahjahlahjahlahlahlahjahlbCDchqduRcdUduSbYWbYVceTbFobXabXbbWQbWQbWQbWQbWQbWQbWQbWRbWSbWQbWQbWQbWQbWQbWQbYIbYEbYhchEbYCbYibYcbYcbYcbYdbXAbXxbXObXBbYYbYcbYcbYXbZhbgZbOjblAcbabgZahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahldpXahjciRciSciSciTciUciUciUciUciUciUciUciUciUciUciUciVciXciYciXciZdrvcjbcbHchZcjdcjeaClbCvcjgcjhcjhcjhcjhcjhcjhcjhcjibCvbCvdrqdrldrjdrgciccjncjncjociccjpcpFcpEcpCcpOcpNcjvcmvcjxcjycghcjzcjAdracjCcjDcjEcjHdrbdrdcicahjcbIahjcaMahjcbIahjcaMahjbZqahjbZqahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlbCDbXKcjLcjMduTcjObXJbFobSZbWqbCDbgZcgCcgDcgDcgEbgZcgCcgDcgDcgEbgZcgCcgDcgDcgEbgZcpGblAbgZbWKbWwbgZbgZcgCcgEbgZbgZcjTbPdbPbbgZcjUcjVbpWbgZbgZbgZbgZbgZahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHahlahjahlahjahjcjWahjahlahjcjWahjahlahjcjWahjahlahlchNchOcjXcjYcjZckacgNbELbELbELbELbCvahlahlahjahlahlahjahlahlahjahlbCvckdbCvcmacmhcicckfckgckhckickjbhAckUckUckUbOHbOKbORckrbhAcghbvCckuclScjCckwcghaJbclRclMcicbOPckzbReckzbOPckzbReckzbOPckAbReckBbOPahlahlahlahlahlahlahlahlahlahlahlahlahjahlbCDbCDbCDbXKckCcjMccPcnCbCDbCDbCDahlahlahjahlahjahjahlahlahlahlahlahlahlahlahlbgZcnyckEbgZbPbbPdbgZahlahlahlahlbgZblAbPdbPackGckGckHckIckGahlahjahjahjahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHaaHdpXahjahjcdcckJcdeahlcdcckJcdeahlcdcckJcdeahjahjahjahjckKcgNcgNcgNcgNbJibJjbELbELbCvahjahjcjtcjtcjtcjtcjtcjtcjtahjbCvbCvbCvcmBcmxcicckPckhckhckickQckxckxcmwcmjcmqcmicmiciickUcghckWcmQcmJckZclacghclbcmIcmDcicbOPcldcnDclfbOPclgcnXclibOPcljcnYcllbOPahlahlahlahlahlahlahlahlahlahlahlahlahjahlbRJahlbCDcfKcabcnZcacbCDbCDahlbRJahlahlahlahlahjahlahlahlahlahlahlahlahlahlahlbgZcnUbgZbgZbPibPdbgZbgZcgCcgEbgZbgZblAbPjbPfckGclqclrclsckGahlahlahjahjahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl -ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlcdcckJcdeahjcdcckJcdeahlcdcckJcdeahlahlahlahlahlahlahlahlbCvbCvbCvbXlbELbCvahlahlcjtclFclzclEclzclucjtahlbCvbSYbELcnzcmxcicclAclAclBcicclCclDcmmcnpckbcmFbPAcksckockocghclKcnmcncclNclOclPclQcmScmRcicbOPclTclUclTbOPclVclWclVbOPclXclYclZbOPahlahlahlahlahlahlahlahlahlahlahlahlahlahlbRJahlahlahjdsiahlahlahjahlahlbRJahlahlahlahlahjahjahlahlahlahlahlahlcmccmdcmebgZbJkaDGbgZbPEbPFciCciFciCciCciCciCciGcfRbPDckGcnBcnAcmkckGahlahlahlahlahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaGcahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaHaaHdpXahjahjcdcckJcdeahlcdcckJcdeahlcdcckJcdeahjahjahjahjckKcgNcgNcgNcgNbJibJjbELbELbCvahjahjcjtcjtcjtcjtcjtcjtcjtahjbCvbCvbCvcmBcmxcicckPckhckhckickQckxckxcmwcmjcmqcmicmiciickUcghckWcmQcmJckZclacghclbcmIcmDcicbOPcldcnDclfbOPclgcnXclibOPcljcnYcllbOPahlahlahlahlahlahlahlahlahlahlahlahlahjahlbRJahlbCDcfKduUcnZcacbCDbCDahlbRJahlahlahlahlahjahlahlahlahlahlahlahlahlahlahlbgZcnUbgZbgZbPibPdbgZbgZcgCcgEbgZbgZblAbPjbPfckGclqclrclsckGahlahlahjahjahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl +ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlcdcckJcdeahjcdcckJcdeahlcdcckJcdeahlahlahlahlahlahlahlahlbCvbCvbCvbXlbELbCvahlahlcjtclFclzclEclzclucjtahlbCvbSYbELcnzcmxcicclAclAclBcicclCclDcmmcnpckbcmFbPAcksckockocghclKcnmcncclNclOclPclQcmScmRcicbOPclTclUclTbOPclVclWclVbOPclXclYclZbOPahlahlahlahlahlahlahlahlahlahlahlahlahlahlbRJahlahlahjduVahlahlahjahlahlbRJahlahlahlahlahjahjahlahlahlahlahlahlcmccmdcmebgZbJkaDGbgZbPEbPFciCciFciCciCciCciCciGcfRbPDckGcnBcnAcmkckGahlahlahlahlahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaGcahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahldpXahjcdcckJcdeahlcdcckJcdeahlcdcckJcdeahjahlahlahlahlahlahlahlcgccgdcgcbELbELbCvahlahlcjtcmscmocmncmrcmpcjtahlbCvcegbELcnzcmxcicclAclAclBciccmucmvcmtcnFcnHckVcmAcmvcmzcmAcmvdtocnOcnMcmFcmGcmHcmEckbcnIcicbOPclTcmKclTbOPclVcmLclVbOPclZcmMclZbOPahlahlahlahlahlahlaaeahlahlahlahlahlahlahlbRJahlahlahjcmNahlahlahlahlahlbRJahlahlahlahlahjahjahlahlahlahlahlahjcbnblAcmObgZcphblAbgZbPVbKLbKLbQabKLchEchEchEbPXbPYchKckGcnQcnPcmTckGahlahlahjahlahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahldpXahjcdcckJcdeahlcdcckJcdeahjcdcckJcdeahjahjahjahjahjahjahjahjbCvbCvbCvbCvbELbCvahjahjcjtcmPcoZcoUcoPcmPcjtahjbCvciccnbclecoccicclAclBclBciccndcnecmycodckbclHclGclJclGclGcnkcnlcnScnRcnocnncnncnncobcoacicbOPbOPbOPbOPbOPbOPbOPbOPbOPbOPbOPbOPbOPahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlahlahlahlahlahlahlahlahlbRJahlahlahlahlahjahjahlahlahlahlahjdsicbncnrblAbrqcpGblAbgZbgZbgZbgZbgZblAbgZahlahjahlahjahlcnscntcnucnvcnwahjahjahjahjahjahjahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl ahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlaaRahjcdccnxcdeahlcdccnxcdeahlcdccnxcdeahjdpXahjahlahlahlahlahlahlahlahlbLWbELcaqahlahlcjtcmZcnfcpkcnqcngcjtcjtcjtciccnEclecoeciccicciccicciccnGckUcofcnpckbckUckUckUbQybQwccOckbckbcnpckUcopckUckUcohcogcicahjahlahlahlahjahjahlahlahjahlahlahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahjahlaaeahlahlahlahlahlahlahlbRJahlahlahlahlahlahjahlahlahlahlahldsicbnblAaBRbgZbLkblAblAblAblAblAblAblAbgZahlahjahlahjahlahjcnVcnWcnVahjahlahlahjahlahlahjahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahlahl diff --git a/bot/NanoTrasenBot.py b/bot/NanoTrasenBot.py index e86009ef580..af97829d22d 100644 --- a/bot/NanoTrasenBot.py +++ b/bot/NanoTrasenBot.py @@ -902,41 +902,34 @@ while True: print truesender+":"+temdata arg = temdata check = temdata.lower() - if check[0:5] == "https": + + if cache_youtube_links == True: + result = YTCV2(arg) + else: + result = YTCV2(arg,0) + if type(result) == str: + ### To remove =" + if result[0:4] == 'nt="': + result = result[4:] + pass + elif result[0:2] == '="': + result = result[2:] + pass + else: + pass + if """ in result: + result.replace(""",'"') if len(temporal_list) == 1: - conn.privmsg(targetchannel,sender+" :Secure Youtube does NOT exist") + conn.privmsg(targetchannel,sender+" : "+result) break else: - temporal_list2.append("Secure Youtube does NOT exist") - break + temporal_list2.append(result) else: - if cache_youtube_links == True: - result = YTCV2(arg) + if len(temporal_list) == 1: + conn.privmsg(targetchannel,sender+" : The video does not exist") + break else: - result = YTCV2(arg,0) - if type(result) == str: - ### To remove =" - if result[0:4] == 'nt="': - result = result[4:] - pass - elif result[0:2] == '="': - result = result[2:] - pass - else: - pass - if """ in result: - result.replace(""",'"') - if len(temporal_list) == 1: - conn.privmsg(targetchannel,sender+" : "+result) - break - else: - temporal_list2.append(result) - else: - if len(temporal_list) == 1: - conn.privmsg(targetchannel,sender+" : The video does not exist") - break - else: - temporal_list2.append("The video does not exist") + temporal_list2.append("The video does not exist") if len(temporal_list) == 1: pass else: diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 6724122a501..60eae92ba1d 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -25,6 +25,19 @@ * Text sanitization */ +//this proc strips html properly, but it's not lazy like the other procs. +//this means that it doesn't just remove < and > and call it a day. seriously, who the fuck thought that would be useful. +/proc/strip_html_properly(var/input) + var/opentag = 1 //These store the position of < and > respectively. + var/closetag = 1 + while(1) + opentag = findtext(input, "<") + closetag = findtext(input, ">") + if(!closetag || !opentag) + break + input = copytext(input, 1, opentag) + copytext(input, (closetag + 1)) + return input + //Simply removes < and > and limits the length of the message /proc/strip_html_simple(var/t,var/limit=MAX_MESSAGE_LEN) var/list/strip_chars = list("<",">") @@ -363,16 +376,3 @@ var/list/binary = list("0","1") temp = findtextEx(haystack, ascii2text(text2ascii(needles,i)), start, end) //Note: ascii2text(text2ascii) is faster than copytext() if(temp) end = temp return end - -//this proc strips html properly, but it's not lazy like the other procs. -//this means that it doesn't just remove < and > and call it a day. seriously, who the fuck thought that would be useful. -/proc/strip_html_properly(var/input) - var/opentag = 1 //These store the position of < and > respectively. - var/closetag = 1 - while(1) - opentag = findtext(input, "<") - closetag = findtext(input, ">") - if(!closetag || !opentag) - break - input = copytext(input, 1, opentag) + copytext(input, (closetag + 1)) - return input diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 87d1feeb1e4..e847cd47236 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -58,6 +58,10 @@ aicamera.camera_mode_off() aicamera.captureimage(A, usr) return + if(waypoint_mode) + set_waypoint(A) + waypoint_mode = 0 + return /* AI restrained() currently does nothing diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index d41cdb4a533..329e9db7804 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -392,7 +392,7 @@ //Anything not bolted down is moved, everything else is destroyed if(!AM.anchored) - AM.Move(D) + AM.Move(D, SOUTH) else qdel(AM) if(istype(T, /turf/simulated)) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 0d5a26dba65..af888fa3c1f 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -4,23 +4,58 @@ var/anchored = 0 var/move_speed = 10 var/l_move_time = 1 - var/m_flag = 1 var/throwing = 0 var/throw_speed = 2 var/throw_range = 7 var/mob/pulledby = null var/languages = 0 //For say() and Hear() + var/inertia_dir = 0 glide_size = 8 -/atom/movable/Move() - var/atom/A = src.loc - . = ..() +/atom/movable/Move(atom/newloc, direct = 0) + if(!loc || !newloc) return 0 + last_move = direct + var/atom/oldloc = loc + + if(loc != newloc) + if (!(direct & (direct - 1))) //Cardinal move + . = ..() + else //Diagonal move, split it into cardinal moves + if (direct & 1) + if (direct & 4) + if (step(src, NORTH)) + . = step(src, EAST) + else if (step(src, EAST)) + . = step(src, NORTH) + else if (direct & 8) + if (step(src, NORTH)) + . = step(src, WEST) + else if (step(src, WEST)) + . = step(src, NORTH) + else if (direct & 2) + if (direct & 4) + if (step(src, SOUTH)) + . = step(src, EAST) + else if (step(src, EAST)) + . = step(src, SOUTH) + else if (direct & 8) + if (step(src, SOUTH)) + . = step(src, WEST) + else if (step(src, WEST)) + . = step(src, SOUTH) + + + if(!loc || (loc == oldloc && oldloc != newloc)) + last_move = 0 + return + src.move_speed = world.timeofday - src.l_move_time src.l_move_time = world.timeofday - src.m_flag = 1 - if ((A != src.loc && A && A.z == src.z)) - src.last_move = get_dir(A, src.loc) - return + + spawn(5) // Causes space drifting. /tg/station has no concept of speed, we just use 5 + if(loc && direct && last_move == direct) + if(loc == newloc) //Remove this check and people can accelerate. Not opening that can of worms just yet. + newtonian_move(last_move) /atom/movable/Del() if(isnull(gc_destroyed) && loc) @@ -69,6 +104,39 @@ return 1 return 0 +//Called whenever an object moves and by mobs when they attempt to move themselves through space +//And when an object or action applies a force on src, see newtonian_move() below +//Return 0 to have src start/keep drifting in a no-grav area and 1 to stop/not start drifting +//Mobs should return 1 if they should be able to move of their own volition, see client/Move() in mob_movement.dm +//movement_dir == 0 when stopping or any dir when trying to move +/atom/movable/proc/Process_Spacemove(var/movement_dir = 0) + if(has_gravity(src)) + return 1 + + if(pulledby) + return 1 + + if(locate(/obj/structure/lattice) in orange(1, get_turf(src))) //Not realistic but makes pushing things in space easier + return 1 + + return 0 + +/atom/movable/proc/newtonian_move(direction) //Only moves the object if it's under no gravity + + if(!loc || Process_Spacemove(0)) + inertia_dir = 0 + return 0 + + inertia_dir = direction + if(!direction) + return 1 + + + var/old_dir = dir + . = step(src, direction) + dir = old_dir + + /atom/movable/proc/hit_check() // todo: this is partly obsolete due to passflags already, add throwing stuff to mob CanPass and finish it if(src.throwing) for(var/atom/A in get_turf(src)) @@ -116,7 +184,7 @@ var/atom/step = get_step(src, (error < 0) ? tdy : tdx) if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break - src.Move(step) + src.Move(step, get_dir(loc, step)) hit_check() error += (error < 0) ? tdist_x : -tdist_y; dist_travelled++ diff --git a/code/game/communications.dm b/code/game/communications.dm index ac4576042c2..3b5faf29f8b 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -176,6 +176,9 @@ var/const/RADIO_AIRLOCK = "6" var/const/RADIO_SECBOT = "7" var/const/RADIO_MULEBOT = "8" var/const/RADIO_MAGNETS = "9" +var/const/RADIO_CLEANBOT = "10" +var/const/RADIO_FLOORBOT = "11" +var/const/RADIO_MEDBOT = "12" var/global/datum/controller/radio/radio_controller diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm index b9ed5c88c54..3ca592195fc 100644 --- a/code/game/gamemodes/meteor/meteors.dm +++ b/code/game/gamemodes/meteor/meteors.dm @@ -8,6 +8,8 @@ /var/list/meteorsC = list(/obj/effect/meteor/dust) //for space dust event +/var/list/meteorsSPOOKY = list(/obj/effect/meteor/pumpkin) + /proc/spawn_meteors(var/number = 10, var/list/meteortypes) for(var/i = 0; i < number; i++) spawn_meteor(meteortypes) @@ -132,6 +134,25 @@ heavy = 1 meteordrop = /obj/item/weapon/ore/uranium +/obj/effect/meteor/pumpkin + name = "PUMPKING" + desc = "THE PUMPKING'S COMING!" + icon = 'icons/obj/meteor_spooky.dmi' + icon_state = "pumpkin" + hits = 10 + heavy = 1 + meteordrop = /obj/item/clothing/head/hardhat/pumpkinhead + meteorsound = 'sound/hallucinations/im_here1.ogg' + dropamt = 1 + bound_width = 96 + bound_height = 96 + +/obj/effect/meteor/pumpkin/New() + ..() + if(prob(50)) + meteordrop = /obj/item/weapon/reagent_containers/food/snacks/grown/pumpkin + meteorsound = 'sound/hallucinations/im_here2.ogg' + /obj/effect/meteor/meaty name = "meaty ore" icon_state = "meateor" diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm index e897262769f..49c8f205ef4 100644 --- a/code/game/machinery/bots/bots.dm +++ b/code/game/machinery/bots/bots.dm @@ -6,6 +6,7 @@ luminosity = 3 use_power = 0 var/obj/item/weapon/card/id/botcard // the ID card that the bot "holds" + var/list/prev_access = list() var/on = 1 var/health = 0 //do not forget to set health for your bot! var/maxhealth = 0 @@ -14,7 +15,74 @@ var/open = 0//Maint panel var/locked = 1 var/hacked = 0 //Used to differentiate between being hacked by silicons and emagged by humans. + var/text_hack = "" //Custom text returned to a silicon upon hacking a bot. + var/text_dehack = "" //Text shown when resetting a bots hacked status to normal. + var/text_dehack_fail = "" //Shown when a silicon tries to reset a bot emagged with the emag item, which cannot be reset. + var/declare_message = "" //What the bot will display to the HUD user. + var/frustration = 0 //Used by some bots for tracking failures to reach their target. + var/speed = 2 //The speed at which the bot moves, or the number of times it moves per process() tick. + var/turf/ai_waypoint //The end point of a bot's path, or the target location. + var/list/path = list() //List of turfs through which a bot 'steps' to reach the waypoint. + var/pathset = 0 + var/list/ignore_list = list() //List of unreachable targets for an ignore-list enabled bot to ignore. + var/mode = 0 //Standardizes the vars that indicate the bot is busy with its function. + var/tries = 0 //Number of times the bot tried and failed to move. + var/remote_disabled = 0 //If enabled, the AI cannot *Remotely* control a bot. It can still control it through cameras. + var/mob/living/silicon/ai/calling_ai //Links a bot to the AI calling it. + var/obj/item/device/radio/Radio //The bot's radio, for speaking to people. + var/radio_frequency //The bot's default radio speaking freqency. Recommended to be on a department frequency. //var/emagged = 0 //Urist: Moving that var to the general /bot tree as it's used by most bots + var/auto_patrol = 0// set to make bot automatically patrol + var/turf/patrol_target // this is turf to navigate to (location of beacon) + var/turf/summon_target // The turf of a user summoning a bot. + var/new_destination // pending new destination (waiting for beacon response) + var/destination // destination description tag + var/next_destination // the next destination in the patrol route + + var/blockcount = 0 //number of times retried a blocked path + var/awaiting_beacon = 0 // count of pticks awaiting a beacon response + + var/nearest_beacon // the nearest beacon's tag + var/turf/nearest_beacon_loc // the nearest beacon's location + + var/beacon_freq = 1445 // navigation beacon frequency + var/control_freq = 1447 // bot control frequency + + var/bot_filter // The radio filter the bot uses to identify itself on the network. + + var/bot_type = 0 //The type of bot it is, for radio control. + #define SEC_BOT 1 // Secutritrons (Beepsky) and ED-209s + #define MULE_BOT 2 // MULEbots + #define FLOOR_BOT 3 // Floorbots + #define CLEAN_BOT 4 // Cleanbots + #define MED_BOT 5 // Medibots + + #define DEFAULT_SCAN_RANGE 7 //default view range for finding targets. + + //Mode defines + #define BOT_IDLE 0 // idle + #define BOT_HUNT 1 // found target, hunting + #define BOT_PREP_ARREST 2 // at target, preparing to arrest + #define BOT_ARREST 3 // arresting target + #define BOT_START_PATROL 4 // start patrol + #define BOT_PATROL 5 // patrolling + #define BOT_SUMMON 6 // summoned by PDA + #define BOT_CLEANING 7 // cleaning (cleanbots) + #define BOT_REPAIRING 8 // repairing hull breaches (floorbots) + #define BOT_MOVING 9 // for clean/floor bots, when moving. + #define BOT_HEALING 10 // healing people (medbots) + #define BOT_RESPONDING 11 // responding to a call from the AI + #define BOT_LOADING 12 // loading/unloading + #define BOT_DELIVER 13 // moving to deliver + #define BOT_GO_HOME 14 // returning to home + #define BOT_BLOCKED 15 // blocked + #define BOT_NAV 16 // computing navigation + #define BOT_WAIT_FOR_NAV 17 // waiting for nav computation + #define BOT_NO_ROUTE 18 // no destination beacon found (or no route) + var/list/mode_name = list("In Pursuit","Preparing to Arrest","Arresting","Beginning Patrol","Patrolling","Summoned by PDA", \ + "Cleaning", "Repairing", "Proceeding to work site","Healing","Responding","Loading/Unloading","Navigating to Delivery Location","Navigating to Home", \ + "Waiting for clear path","Calculating navigation path","Pinging beacon network","Unable to reach destination") + //This holds text for what the bot is mode doing, reported on the AI's bot control interface. /obj/machinery/bot/proc/turn_on() @@ -26,26 +94,46 @@ /obj/machinery/bot/proc/turn_off() on = 0 SetLuminosity(0) + bot_reset() //Resets an AI's call, should it exist. + +/obj/machinery/bot/New() + ..() + botcard = new /obj/item/weapon/card/id(src) + set_custom_texts() + Radio = new /obj/item/device/radio(src) + Radio.listening = 0 //Makes bot radios transmit only so no one hears things while adjacent to one. + +/obj/machinery/bot/proc/add_to_beacons(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots. + if(radio_controller) + radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS) + if(bot_filter) + radio_controller.add_object(src, control_freq, filter = bot_filter) /obj/machinery/bot/proc/explode() qdel(src) /obj/machinery/bot/proc/healthcheck() - if (src.health <= 0) - src.explode() + if (health <= 0) + explode() -/obj/machinery/bot/proc/Emag(mob/user as mob) - if(locked) +/obj/machinery/bot/proc/Emag(mob/user as mob) //Master Emag proc. Ensure this is called in your bot before setting unique functions. + if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again. locked = 0 emagged = 1 user << "You bypass [src]'s controls." - if(!locked && open) + if(!locked && open) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging. emagged = 2 + remote_disabled = 1 //Manually emagging the bot locks out the AI built in panel. + locked = 1 //Access denied forever! + bot_reset() + turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP. + else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet. + user << "You need to open maintenance panel first." /obj/machinery/bot/examine(mob/user) ..() - if (src.health < maxhealth) - if (src.health > maxhealth/3) + if (health < maxhealth) + if (health > maxhealth/3) user << "[src]'s parts look loose." else user << "[src]'s parts look very loose." @@ -54,32 +142,96 @@ /obj/machinery/bot/attack_alien(var/mob/living/carbon/alien/user as mob) user.changeNext_move(CLICK_CD_MELEE) - src.health -= rand(15,30)*brute_dam_coeff - src.visible_message("[user] has slashed [src]!") - playsound(src.loc, 'sound/weapons/slice.ogg', 25, 1, -1) + health -= rand(15,30)*brute_dam_coeff + visible_message("[user] has slashed [src]!") + playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) if(prob(10)) - new /obj/effect/decal/cleanable/oil(src.loc) + new /obj/effect/decal/cleanable/oil(loc) healthcheck() /obj/machinery/bot/attack_animal(var/mob/living/simple_animal/M as mob) - if(M.melee_damage_upper == 0) return + if(M.melee_damage_upper == 0) + return M.changeNext_move(CLICK_CD_MELEE) - src.health -= M.melee_damage_upper - src.visible_message("[M] has [M.attacktext] [src]!") + health -= M.melee_damage_upper + visible_message("[M] has [M.attacktext] [src]!") add_logs(M, src, "attacked", admin=0) if(prob(10)) - new /obj/effect/decal/cleanable/oil(src.loc) + new /obj/effect/decal/cleanable/oil(loc) healthcheck() +/obj/machinery/bot/Topic(href, href_list) //Master Topic to handle common functions. + . = ..() + if (.) + return + if(topic_denied(usr)) + usr << "[src]'s interface is not responding!" + href_list = list() + return + usr.set_machine(src) + add_fingerprint(usr) + if((href_list["power"]) && (allowed(usr) || !locked)) + if (on) + turn_off() + else + turn_on() + + switch(href_list["operation"]) + if("patrol") + auto_patrol = !auto_patrol + mode = BOT_IDLE + if("remote") + remote_disabled = !remote_disabled + if("hack") + if(emagged != 2) + emagged = 2 + hacked = 1 + locked = 1 + usr << "[text_hack]" + bot_reset() + else if(!hacked) + usr << "[text_dehack_fail]" + else + emagged = 0 + hacked = 0 + usr << "[text_dehack]" + bot_reset() + updateUsrDialog() + +/obj/machinery/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired. + // 0 for access, 1 for denied. + if(emagged == 2) //An emagged bot cannot be controlled by humans, silicons can if one hacked it. + if(!hacked) //Manually emagged by a human - access denied to all. + return 1 + else if(!issilicon(user)) //Bot is hacked, so only silicons are allowed access. + return 1 + else + return 0 + +/obj/machinery/bot/process() //Master process which handles code common across most bots. + + set background = BACKGROUND_ENABLED + + if(!on) + return + + switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command. + if(BOT_RESPONDING) //Called by the AI. + call_mode() + return + if(BOT_SUMMON) //Called by PDA + bot_summon() + return + return 1 //Successful completion. Used to prevent child process() continuing if this one is ended early. /obj/machinery/bot/attackby(obj/item/weapon/W as obj, mob/user as mob) if(istype(W, /obj/item/weapon/screwdriver)) if(!locked) open = !open - user << "Maintenance panel is now [src.open ? "opened" : "closed"]." + user << "Maintenance panel is now [open ? "opened" : "closed"]." else user << "Maintenance panel is locked." else if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") @@ -103,10 +255,10 @@ s.set_up(5, 1, src) switch(W.damtype) if("fire") - src.health -= W.force * fire_dam_coeff + health -= W.force * fire_dam_coeff s.start() if("brute") - src.health -= W.force * brute_dam_coeff + health -= W.force * brute_dam_coeff s.start() ..() healthcheck() @@ -124,24 +276,24 @@ return /obj/machinery/bot/blob_act() - src.health -= rand(20,40)*fire_dam_coeff + health -= rand(20,40)*fire_dam_coeff healthcheck() return /obj/machinery/bot/ex_act(severity) switch(severity) if(1.0) - src.explode() + explode() return if(2.0) - src.health -= rand(5,10)*fire_dam_coeff - src.health -= rand(10,20)*brute_dam_coeff + health -= rand(5,10)*fire_dam_coeff + health -= rand(10,20)*brute_dam_coeff healthcheck() return if(3.0) if (prob(50)) - src.health -= rand(1,5)*fire_dam_coeff - src.health -= rand(1,5)*brute_dam_coeff + health -= rand(1,5)*fire_dam_coeff + health -= rand(1,5)*brute_dam_coeff healthcheck() return return @@ -149,7 +301,7 @@ /obj/machinery/bot/emp_act(severity) var/was_on = on stat |= EMPED - var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( src.loc ) + var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( loc ) pulse2.icon = 'icons/effects/effects.dmi' pulse2.icon_state = "empdisable" pulse2.name = "emp sparks" @@ -167,17 +319,467 @@ /obj/machinery/bot/proc/hack(mob/user) var/hack - if(issilicon(user)) - hack += "[src.emagged ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]
" - hack += "Harm Prevention Safety System: [src.emagged ? "DANGER" : "Engaged"]
" + if(issilicon(user)) //Allows silicons to toggle the emag status of a bot. + hack += "[emagged == 2 ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]
" + hack += "Harm Prevention Safety System: [emagged ? "DANGER" : "Engaged"]
" + else if(!locked) //Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control. + hack += "Remote network control radio: [remote_disabled ? "Disconnected" : "Connected"]

" return hack -/obj/machinery/bot/attack_ai(mob/user as mob) - src.attack_hand(user) +/obj/machinery/bot/proc/set_custom_texts() //Superclass for setting hack texts. Appears only if a set is not given to a bot locally. + text_hack = "You hack [name]." + text_dehack = "You reset [name]." + text_dehack_fail = "You fail to reset [name]." -/obj/machinery/bot/proc/speak(var/message) - if((!src.on) || (!message)) +/obj/machinery/bot/attack_ai(mob/user as mob) + attack_hand(user) + +/obj/machinery/bot/proc/speak(var/message, freq) //Pass a message to have the bot say() it. Pass a frequency to say it on the radio. + if((!on) || (!message)) return - audible_message("[src] beeps, \"[message]\"",2) + if(freq) + Radio.set_frequency(radio_frequency) + Radio.talk_into(src, message, radio_frequency) + else + say(message) return + //Generalized behavior code, override where needed! + +/* +scan() will search for a given type (such as turfs, human mobs, or objects) in the bot's view range, and return a single result. +Arguments: The object type to be searched (such as "/mob/living/carbon/human"), the old scan result to be ignored, if one exists, +and the view range, which defaults to 7 (full screen) if an override is not passed. +If the bot maintains an ignore list, it is also checked here. + +Example usage: patient = scan(/mob/living/carbon/human, oldpatient, 1) +The proc would return a human next to the bot to be set to the patient var. +Pass the desired type path itself, declaring a temporary var beforehand is not required. +*/ +obj/machinery/bot/proc/scan(var/scan_type, var/old_target, var/scan_range) + var/final_result + for (var/scan in view (scan_range ? scan_range : DEFAULT_SCAN_RANGE, src) ) //Search for something in range! + if(!istype(scan, scan_type)) //Check that the thing we found is the type we want! + continue //If not, keep searching! + if( !(scan in ignore_list) && !(scan in old_target) ) //Filter for blacklisted elements, usually unreachable or previously processed oness + var/scan_result = process_scan(scan) //Some bots may require additional processing when a result is selected. + if( scan_result ) + final_result = scan_result + else + continue //The current element failed assessment, move on to the next. + return final_result + +//When the scan finds a target, run bot specific processing to select it for the next step. Empty by default. +obj/machinery/bot/proc/process_scan(var/scan_target) + return scan_target + + +/obj/machinery/bot/proc/add_to_ignore(var/subject) + if(ignore_list.len < 50) //This will help keep track of them, so the bot is always trying to reach a blocked spot. + ignore_list |= subject + else if (ignore_list.len >= subject) //If the list is full, insert newest, delete oldest. + ignore_list -= ignore_list[1] + ignore_list |= subject + +/* +Movement proc for stepping a bot through a path generated through A-star. +Pass a positive integer as an argument to override a bot's default speed. +*/ +obj/machinery/bot/proc/bot_move(var/dest, var/move_speed) + + if(!dest || !path || path.len == 0) //A-star failed or a path/destination was not set. + path = list() + return 0 + if(get_turf(src) == get_turf(dest)) //We have arrived, no need to move again. + return 1 + var/success + var/step_count = move_speed ? move_speed : speed //If a value is passed into move_speed, use that instead of the default speed var. + if(step_count >= 1 && tries < 4) + for(step_count, step_count >= 1,step_count--) + success = bot_step(dest) + if (success) + tries = 0 + else + tries++ + break + sleep(4) + else + return 0 + return 1 + + +obj/machinery/bot/proc/bot_step(var/dest) + if(path.len > 1) + step_to(src, path[1]) + if(get_turf(src) == path[1]) //Successful move + path -= path[1] + else + return 0 + else if(path.len == 1) + step_to(src, dest) + path = list() + return 1 + + +/obj/machinery/bot/proc/check_bot_access() + if(mode != BOT_SUMMON && mode != BOT_RESPONDING) + botcard.access = prev_access + +/obj/machinery/bot/proc/call_bot(var/caller, var/turf/waypoint) + bot_reset() //Reset a bot before setting it to call mode. + var/area/end_area = get_area(waypoint) + + //For giving the bot temporary all-access. + var/obj/item/weapon/card/id/all_access = new /obj/item/weapon/card/id + var/datum/job/captain/All = new/datum/job/captain + all_access.access = All.get_access() + + path = AStar(src, waypoint, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 200, id=all_access) + calling_ai = caller //Link the AI to the bot! + ai_waypoint = waypoint + + if(path && path.len) //Ensures that a valid path is calculated! + if(!on) + turn_on() //Saves the AI the hassle of having to activate a bot manually. + botcard = all_access //Give the bot all-access while under the AI's command. + calling_ai << "\icon[src] [name] called to [end_area.name]. [path.len-1] meters to destination." + pathset = 1 + mode = BOT_RESPONDING + tries = 0 + else + calling_ai << "Failed to calculate a valid route. Ensure destination is clear of obstructions and within range." + calling_ai = null + +/obj/machinery/bot/proc/call_mode() //Handles preparing a bot for a call, as well as calling the move proc. +//Handles the bot's movement during a call. + var/success = bot_move(ai_waypoint, 3) + if (!success) + if(calling_ai) + calling_ai << "\icon[src] [get_turf(src) == ai_waypoint ? "[src] successfully arrived to waypoint." : "[src] failed to reach waypoint."]" + calling_ai = null + bot_reset() + +obj/machinery/bot/proc/bot_reset() + if(calling_ai) //Simple notification to the AI if it called a bot. It will not know the cause or identity of the bot. + calling_ai << "Call command to a bot has been reset." + calling_ai = null + path = list() + summon_target = null + pathset = 0 + botcard.access = prev_access + tries = 0 + mode = BOT_IDLE + + + + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//Patrol and summon code! +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +/obj/machinery/bot/proc/bot_patrol() + patrol_step() + spawn(5) + if(mode == BOT_PATROL) + patrol_step() + return + +obj/machinery/bot/proc/start_patrol() + + if(tries >= 4) //Bot is trapped, so stop trying to patrol. + auto_patrol = 0 + tries = 0 + speak("Unable to start patrol.") + + return + + if(!auto_patrol) //A bot not set to patrol should not be patrolling. + mode = BOT_IDLE + return + + if(patrol_target) // has patrol target + spawn(0) + calc_path() // Find a route to it + if(path.len == 0) + patrol_target = 0 + return + mode = BOT_PATROL + else // no patrol target, so need a new one + find_patrol_target() + speak("Engaging patrol mode.") + tries++ + return + +// perform a single patrol step + +/obj/machinery/bot/proc/patrol_step() + + if(loc == patrol_target) // reached target + + at_patrol_target() + return + + else if(path.len > 0 && patrol_target) // valid path + var/turf/next = path[1] + if(next == loc) + path -= next + return + + + var/moved = bot_move(patrol_target)//step_towards(src, next) // attempt to move + if(moved) // successful move + blockcount = 0 + + else // failed to move + blockcount++ + + if(blockcount > 5) // attempt 5 times before recomputing + // find new path excluding blocked turf + + spawn(2) + calc_path(next) + if(path.len == 0) + find_patrol_target() + else + blockcount = 0 + tries = 0 + + return + + return + + else // no path, so calculate new one + mode = BOT_START_PATROL + + return + +// finds a new patrol target +/obj/machinery/bot/proc/find_patrol_target() + send_status() + if(awaiting_beacon) // awaiting beacon response + awaiting_beacon++ + if(awaiting_beacon > 5) // wait 5 secs for beacon response + find_nearest_beacon() // then go to nearest instead + return + if(next_destination) + set_destination(next_destination) + else + + find_nearest_beacon() + return + + +// finds the nearest beacon to self +// signals all beacons matching the patrol code +/obj/machinery/bot/proc/find_nearest_beacon() + nearest_beacon = null + new_destination = "__nearest__" + post_signal(beacon_freq, "findbeacon", "patrol") + awaiting_beacon = 1 + spawn(10) + awaiting_beacon = 0 + if(nearest_beacon) + set_destination(nearest_beacon) + tries = 0 + else + auto_patrol = 0 + mode = BOT_IDLE + speak("Disengaging patrol mode.") + send_status() + + +/obj/machinery/bot/proc/at_patrol_target() + + find_patrol_target() + return + + +// sets the current destination +// signals all beacons matching the patrol code +// beacons will return a signal giving their locations +/obj/machinery/bot/proc/set_destination(var/new_dest) + new_destination = new_dest + post_signal(beacon_freq, "findbeacon", "patrol") + awaiting_beacon = 1 + + +// receive a radio signal +// used for beacon reception + +/obj/machinery/bot/receive_signal(datum/signal/signal) + //log_admin("DEBUG \[[// world.timeofday]\]: /obj/machinery/bot/receive_signal([signal.debug_print()])") + if(!on) + return +/* + if(!signal.data["beacon"]) + + for(var/x in signal.data) + world << "* [x] = [signal.data[x]]" + */ + + var/recv = signal.data["command"] + // process all-bot input + + if(recv=="bot_status") + send_status() + + // check to see if we are the commanded bot + if(signal.data["active"] == src) + if(emagged == 2 || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands. + return + // process control input + switch(recv) + if("stop") + bot_reset() //HOLD IT!! + auto_patrol = 0 + return + + if("go") + auto_patrol = 1 + return + + if("summon") + bot_reset() + var/list/user_access = signal.data["useraccess"] + summon_target = signal.data["target"] //Location of the user + if(user_access.len != 0) + botcard.access = user_access + prev_access //Adds the user's access, if any. + mode = BOT_SUMMON + calc_summon_path() + speak("Responding.", radio_frequency) + return + + // receive response from beacon + recv = signal.data["beacon"] + var/valid = signal.data["patrol"] + if(!recv || !valid) + return + if(recv == new_destination) // if the recvd beacon location matches the set destination + // the we will navigate there + destination = new_destination + patrol_target = signal.source.loc + next_destination = signal.data["next_patrol"] + awaiting_beacon = 0 + + // if looking for nearest beacon + else if(new_destination == "__nearest__") + var/dist = get_dist(src,signal.source.loc) + if(nearest_beacon) + // note we ignore the beacon we are located at + if(dist>1 && dist 1) + nearest_beacon = recv + nearest_beacon_loc = signal.source.loc + return + + +// send a radio signal with a single data key/value pair +/obj/machinery/bot/proc/post_signal(var/freq, var/key, var/value) + post_signal_multiple(freq, list("[key]" = value) ) + +// send a radio signal with multiple data key/values +/obj/machinery/bot/proc/post_signal_multiple(var/freq, var/list/keyval) + if(!z || z != 1) //Bot control will only work on station. + return + var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq) + + if(!frequency) return + + var/datum/signal/signal = new() + signal.source = src + signal.transmission_method = 1 +// for(var/key in keyval) +// signal.data[key] = keyval[key] + signal.data = keyval +// world << "sent [key],[keyval[key]] on [freq]" + if(signal.data["findbeacon"]) + frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS) + else if(signal.data["type"] == bot_type) + frequency.post_signal(src, signal, filter = bot_filter) + else + frequency.post_signal(src, signal) + +// signals bot status etc. to controller +/obj/machinery/bot/proc/send_status() + if(remote_disabled || emagged == 2) + return + var/list/kv = list( + "type" = bot_type, + "name" = name, + "loca" = get_area(src), // area + "mode" = mode + ) + post_signal_multiple(control_freq, kv) + + +obj/machinery/bot/proc/bot_summon() + // summoned to PDA + summon_step() + return + +// calculates a path to the current destination +// given an optional turf to avoid +/obj/machinery/bot/proc/calc_path(var/turf/avoid) + check_bot_access() + path = AStar(loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 120, id=botcard, exclude=avoid) + if(!path) + path = list() + +/obj/machinery/bot/proc/calc_summon_path(var/turf/avoid) + check_bot_access() + path = AStar(loc, summon_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 150, id=botcard, exclude=avoid) + if(!path || tries >= 5) //Cannot reach target. Give up and announce the issue. + speak("Summon command failed, destination unreachable.",radio_frequency) + bot_reset() + +/obj/machinery/bot/proc/summon_step() + + if(loc == summon_target) // Arrived to summon location. + bot_reset() + return + + else if(path.len > 0 && summon_target) //Proper path acquired! + var/turf/next = path[1] + if(next == loc) + path -= next + return + + var/moved = bot_move(summon_target, 3) // Move attempt + if(moved) + blockcount = 0 + + else // failed to move + blockcount++ + + if(blockcount > 5) // attempt 5 times before recomputing + // find new path excluding blocked turf + spawn(2) + calc_summon_path(next) + tries++ + return + + return + + else // no path, so calculate new one + calc_summon_path() + + return + + +/obj/machinery/bot/Bump(M as mob|obj) //Leave no door unopened! + if((istype(M, /obj/machinery/door/airlock) || istype(M, /obj/machinery/door/window)) && (!isnull(botcard))) + var/obj/machinery/door/D = M + if(D.check_access(botcard)) + D.open() + frustration = 0 + else if((istype(M, /mob/living/)) && (!anchored)) + var/mob/living/Mb = M + loc = Mb.loc + frustration = 0 + return diff --git a/code/game/machinery/bots/cleanbot.dm b/code/game/machinery/bots/cleanbot.dm index 592b1686c4a..abbbd289b62 100644 --- a/code/game/machinery/bots/cleanbot.dm +++ b/code/game/machinery/bots/cleanbot.dm @@ -24,51 +24,57 @@ //weight = 1.0E7 health = 25 maxhealth = 25 - var/cleaning = 0 var/blood = 1 var/list/target_types = list() var/obj/effect/decal/cleanable/target var/obj/effect/decal/cleanable/oldtarget + var/max_targets = 50 //Maximum number of targets a cleanbot can ignore. var/oldloc = null - req_access = list(access_janitor) - var/path[] = new() - var/patrol_path[] = null - var/beacon_freq = 1445 // navigation beacon frequency + req_one_access = list(access_janitor, access_robotics) +// var/patrol_path[] = null +// var/beacon_freq = 1445 // navigation beacon frequency var/closest_dist var/closest_loc var/failed_steps - var/should_patrol var/next_dest var/next_dest_loc + radio_frequency = SERV_FREQ //Service + bot_type = CLEAN_BOT + bot_filter = RADIO_CLEANBOT /obj/machinery/bot/cleanbot/New() ..() - src.get_targets() - src.icon_state = "cleanbot[src.on]" + get_targets() + icon_state = "cleanbot[on]" - should_patrol = 1 - - src.botcard = new /obj/item/weapon/card/id(src) var/datum/job/janitor/J = new/datum/job/janitor - src.botcard.access = J.get_access() - - if(radio_controller) - radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS) + botcard.access = J.get_access() + prev_access = botcard.access + spawn(5) + add_to_beacons(bot_filter) /obj/machinery/bot/cleanbot/turn_on() - . = ..() - src.icon_state = "cleanbot[src.on]" - src.updateUsrDialog() + ..() + icon_state = "cleanbot[on]" + updateUsrDialog() /obj/machinery/bot/cleanbot/turn_off() ..() - src.target = null - src.oldtarget = null - src.oldloc = null - src.icon_state = "cleanbot[src.on]" - src.path = new() - src.updateUsrDialog() + icon_state = "cleanbot[on]" + updateUsrDialog() + +/obj/machinery/bot/cleanbot/bot_reset() + ..() + ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable. + target = null + oldtarget = null + oldloc = null + +/obj/machinery/bot/cleanbot/set_custom_texts() + text_hack = "You corrupt [name]'s cleaning software." + text_dehack = "[name]'s software has been reset!" + text_dehack_fail = "[name] does not seem to respond to your repair code!" /obj/machinery/bot/cleanbot/attack_hand(mob/user as mob) . = ..() @@ -81,76 +87,39 @@ var/dat dat += hack(user) dat += text({" -Automatic Station Cleaner v1.0

+Cleaner v1.1 controls

Status: []
-Behaviour controls are [src.locked ? "locked" : "unlocked"]
-Maintenance panel panel is [src.open ? "opened" : "closed"]"}, -text("[src.on ? "On" : "Off"]")) - if(!src.locked || issilicon(user)) - dat += text({"
Cleans Blood: []
"}, text("[src.blood ? "Yes" : "No"]")) - dat += text({"
Patrol station: []
"}, text("[src.should_patrol ? "Yes" : "No"]")) - // dat += text({"
Beacon frequency: []
"}, text("[src.beacon_freq]")) -/* if(src.open && !src.locked) - dat += text({" -Odd looking screw twiddled: []
-Weird button pressed: []"}, -text("[src.screwloose ? "Yes" : "No"]"), -text("[src.oddbutton ? "Yes" : "No"]"))*/ +Behaviour controls are [locked ? "locked" : "unlocked"]
+Maintenance panel panel is [open ? "opened" : "closed"]"}, +text("[on ? "On" : "Off"]")) + if(!locked || issilicon(user)) + dat += text({"
Cleans Blood: []
"}, text("[blood ? "Yes" : "No"]")) + dat += text({"
Patrol station: []
"}, text("[auto_patrol ? "Yes" : "No"]")) - user << browse("Cleaner v1.0 controls[dat]", "window=autocleaner") - onclose(user, "autocleaner") + var/datum/browser/popup = new(user, "autoclean", "Automatic Station Cleaner v1.1") + popup.set_content(dat) + popup.open() return /obj/machinery/bot/cleanbot/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - src.add_fingerprint(usr) + + ..() switch(href_list["operation"]) - if("start") - if (src.on && !src.emagged) - turn_off() - else - turn_on() if("blood") - src.blood =!src.blood - src.get_targets() - src.updateUsrDialog() - if("patrol") - src.should_patrol =!src.should_patrol - src.patrol_path = null - src.updateUsrDialog() + blood =!blood + get_targets() + updateUsrDialog() if("freq") var/freq = text2num(input("Select frequency for navigation beacons", "Frequency", num2text(beacon_freq / 10))) * 10 if (freq > 0) - src.beacon_freq = freq - src.updateUsrDialog() -/* if("screw") - src.screwloose = !src.screwloose - usr << "You press the weird button." - src.updateUsrDialog() */ - if("hack") - if(!src.emagged) - src.emagged = 2 - src.hacked = 1 - usr << "You corrupt [src]'s cleaning software." - else if(!src.hacked) - usr << "[src] does not seem to respond to your repair code!" - else - src.hacked = 0 - src.emagged = 0 - usr << "[src]'s software has been reset!" - src.updateUsrDialog() + beacon_freq = freq + updateUsrDialog() /obj/machinery/bot/cleanbot/attackby(obj/item/weapon/W, mob/user as mob) if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) - if(src.allowed(usr) && !open && !emagged) - src.locked = !src.locked - user << "You [ src.locked ? "lock" : "unlock"] the [src] behaviour controls." + if(allowed(usr) && !open && !emagged) + locked = !locked + user << "You [ locked ? "lock" : "unlock"] the [src] behaviour controls." else if(emagged) user << "ERROR" @@ -163,135 +132,76 @@ text("[src.oddbutton ? "Yes" : "No" /obj/machinery/bot/cleanbot/Emag(mob/user as mob) ..() - if(open && !locked) - if(user) user << "[src] buzzes and beeps." - src.emagged = 2 + if(emagged == 2) + if(user) + user << "[src] buzzes and beeps." + +/obj/machinery/bot/cleanbot/process_scan(var/obj/effect/decal/cleanable/D) + for(var/T in target_types) + if(istype(D, T)) + return D /obj/machinery/bot/cleanbot/process() - set background = BACKGROUND_ENABLED - - if(!src.on) + if (!..()) return - if(src.cleaning) - return - var/list/cleanbottargets = list() - if(!src.emagged && prob(5)) + if(mode == BOT_CLEANING) + return + + if(emagged == 2) //Emag functions + if(istype(loc,/turf/simulated)) + + if(prob(10)) //Wets floors randomly + var/turf/simulated/T = loc + T.MakeSlippery() + + if(prob(5)) //Spawns foam! + visible_message("[src] whirs and bubbles violently, before releasing a plume of froth!") + new /obj/effect/effect/foam(loc) + + else if (prob(5)) visible_message("[src] makes an excited beeping booping sound!") - if(src.emagged && prob(10)) //Wets floors randomly - if(istype(loc,/turf/simulated)) - var/turf/simulated/T = src.loc - T.MakeSlippery() + if(!target) //Search for cleanables it can see. + target = scan(/obj/effect/decal/cleanable/, oldtarget) + oldtarget = target - if(src.emagged && prob(5)) //Spawns foam! - visible_message("[src] whirs and bubbles violently, before releasing a plume of froth!") - new /obj/effect/effect/foam(src.loc) + if(!target) + if(loc != oldloc) + oldtarget = null - if(!src.target || src.target == null) - for (var/obj/effect/decal/cleanable/D in view(7,src)) - for(var/T in src.target_types) - if(!(D in cleanbottargets) && (D.type == T || D.parent_type == T) && D != src.oldtarget) - src.oldtarget = D - src.target = D - return + if(auto_patrol) + if(mode == BOT_IDLE || mode == BOT_START_PATROL) + start_patrol() - if(!src.target || src.target == null) - if(src.loc != src.oldloc) - src.oldtarget = null + if(mode == BOT_PATROL) + bot_patrol() - if (!should_patrol) + return + + if(target) + if(!path || path.len == 0) //No path, need a new one + //Try to produce a path to the target, and ignore airlocks to which it has access. + path = AStar(loc, target.loc, /turf/proc/AdjacentTurfsWithAccess, /turf/proc/Distance, 0, 30, id=botcard) + if (!bot_move(target)) + add_to_ignore(target) + target = null + return + mode = BOT_MOVING + else if (!bot_move(target)) + target = null + mode = BOT_IDLE + + if(loc == target.loc) + clean(target) + path = list() + target = null return - if (!patrol_path || patrol_path.len < 1) - var/datum/radio_frequency/frequency = radio_controller.return_frequency(beacon_freq) - - if(!frequency) return - - closest_dist = 9999 - closest_loc = null - next_dest_loc = null - - var/datum/signal/signal = new() - signal.source = src - signal.transmission_method = 1 - signal.data = list("findbeacon" = "patrol") - frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS) - spawn(5) - if (!next_dest_loc) - next_dest_loc = closest_loc - if (next_dest_loc) - src.patrol_path = AStar(src.loc, next_dest_loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 120, id=botcard, exclude=null) - if(!patrol_path) - patrol_path = list() - else - patrol_move() - - return - - if(target && path.len == 0) - spawn(0) - if(!src || !target) return - src.path = AStar(src.loc, src.target.loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 30) - if(!src.path) - src.path = list() - if(src.path.len == 0) - src.oldtarget = src.target - src.target = null - return - if(src.path.len > 0 && src.target && (src.target != null)) - step_to(src, src.path[1]) - src.path -= src.path[1] - else if(src.path.len == 1) - step_to(src, target) - - if(src.target && (src.target != null)) - patrol_path = null - if(src.loc == src.target.loc) - clean(src.target) - src.path = new() - src.target = null - return - - src.oldloc = src.loc - -/obj/machinery/bot/cleanbot/proc/patrol_move() - if (src.patrol_path.len <= 0) - return - - var/next = src.patrol_path[1] - src.patrol_path -= next - if (next == src.loc) - return - - var/moved = step_towards(src, next) - if (!moved) - failed_steps++ - if (failed_steps > 4) - patrol_path = null - next_dest = null - failed_steps = 0 - else - failed_steps = 0 - -/obj/machinery/bot/cleanbot/receive_signal(datum/signal/signal) - var/recv = signal.data["beacon"] - var/valid = signal.data["patrol"] - if(!recv || !valid) - return - - var/dist = get_dist(src, signal.source.loc) - if (dist < closest_dist && signal.source.loc != src.loc) - closest_dist = dist - closest_loc = signal.source.loc - next_dest = signal.data["next_patrol"] - - if (recv == next_dest) - next_dest_loc = signal.source.loc - next_dest = signal.data["next_patrol"] + oldloc = loc /obj/machinery/bot/cleanbot/proc/get_targets() - src.target_types = new/list() + target_types = new/list() target_types += /obj/effect/decal/cleanable/oil target_types += /obj/effect/decal/cleanable/vomit @@ -306,7 +216,7 @@ text("[src.oddbutton ? "Yes" : "No" target_types += /obj/effect/decal/cleanable/greenglow target_types += /obj/effect/decal/cleanable/dirt - if(src.blood) + if(blood) target_types += /obj/effect/decal/cleanable/xenoblood/ target_types += /obj/effect/decal/cleanable/xenoblood/xgibs target_types += /obj/effect/decal/cleanable/blood/ @@ -314,20 +224,21 @@ text("[src.oddbutton ? "Yes" : "No" target_types += /obj/effect/decal/cleanable/trail_holder /obj/machinery/bot/cleanbot/proc/clean(var/obj/effect/decal/cleanable/target) - src.anchored = 1 - src.icon_state = "cleanbot-c" + anchored = 1 + icon_state = "cleanbot-c" visible_message("[src] begins to clean up [target]") - src.cleaning = 1 + mode = BOT_CLEANING spawn(50) - src.cleaning = 0 - qdel(target) - src.icon_state = "cleanbot[src.on]" - src.anchored = 0 - src.target = null + if(mode == BOT_CLEANING) + qdel(target) + anchored = 0 + target = null + mode = BOT_IDLE + icon_state = "cleanbot[on]" /obj/machinery/bot/cleanbot/explode() - src.on = 0 - src.visible_message("[src] blows apart!") + on = 0 + visible_message("[src] blows apart!") var/turf/Tsec = get_turf(src) new /obj/item/weapon/reagent_containers/glass/bucket(Tsec) @@ -348,17 +259,17 @@ text("[src.oddbutton ? "Yes" : "No" if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm)) user.drop_item() qdel(W) - var/turf/T = get_turf(src.loc) + var/turf/T = get_turf(loc) var/obj/machinery/bot/cleanbot/A = new /obj/machinery/bot/cleanbot(T) - A.name = src.created_name + A.name = created_name user << "You add the robot arm to the bucket and sensor assembly. Beep boop!" user.unEquip(src, 1) qdel(src) else if (istype(W, /obj/item/weapon/pen)) - var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN) + var/t = copytext(stripped_input(user, "Enter new robot name", name, created_name),1,MAX_NAME_LEN) if (!t) return - if (!in_range(src, usr) && src.loc != usr) + if (!in_range(src, usr) && loc != usr) return - src.created_name = t + created_name = t diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index fd0f7ae848e..fd42c38f7b1 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -25,7 +25,6 @@ var/threatlevel = 0 var/target_lastloc //Loc of target when arrested. var/last_found //There's a delay - var/frustration = 0 //var/emagged = 0 //Emagged Secbots view everyone as a criminal var/declare_arrests = 1 //When making an arrest, should it notify everyone wearing sechuds? var/idcheck = 1 //If true, arrest people with no IDs @@ -34,38 +33,17 @@ var/arrest_type = 0 //If true, don't handcuff var/projectile = /obj/item/projectile/energy/electrode //Holder for projectile type var/shoot_sound = 'sound/weapons/Taser.ogg' - - var/mode = 0 -#define SECBOT_IDLE 0 // idle -#define SECBOT_HUNT 1 // found target, hunting -#define SECBOT_PREP_ARREST 2 // at target, preparing to arrest -#define SECBOT_ARREST 3 // arresting target -#define SECBOT_START_PATROL 4 // start patrol -#define SECBOT_PATROL 5 // patrolling -#define SECBOT_SUMMON 6 // summoned by PDA - - var/auto_patrol = 0 // set to make bot automatically patrol - - var/beacon_freq = 1445 // navigation beacon frequency - var/control_freq = 1447 // bot control frequency - + radio_frequency = SEC_FREQ + bot_type = SEC_BOT + bot_filter = RADIO_SECBOT +/ //List of weapons that secbots will not arrest for var/safe_weapons = list(\ /obj/item/weapon/gun/energy/laser/bluetag,\ /obj/item/weapon/gun/energy/laser/redtag,\ - /obj/item/weapon/gun/energy/laser/practice) - - var/turf/patrol_target // this is turf to navigate to (location of beacon) - var/new_destination // pending new destination (waiting for beacon response) - var/destination // destination description tag - var/next_destination // the next destination in the patrol route - var/list/path = new // list of path turfs - - var/blockcount = 0 //number of times retried a blocked path - var/awaiting_beacon = 0 // count of pticks awaiting a beacon response - - var/nearest_beacon // the nearest beacon's tag - var/turf/nearest_beacon_loc // the nearest beacon's location + /obj/item/weapon/gun/energy/laser/practice,\ + /obj/item/weapon/melee/telebaton,\ + /obj/item/weapon/gun/energy/kinetic_accelerator) /obj/item/weapon/ed209_assembly @@ -85,16 +63,15 @@ name = created_name if(created_lasercolor) lasercolor = created_lasercolor - src.icon_state = "[lasercolor]ed209[src.on]" - src.set_weapon() //giving it the right projectile and firing sound. + icon_state = "[lasercolor]ed209[on]" + set_weapon() //giving it the right projectile and firing sound. spawn(3) - src.botcard = new /obj/item/weapon/card/id(src) var/datum/job/detective/J = new/datum/job/detective - src.botcard.access = J.get_access() + botcard.access = J.get_access() + prev_access = botcard.access - if(radio_controller) - radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT) - radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS) + + add_to_beacons(bot_filter) if(lasercolor) shot_delay = 6//Longer shot delay because JESUS CHRIST check_records = 0//Don't actively target people set to arrest @@ -108,19 +85,28 @@ /obj/machinery/bot/ed209/turn_on() . = ..() - src.icon_state = "[lasercolor]ed209[src.on]" - src.mode = SECBOT_IDLE - src.updateUsrDialog() + icon_state = "[lasercolor]ed209[on]" + mode = BOT_IDLE + updateUsrDialog() /obj/machinery/bot/ed209/turn_off() ..() - src.target = null - src.oldtarget_name = null - src.anchored = 0 - src.mode = SECBOT_IDLE + icon_state = "[lasercolor]ed209[on]" + updateUsrDialog() + +/obj/machinery/bot/ed209/bot_reset() + ..() + target = null + oldtarget_name = null + anchored = 0 walk_to(src,0) - src.icon_state = "[lasercolor]ed209[src.on]" - src.updateUsrDialog() + last_found = world.time + set_weapon() + +/obj/machinery/bot/ed209/set_custom_texts() + text_hack = "You disable [name]'s combat inhibitor." + text_dehack = "You restore [name]'s combat inhibitor." + text_dehack_fail = "[name] ignores your attempts to restrict him!" /obj/machinery/bot/ed209/attack_hand(mob/user as mob) . = ..() @@ -129,13 +115,14 @@ var/dat dat += hack(user) dat += text({" +Security Unit v2.6 controls

Status: []
-Behaviour controls are [src.locked ? "locked" : "unlocked"]
-Maintenance panel panel is [src.open ? "opened" : "closed"]
"}, +Behaviour controls are [locked ? "locked" : "unlocked"]
+Maintenance panel panel is [open ? "opened" : "closed"]
"}, -"
[src.on ? "On" : "Off"]" ) +"[on ? "On" : "Off"]" ) - if(!src.locked || issilicon(user)) + if(!locked || issilicon(user)) if(!lasercolor) dat += text({"
Arrest Unidentifiable Persons: []
@@ -143,82 +130,50 @@ Arrest for Unauthorized Weapons: []
Arrest for Warrant: []

Operating Mode: []
-Report Arrests[]"}, - -"[src.idcheck ? "Yes" : "No"]", -"[src.weaponscheck ? "Yes" : "No"]", -"[src.check_records ? "Yes" : "No"]", -"[src.arrest_type ? "Detain" : "Arrest"]", -"[src.declare_arrests ? "Yes" : "No"]" ) - - dat += text({"
-Auto Patrol: []"}, +Report Arrests[]
+Auto Patrol[]"}, +"[idcheck ? "Yes" : "No"]", +"[weaponscheck ? "Yes" : "No"]", +"[check_records ? "Yes" : "No"]", +"[arrest_type ? "Detain" : "Arrest"]", +"[declare_arrests ? "Yes" : "No"]", "[auto_patrol ? "On" : "Off"]" ) - - var/datum/browser/popup = new(user, "autosec", "Securitron v2.0.9 controls") + var/datum/browser/popup = new(user, "autoed209", "Automatic Security Unit v2.6") popup.set_content(dat) popup.open() return /obj/machinery/bot/ed209/Topic(href, href_list) - if (..()) - return - usr.set_machine(src) - src.add_fingerprint(usr) if(lasercolor && (istype(usr,/mob/living/carbon/human))) var/mob/living/carbon/human/H = usr if((lasercolor == "b") && (istype(H.wear_suit, /obj/item/clothing/suit/redtag)))//Opposing team cannot operate it return else if((lasercolor == "r") && (istype(H.wear_suit, /obj/item/clothing/suit/bluetag))) return - if ((href_list["power"]) && (src.allowed(usr))) - if (src.on && !src.emagged) - turn_off() - else - turn_on() - return + ..() switch(href_list["operation"]) if ("idcheck") - src.idcheck = !src.idcheck - src.updateUsrDialog() + idcheck = !idcheck if("weaponscheck") - src.weaponscheck = !src.weaponscheck - src.updateUsrDialog() - if("ignorerec") - src.check_records = !src.check_records - src.updateUsrDialog() - if("switchmode") - src.arrest_type = !src.arrest_type - src.updateUsrDialog() - if("patrol") - auto_patrol = !auto_patrol - mode = SECBOT_IDLE + weaponscheck = !weaponscheck + updateUsrDialog() + if ("ignorerec") + check_records = !check_records + updateUsrDialog() + if ("switchmode") + arrest_type = !arrest_type updateUsrDialog() if("declarearrests") - src.declare_arrests = !src.declare_arrests - src.updateUsrDialog() - if("hack") - if(!src.emagged) - src.emagged = 2 - src.hacked = 1 - src.set_weapon() - usr << "You disable [src]'s combat inhibitor." - else if(!src.hacked) - usr << "[src] ignores your attempts to restrict it!" - else - src.emagged = 0 - src.hacked = 0 - src.set_weapon() - usr << "You restore [src]'s combat inhibitor." - src.updateUsrDialog() + declare_arrests = !declare_arrests + updateUsrDialog() /obj/machinery/bot/ed209/attackby(obj/item/weapon/W as obj, mob/user as mob) if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) - if (src.allowed(user) && !open && !emagged) - src.locked = !src.locked - user << "Controls are now [src.locked ? "locked" : "unlocked"]." + if (allowed(user) && !open && !emagged) + locked = !locked + user << "Controls are now [locked ? "locked" : "unlocked"]." else if(emagged) user << "ERROR" @@ -230,79 +185,75 @@ Auto Patrol: []"}, ..() if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry. return - if (!istype(W, /obj/item/weapon/screwdriver) && (!src.target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. + if (!istype(W, /obj/item/weapon/screwdriver) && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. if(W.force && W.damtype != STAMINA)//If force is non-zero and damage type isn't stamina. threatlevel = user.assess_threat(src) threatlevel += 6 if(threatlevel >= 4) - src.target = user + target = user if(lasercolor)//To make up for the fact that lasertag bots don't hunt - src.shootAt(user) - src.mode = SECBOT_HUNT + shootAt(user) + mode = BOT_HUNT /obj/machinery/bot/ed209/Emag(mob/user as mob) ..() - if(open && !locked) - if(user) user << "You short out [src]'s target assessment circuits." - spawn(0) - audible_message("[src] buzzes oddly!") - src.target = null - if(user) src.oldtarget_name = user.name - src.last_found = world.time - src.anchored = 0 - src.declare_arrests = 0 - src.emagged = 2 - src.on = 1 - src.icon_state = "[lasercolor]ed209[src.on]" - src.set_weapon() - mode = SECBOT_IDLE + if(emagged == 2) + if(user) + user << "You short out [src]'s target assessment circuits." + oldtarget_name = user.name + audible_message("[src] buzzes oddly!") + declare_arrests = 0 + icon_state = "[lasercolor]ed209[on]" + set_weapon() /obj/machinery/bot/ed209/process() - set background = BACKGROUND_ENABLED - - if (!src.on || src.disabled) + if (!..()) return + + if(disabled) + return + var/list/targets = list() - for (var/mob/living/carbon/C in view(9,src)) //Let's find us a target + for (var/mob/living/carbon/C in view(7,src)) //Let's find us a target var/threatlevel = 0 if ((C.stat) || (C.lying)) continue threatlevel = C.assess_threat(src, lasercolor) - //src.speak(C.real_name + text(": threat: []", threatlevel)) + //speak(C.real_name + text(": threat: []", threatlevel)) if (threatlevel < 4 ) continue var/dst = get_dist(src, C) - if ( dst <= 1 || dst > 12) + if ( dst <= 1 || dst > 7) continue targets += C if (targets.len>0) var/mob/living/carbon/t = pick(targets) if ((t.stat!=2) && (t.lying != 1) && (!t.handcuffed)) //we don't shoot people who are dead, cuffed or lying down. - src.shootAt(t) + shootAt(t) switch(mode) - if(SECBOT_IDLE) // idle + if(BOT_IDLE) // idle walk_to(src,0) - if(!src.lasercolor) //lasertag bots don't want to arrest anyone + if(!lasercolor) //lasertag bots don't want to arrest anyone look_for_perp() // see if any criminals are in range if(!mode && auto_patrol) // still idle, and set to patrol - mode = SECBOT_START_PATROL // switch to patrol mode + mode = BOT_START_PATROL // switch to patrol mode - if(SECBOT_HUNT) // hunting for perp + if(BOT_HUNT) // hunting for perp // if can't reach perp for long enough, go idle - if(src.frustration >= 8) + if (frustration >= 8) walk_to(src,0) back_to_idle() if(target) // make sure target exists - if(src.Adjacent(target) && isturf(src.target.loc)) // if right next to perp - playsound(src.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) - src.icon_state = "[lasercolor]ed209-c" + if(Adjacent(target) && isturf(target.loc)) // if right next to perp + playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) + icon_state = "[lasercolor]ed209-c" spawn(2) - src.icon_state = "[lasercolor]ed209[src.on]" - var/mob/living/carbon/M = src.target + icon_state = "[lasercolor]ed209[on]" + var/mob/living/carbon/M = target if(istype(M, /mob/living/carbon/human)) if( M.stuttering < 5 && !(HULK in M.mutations) ) M.stuttering = 5 @@ -315,45 +266,45 @@ Auto Patrol: []"}, if(declare_arrests) var/area/location = get_area(src) - broadcast_hud_message("[src.name] is [arrest_type ? "detaining" : "arresting"] level [threatlevel] scumbag [target.name] in [location]", src) - target.visible_message("[src.target] has been stunned by [src]!",\ - "[src.target] has been stunned by [src]!") + speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag [target] in [location].", radio_frequency) + target.visible_message("[target] has been stunned by [src]!",\ + "[target] has been stunned by [src]!") - mode = SECBOT_PREP_ARREST - src.anchored = 1 - src.target_lastloc = M.loc + mode = BOT_PREP_ARREST + anchored = 1 + target_lastloc = M.loc return else // not next to perp - var/turf/olddist = get_dist(src, src.target) - walk_to(src, src.target,1,4) - if((get_dist(src, src.target)) >= (olddist)) - src.frustration++ + var/turf/olddist = get_dist(src, target) + walk_to(src, target,1,4) + if ((get_dist(src, target)) >= (olddist)) + frustration++ else - src.frustration = 0 + frustration = 0 else back_to_idle() - if(SECBOT_PREP_ARREST) // preparing to arrest target + if(BOT_PREP_ARREST) // preparing to arrest target // see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again. - if( !src.Adjacent(target) || !isturf(src.target.loc) || src.target.weakened < 2 ) + if( !Adjacent(target) || !isturf(target.loc) || target.weakened < 2 ) back_to_hunt() return if(iscarbon(target) && target.canBeHandcuffed()) - if(!src.arrest_type) - if(!src.target.handcuffed) //he's not cuffed? Try to cuff him! - mode = SECBOT_ARREST - playsound(src.loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2) - target.visible_message("[src] is trying to put zipties on [src.target]!",\ - "[src] is trying to put zipties on [src.target]!") + if(!arrest_type) + if(!target.handcuffed) //he's not cuffed? Try to cuff him! + mode = BOT_ARREST + playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2) + target.visible_message("[src] is trying to put zipties on [target]!",\ + "[src] is trying to put zipties on [target]!") spawn(60) - if( !src.Adjacent(target) || !isturf(src.target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing. + if( !Adjacent(target) || !isturf(target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing. return - if(!src.target.handcuffed) - src.target.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(src.target) + if(!target.handcuffed) + target.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(target) target.update_inv_handcuffed(0) //update the handcuffs overlay back_to_idle() else @@ -363,325 +314,78 @@ Auto Patrol: []"}, back_to_idle() return - if(SECBOT_ARREST) + if(BOT_ARREST) if (!target) - src.anchored = 0 - mode = SECBOT_IDLE - src.last_found = world.time + anchored = 0 + mode = BOT_IDLE + last_found = world.time frustration = 0 return - if(src.target.handcuffed) //no target or target cuffed? back to idle. + if(target.handcuffed) //no target or target cuffed? back to idle. back_to_idle() return - if( !src.Adjacent(target) || !isturf(src.target.loc) || (src.target.loc != src.target_lastloc && src.target.weakened < 2) ) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again. + if( !Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.weakened < 2) ) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again. back_to_hunt() return + else + mode = BOT_PREP_ARREST + anchored = 0 + + if(BOT_START_PATROL) + look_for_perp() + start_patrol() + + if(BOT_PATROL) + look_for_perp() + bot_patrol() - if(SECBOT_START_PATROL) // start a patrol - - if(path.len > 0 && patrol_target) // have a valid path, so just resume - mode = SECBOT_PATROL - return - - else if(patrol_target) // has patrol target already - spawn(0) - calc_path() // so just find a route to it - if(path.len == 0) - patrol_target = 0 - return - mode = SECBOT_PATROL - - - else // no patrol target, so need a new one - find_patrol_target() - speak("Engaging patrol mode.") - - - if(SECBOT_PATROL) // patrol mode - patrol_step() - spawn(5) - if(mode == SECBOT_PATROL) - patrol_step() - - if(SECBOT_SUMMON) // summoned to PDA - patrol_step() - spawn(4) - if(mode == SECBOT_SUMMON) - patrol_step() - sleep(4) - patrol_step() return /obj/machinery/bot/ed209/proc/back_to_idle() - src.anchored = 0 - mode = SECBOT_IDLE - src.target = null - src.last_found = world.time + anchored = 0 + mode = BOT_IDLE + target = null + last_found = world.time frustration = 0 spawn(0) process() //ensure bot quickly responds /obj/machinery/bot/ed209/proc/back_to_hunt() - src.anchored = 0 - src.frustration = 0 - mode = SECBOT_HUNT + anchored = 0 + frustration = 0 + mode = BOT_HUNT spawn(0) process() //ensure bot quickly responds -// perform a single patrol step -/obj/machinery/bot/ed209/proc/patrol_step() - - if(loc == patrol_target) // reached target - at_patrol_target() - return - - else if(path.len > 0 && patrol_target) // valid path - - var/turf/next = path[1] - if(next == loc) - path -= next - return - - - if(istype( next, /turf/simulated)) - - var/moved = step_towards(src, next) // attempt to move - if(moved) // successful move - blockcount = 0 - path -= loc - - if(lasercolor) - sleep(20) - else - look_for_perp() - else // failed to move - - blockcount++ - - if(blockcount > 5) // attempt 5 times before recomputing - // find new path excluding blocked turf - - spawn(2) - calc_path(next) - if(path.len == 0) - find_patrol_target() - else - blockcount = 0 - - return - - return - - else // not a valid turf - mode = SECBOT_IDLE - return - - else // no path, so calculate new one - mode = SECBOT_START_PATROL - - -// finds a new patrol target -/obj/machinery/bot/ed209/proc/find_patrol_target() - send_status() - if(awaiting_beacon) // awaiting beacon response - awaiting_beacon++ - if(awaiting_beacon > 5) // wait 5 secs for beacon response - find_nearest_beacon() // then go to nearest instead - return - - if(next_destination) - set_destination(next_destination) - else - find_nearest_beacon() - return - - -// finds the nearest beacon to self -// signals all beacons matching the patrol code -/obj/machinery/bot/ed209/proc/find_nearest_beacon() - nearest_beacon = null - new_destination = "__nearest__" - post_signal(beacon_freq, "findbeacon", "patrol") - awaiting_beacon = 1 - spawn(10) - awaiting_beacon = 0 - if(nearest_beacon) - set_destination(nearest_beacon) - else - auto_patrol = 0 - mode = SECBOT_IDLE - speak("Disengaging patrol mode.") - send_status() - - -/obj/machinery/bot/ed209/proc/at_patrol_target() - if(auto_patrol) - find_patrol_target() - else - mode = SECBOT_IDLE - return - - -// sets the current destination -// signals all beacons matching the patrol code -// beacons will return a signal giving their locations -/obj/machinery/bot/ed209/proc/set_destination(var/new_dest) - new_destination = new_dest - post_signal(beacon_freq, "findbeacon", "patrol") - awaiting_beacon = 1 - - -// receive a radio signal -// used for beacon reception - -/obj/machinery/bot/ed209/receive_signal(datum/signal/signal) - - if(!on) - return - - /* - world << "rec signal: [signal.source]" - for(var/x in signal.data) - world << "* [x] = [signal.data[x]]" - */ - - var/recv = signal.data["command"] - // process all-bot input - if(recv=="bot_status") - send_status() - - // check to see if we are the commanded bot - if(signal.data["active"] == src) - // process control input - switch(recv) - if("stop") - mode = SECBOT_IDLE - auto_patrol = 0 - return - - if("go") - mode = SECBOT_IDLE - auto_patrol = 1 - return - - if("summon") - patrol_target = signal.data["target"] - next_destination = destination - destination = null - awaiting_beacon = 0 - mode = SECBOT_SUMMON - calc_path() - speak("Responding.") - - return - - - - // receive response from beacon - recv = signal.data["beacon"] - var/valid = signal.data["patrol"] - if(!recv || !valid) - return - - if(recv == new_destination) // if the recvd beacon location matches the set destination - // the we will navigate there - destination = new_destination - patrol_target = signal.source.loc - next_destination = signal.data["next_patrol"] - awaiting_beacon = 0 - - // if looking for nearest beacon - else if(new_destination == "__nearest__") - var/dist = get_dist(src,signal.source.loc) - if(nearest_beacon) - - // note we ignore the beacon we are located at - if(dist>1 && dist 1) - nearest_beacon = recv - nearest_beacon_loc = signal.source.loc - return - - -// send a radio signal with a single data key/value pair -/obj/machinery/bot/ed209/proc/post_signal(var/freq, var/key, var/value) - post_signal_multiple(freq, list("[key]" = value) ) - -// send a radio signal with multiple data key/values -/obj/machinery/bot/ed209/proc/post_signal_multiple(var/freq, var/list/keyval) - - var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq) - - if(!frequency) return - - var/datum/signal/signal = new() - signal.source = src - signal.transmission_method = 1 - //for(var/key in keyval) - // signal.data[key] = keyval[key] - //world << "sent [key],[keyval[key]] on [freq]" - signal.data = keyval - if (signal.data["findbeacon"]) - frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS) - else if (signal.data["type"] == "secbot") - frequency.post_signal(src, signal, filter = RADIO_SECBOT) - else - frequency.post_signal(src, signal) - -// signals bot status etc. to controller -/obj/machinery/bot/ed209/proc/send_status() - var/list/kv = list( - "type" = "secbot", - "name" = name, - "loca" = loc.loc, // area - "mode" = mode, - ) - post_signal_multiple(control_freq, kv) - - - -// calculates a path to the current destination -// given an optional turf to avoid -/obj/machinery/bot/ed209/proc/calc_path(var/turf/avoid = null) - src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 120, id=botcard, exclude=avoid) - if(!src.path) - src.path = list() - - // look for a criminal in view of the bot /obj/machinery/bot/ed209/proc/look_for_perp() - if(src.disabled) + if(disabled) return - src.anchored = 0 - src.threatlevel = 0 - for (var/mob/living/carbon/C in view(12,src)) //Let's find us a criminal + anchored = 0 + threatlevel = 0 + for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal if ((C.stat) || (C.handcuffed)) continue - if ((C.name == src.oldtarget_name) && (world.time < src.last_found + 100)) + if ((C.name == oldtarget_name) && (world.time < last_found + 100)) continue - src.threatlevel = C.assess_threat(src, lasercolor) + threatlevel = C.assess_threat(src, lasercolor) - if (!src.threatlevel) + if (!threatlevel) continue - else if (src.threatlevel >= 4) - src.target = C - src.oldtarget_name = C.name - src.speak("Level [src.threatlevel] infraction alert!") - playsound(src.loc, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/EDPlaceholder.ogg'), 50, 0) - src.visible_message("[src] points at [C.name]!") - mode = SECBOT_HUNT + else if (threatlevel >= 4) + target = C + oldtarget_name = C.name + speak("Level [threatlevel] infraction alert!") + playsound(loc, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/EDPlaceholder.ogg'), 50, 0) + visible_message("[src] points at [C.name]!") + mode = BOT_HUNT spawn(0) process() // ensure bot quickly responds to a perp break @@ -695,14 +399,14 @@ Auto Patrol: []"}, return 0 /obj/machinery/bot/ed209/Bump(M as mob|obj) //Leave no door unopened! - if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard))) + if ((istype(M, /obj/machinery/door)) && (!isnull(botcard))) var/obj/machinery/door/D = M - if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard)) + if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(botcard)) D.open() - src.frustration = 0 - else if ((istype(M, /mob/living/)) && (!src.anchored)) - src.loc = M:loc - src.frustration = 0 + frustration = 0 + else if ((istype(M, /mob/living/)) && (!anchored)) + loc = M:loc + frustration = 0 return /* terrible @@ -715,13 +419,13 @@ Auto Patrol: []"}, /obj/machinery/bot/ed209/explode() walk_to(src,0) - src.visible_message("[src] blows apart!") + visible_message("[src] blows apart!") var/turf/Tsec = get_turf(src) var/obj/item/weapon/ed209_assembly/Sa = new /obj/item/weapon/ed209_assembly(Tsec) Sa.build_step = 1 Sa.overlays += image('icons/obj/aibots.dmi', "hs_hole") - Sa.created_name = src.name + Sa.created_name = name new /obj/item/device/assembly/prox_sensor(Tsec) if(!lasercolor) @@ -756,12 +460,12 @@ Auto Patrol: []"}, s.set_up(3, 1, src) s.start() - new /obj/effect/decal/cleanable/oil(src.loc) + new /obj/effect/decal/cleanable/oil(loc) qdel(src) /obj/machinery/bot/ed209/proc/set_weapon() //used to update the projectile type and firing sound shoot_sound = 'sound/weapons/laser.ogg' - if(src.emagged == 2) + if(emagged == 2) if(lasercolor) projectile = /obj/item/projectile/lasertag else @@ -796,7 +500,7 @@ Auto Patrol: []"}, if (!( istype(U, /turf) )) return var/obj/item/projectile/A = new projectile (loc) - playsound(src.loc, shoot_sound, 50, 1) + playsound(loc, shoot_sound, 50, 1) A.current = U A.yo = U.y - T.y A.xo = U.x - T.x @@ -808,8 +512,8 @@ Auto Patrol: []"}, /obj/machinery/bot/ed209/attack_alien(var/mob/living/carbon/alien/user as mob) ..() if (!isalien(target)) - src.target = user - src.mode = SECBOT_HUNT + target = user + mode = BOT_HUNT /obj/machinery/bot/ed209/emp_act(severity) @@ -817,7 +521,7 @@ Auto Patrol: []"}, if(severity==2 && prob(70)) ..(severity-1) else - var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( src.loc ) + var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( loc ) pulse2.icon = 'icons/effects/effects.dmi' pulse2.icon_state = "empdisable" pulse2.name = "emp sparks" @@ -847,8 +551,8 @@ Auto Patrol: []"}, if(targets.len) var/mob/toarrest = pick(targets) if (toarrest) - src.target = toarrest - src.mode = SECBOT_HUNT + target = toarrest + mode = BOT_HUNT @@ -856,9 +560,9 @@ Auto Patrol: []"}, ..() if(istype(W, /obj/item/weapon/pen)) - var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN) + var/t = copytext(stripped_input(user, "Enter new robot name", name, created_name),1,MAX_NAME_LEN) if(!t) return - if(!in_range(src, usr) && src.loc != usr) return + if(!in_range(src, usr) && loc != usr) return created_name = t return @@ -962,14 +666,14 @@ Auto Patrol: []"}, return build_step++ user << "You add [W] to [src]." - src.item_state = "[lasercolor]ed209_taser" - src.icon_state = "[lasercolor]ed209_taser" + item_state = "[lasercolor]ed209_taser" + icon_state = "[lasercolor]ed209_taser" user.drop_item() qdel(W) if(8) if(istype(W, /obj/item/weapon/screwdriver)) - playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) var/turf/T = get_turf(user) user << "Now attaching the gun to the frame..." sleep(40) @@ -993,18 +697,18 @@ Auto Patrol: []"}, /obj/machinery/bot/ed209/bullet_act(var/obj/item/projectile/Proj) if(!disabled) var/lasertag_check = 0 - if((src.lasercolor == "b")) + if((lasercolor == "b")) if(istype(Proj, /obj/item/projectile/lasertag/redtag)) lasertag_check++ - else if((src.lasercolor == "r")) + else if((lasercolor == "r")) if(istype(Proj, /obj/item/projectile/lasertag/bluetag)) lasertag_check++ if(lasertag_check) icon_state = "[lasercolor]ed2090" - src.disabled = 1 + disabled = 1 target = null spawn(100) - src.disabled = 0 + disabled = 0 icon_state = "[lasercolor]ed2091" return 1 else diff --git a/code/game/machinery/bots/floorbot.dm b/code/game/machinery/bots/floorbot.dm index 195c07958a6..37f35e71252 100644 --- a/code/game/machinery/bots/floorbot.dm +++ b/code/game/machinery/bots/floorbot.dm @@ -36,35 +36,64 @@ maxhealth = 25 //weight = 1.0E7 var/amount = 10 - var/repairing = 0 - var/improvefloors = 0 + var/replacetiles = 0 var/eattiles = 0 var/maketiles = 0 + var/fixfloors = 0 + var/autotile = 0 + var/nag_on_empty = 1 + var/nagged = 0 //Prevents the Floorbot nagging more than once per refill. + var/max_targets = 50 var/turf/target var/turf/oldtarget var/oldloc = null - req_access = list(access_construction) - var/path[] = new() + req_one_access = list(access_construction, access_robotics) var/targetdirection - + radio_frequency = ENG_FREQ //Engineering channel + bot_type = FLOOR_BOT + bot_filter = RADIO_FLOORBOT + var/process_type //Determines what to do when process_scan() recieves a target. See process_scan() for details. + #define HULL_BREACH 1 + #define BRIDGE_MODE 2 + #define FIX_TILE 3 + #define AUTO_TILE 4 + #define REPLACE_TILE 5 + #define TILE_EMAG 6 /obj/machinery/bot/floorbot/New() ..() - src.updateicon() + updateicon() + var/datum/job/engineer/J = new/datum/job/engineer + botcard.access = J.get_access() + prev_access = botcard.access + + spawn(5) + add_to_beacons(bot_filter) /obj/machinery/bot/floorbot/turn_on() . = ..() - src.updateicon() - src.updateUsrDialog() + updateicon() + updateUsrDialog() /obj/machinery/bot/floorbot/turn_off() ..() - src.target = null - src.oldtarget = null - src.oldloc = null - src.updateicon() - src.path = new() - src.updateUsrDialog() + updateicon() + updateUsrDialog() + +/obj/machinery/bot/floorbot/bot_reset() + ..() + target = null + oldtarget = null + oldloc = null + ignore_list = list() + nagged = 0 + anchored = 0 + update_icon() + +/obj/machinery/bot/floorbot/set_custom_texts() + text_hack = "You corrupt [name]'s construction protocols." + text_dehack = "You detect errors in [name] and reset his programming." + text_dehack_fail = "[name] is not responding to reset commands!" /obj/machinery/bot/floorbot/attack_hand(mob/user as mob) . = ..() @@ -76,44 +105,50 @@ /obj/machinery/bot/floorbot/interact(mob/user as mob) var/dat dat += hack(user) - dat += "Automatic Station Floor Repairer v1.0

" - dat += "Status: [src.on ? "On" : "Off"]
" - dat += "Maintenance panel panel is [src.open ? "opened" : "closed"]
" - dat += "Tiles left: [src.amount]
" - dat += "Behvaiour controls are [src.locked ? "locked" : "unlocked"]
" - if(!src.locked || issilicon(user)) - dat += "Improves floors: [src.improvefloors ? "Yes" : "No"]
" - dat += "Finds tiles: [src.eattiles ? "Yes" : "No"]
" - dat += "Make singles pieces of metal into tiles when empty: [src.maketiles ? "Yes" : "No"]
" + dat += "Floor Repairer Controls v1.1

" + dat += "Status: [on ? "On" : "Off"]
" + dat += "Maintenance panel panel is [open ? "opened" : "closed"]
" + dat += "Tiles left: [amount]
" + dat += "Behvaiour controls are [locked ? "locked" : "unlocked"]
" + if(!locked || issilicon(user)) + dat += "Add tiles to new hull plating: [autotile ? "Yes" : "No"]
" + dat += "Replace floor tiles: [replacetiles ? "Yes" : "No"]
" + dat += "Finds tiles: [eattiles ? "Yes" : "No"]
" + dat += "Make pieces of metal into tiles when empty: [maketiles ? "Yes" : "No"]
" + dat += "Transmit notice when empty: [nag_on_empty ? "Yes" : "No"]
" + dat += "Repair damaged tiles and platings: [fixfloors ? "Yes" : "No"]
" + dat += "Patrol Station: [auto_patrol ? "Yes" : "No"]
" var/bmode - if (src.targetdirection) - bmode = dir2text(src.targetdirection) + if (targetdirection) + bmode = dir2text(targetdirection) else - bmode = "Disabled" - dat += "

Bridge Mode : [bmode]
" + bmode = "disabled" + dat += "Bridge Mode : [bmode]
" - user << browse("Repairbot v1.0 controls[dat]", "window=autorepair") - onclose(user, "autorepair") + var/datum/browser/popup = new(user, "autofloor", "Automatic Station Floor Repairer v1.1") + popup.set_content(dat) + popup.open() return /obj/machinery/bot/floorbot/attackby(var/obj/item/W , mob/user as mob) if(istype(W, /obj/item/stack/tile/plasteel)) var/obj/item/stack/tile/plasteel/T = W - if(src.amount >= 50) + if(amount >= 50) return - var/loaded = min(50 - src.amount, T.get_amount()) + var/loaded = min(50-amount, T.amount) T.use(loaded) - src.amount += loaded + amount += loaded if (loaded > 0) - user << "You load [loaded] tiles into the floorbot. He now contains [src.amount] tiles." - src.updateicon() + user << "You load [loaded] tiles into the floorbot. He now contains [amount] tiles." + nagged = 0 + updateicon() else - user << "You need at least one floor tile to put into the floorbot." + user << "You need at least one floor tile to put into [src]" else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) - if(src.allowed(usr) && !open && !emagged) - src.locked = !src.locked - user << "You [src.locked ? "lock" : "unlock"] the [src] behaviour controls." + if(allowed(user) && !open && !emagged) + locked = !locked + user << "You [locked ? "lock" : "unlock"] \the [src] behaviour controls." else if(emagged) user << "ERROR" @@ -121,265 +156,301 @@ user << "Please close the access panel before locking it." else user << "Access denied." - src.updateUsrDialog() + updateUsrDialog() else ..() /obj/machinery/bot/floorbot/Emag(mob/user as mob) ..() - if(open && !locked) - if(user) user << "The [src] buzzes and beeps." + if(emagged == 2) + if(user) + user << "[src] buzzes and beeps." /obj/machinery/bot/floorbot/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - src.add_fingerprint(usr) + ..() switch(href_list["operation"]) - if("start") - if (src.on && !src.emagged) - turn_off() - else - turn_on() - if("improve") - src.improvefloors = !src.improvefloors - src.updateUsrDialog() + if("replace") + replacetiles = !replacetiles if("tiles") - src.eattiles = !src.eattiles - src.updateUsrDialog() + eattiles = !eattiles if("make") - src.maketiles = !src.maketiles - src.updateUsrDialog() - if("hack") - if(!src.emagged) - src.emagged = 2 - src.hacked = 1 - usr << "You corrupt [src]'s construction protocols." - else if(!src.hacked) - usr << "[src] is not responding to reset commands!" - else - src.emagged = 0 - src.hacked = 0 - usr << "You detect errors in [src] and reset its programming." - src.updateUsrDialog() + maketiles = !maketiles + if("fix") + fixfloors = !fixfloors + if("autotile") + autotile = !autotile + if("emptynag") + nag_on_empty = !nag_on_empty + if("bridgemode") - switch(src.targetdirection) - if(null) + var/setdir = input("Select construction direction:") as null|anything in list("north","east","south","west","disable") + switch(setdir) + if("north") targetdirection = 1 - if(1) + if("south") targetdirection = 2 - if(2) + if("east") targetdirection = 4 - if(4) + if("west") targetdirection = 8 - if(8) + if("disable") targetdirection = null - else - targetdirection = null - src.updateUsrDialog() + updateUsrDialog() /obj/machinery/bot/floorbot/process() - set background = BACKGROUND_ENABLED + if (!..()) + return - if(!src.on) + if(mode == BOT_REPAIRING) return - if(src.repairing) - return - var/list/floorbottargets = list() - if(src.amount <= 0 && ((src.target == null) || !src.target)) - if(src.eattiles) - for(var/obj/item/stack/tile/plasteel/T in view(7, src)) - if(T != src.oldtarget && !(target in floorbottargets)) - src.oldtarget = T - src.target = T - break - if(src.target == null || !src.target) - if(src.maketiles) - if(src.target == null || !src.target) - for(var/obj/item/stack/sheet/metal/M in view(7, src)) - if(!(M in floorbottargets) && M != src.oldtarget && M.amount == 1 && !(istype(M.loc, /turf/simulated/wall))) - src.oldtarget = M - src.target = M - break - else + + if(amount <= 0 && !target) //Out of tiles! We must refill! + if(eattiles) //Configured to find and consume floortiles! + target = scan(/obj/item/stack/tile/plasteel, oldtarget) + process_type = null + + if(!target && maketiles) //We did not manage to find any floor tiles! Scan for metal stacks and make our own! + target = scan(/obj/item/stack/sheet/metal, oldtarget) + process_type = null return + else + if(nag_on_empty) //Floorbot is empty and cannot acquire more tiles, nag the engineers for more! + nag() + if(prob(5)) visible_message("[src] makes an excited booping beeping sound!") - if((!src.target || src.target == null) && emagged < 2) - if(targetdirection != null) - /* - for (var/turf/space/D in view(7,src)) - if(!(D in floorbottargets) && D != src.oldtarget) // Added for bridging mode - if(get_dir(src, D) == targetdirection) - src.oldtarget = D - src.target = D - break - */ + //Normal scanning procedure. We have tiles loaded, are not emagged. + if(!target && emagged < 2 && amount > 0) + if(targetdirection != null) //The bot is in bridge mode. + //Try to find a space tile immediately in our selected direction. var/turf/T = get_step(src, targetdirection) if(istype(T, /turf/space)) - src.oldtarget = T - src.target = T - if(!src.target || src.target == null) - for (var/turf/space/D in view(7,src)) - if(!(D in floorbottargets) && D != src.oldtarget && (D.loc.name != "Space")) - src.oldtarget = D - src.target = D - break - if((!src.target || src.target == null ) && src.improvefloors) - for (var/turf/simulated/floor/F in view(7,src)) - if(!(F in floorbottargets) && F != src.oldtarget && F.icon_state == "Floor1" && !(istype(F, /turf/simulated/floor/plating))) - src.oldtarget = F - src.target = F - break - if((!src.target || src.target == null) && src.eattiles) - for(var/obj/item/stack/tile/plasteel/T in view(7, src)) - if(!(T in floorbottargets) && T != src.oldtarget) - src.oldtarget = T - src.target = T - break + target = T - if((!src.target || src.target == null) && emagged == 2) - if(!src.target || src.target == null) - for (var/turf/simulated/floor/D in view(7,src)) - if(!(D in floorbottargets) && D != src.oldtarget && D.floor_tile) - src.oldtarget = D - src.target = D - break - - if(!src.target || src.target == null) - if(src.loc != src.oldloc) - src.oldtarget = null - return - - if(src.target && (src.target != null) && src.path.len == 0) - spawn(0) - if(!istype(src.target, /turf/)) - var/turf/TL = get_turf(target) - src.path = AStar(src.loc, TL, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30) - else - src.path = AStar(src.loc, src.target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30) - if(!src.path) - src.path = list() - if(src.path.len == 0) - src.oldtarget = src.target - src.target = null - return - if(src.path.len > 0 && src.target && (src.target != null)) - step_to(src, src.path[1]) - src.path -= src.path[1] - else if(src.path.len == 1) - step_to(src, target) - src.path = new() - - if(src.loc == src.target || src.loc == src.target.loc) - if(istype(src.target, /obj/item/stack/tile/plasteel)) - src.eattile(src.target) - else if(istype(src.target, /obj/item/stack/sheet/metal)) - src.maketile(src.target) - else if(istype(src.target, /turf/) && emagged < 2) - repair(src.target) - else if(emagged == 2 && istype(src.target,/turf/simulated/floor)) - var/turf/simulated/floor/F = src.target - src.anchored = 1 - src.repairing = 1 - if(prob(90)) - F.break_tile_to_plating() - else - F.ReplaceWithLattice() - visible_message("[src] makes an excited booping sound.") - spawn(50) - src.amount ++ - src.anchored = 0 - src.repairing = 0 - src.target = null - src.path = new() - return - - src.oldloc = src.loc - - -/obj/machinery/bot/floorbot/proc/repair(var/turf/target) - if(istype(target, /turf/space/)) - if(target.loc.name == "Space") + else //Find a space tile farther way! + target = scan(/turf/space, oldtarget) + anchored = 1 + process_type = BRIDGE_MODE return - else if(!istype(target, /turf/simulated/floor)) + + if(!target) + process_type = HULL_BREACH //Ensures the floorbot does not try to "fix" space areas or shuttle docking zones. + target = scan(/turf/space, oldtarget) + anchored = 1 //Prevent the floorbot being blown off-course while trying to reach a hull breach. + return + + if(!target && replacetiles) //Finds a floor without a tile and gives it one. + process_type = REPLACE_TILE //The target must be the floor and not a tile. The floor must not already have a floortile. + //target = scan(/turf/simulated/floor, oldtarget) + return + + if(!target && fixfloors) //Repairs damaged floors and tiles. + process_type = FIX_TILE + target = scan(/turf/simulated/floor, oldtarget) + return + + if(!target && emagged == 2) //We are emagged! Time to rip up the floors! + process_type = TILE_EMAG + target = scan(/turf/simulated/floor, oldtarget) return - if(src.amount <= 0) + + + if(!target) + + if(auto_patrol) + if(mode == BOT_IDLE || mode == BOT_START_PATROL) + start_patrol() + + if(mode == BOT_PATROL) + bot_patrol() + + if(!target) + if(loc != oldloc) + oldtarget = null return - src.anchored = 1 - src.icon_state = "floorbot-c" - if(istype(target, /turf/space/)) - visible_message("[src] begins to repair the hole.") - var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel - src.repairing = 1 - spawn(50) - T.build(src.loc) - src.repairing = 0 - src.amount -= 1 - src.updateicon() - src.anchored = 0 - src.target = null + + if(target) + if(path.len == 0) + if(!istype(target, /turf/)) + var/turf/TL = get_turf(target) + path = AStar(loc, TL, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=botcard) + else + path = AStar(loc, target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=botcard) + + if(!bot_move(target)) + add_to_ignore(target) + oldtarget = target + target = null + mode = BOT_IDLE + return + else if( !bot_move(target) ) + oldtarget = target + target = null + mode = BOT_IDLE + return + + if(loc == target || loc == target.loc) + if(istype(target, /obj/item/stack/tile/plasteel)) + eattile(target) + else if(istype(target, /obj/item/stack/sheet/metal)) + maketile(target) + else if(istype(target, /turf/) && emagged < 2) + repair(target) + else if(emagged == 2 && istype(target,/turf/simulated/floor)) + var/turf/simulated/floor/F = target + anchored = 1 + mode = BOT_REPAIRING + if(prob(90)) + F.break_tile_to_plating() + else + F.ReplaceWithLattice() + visible_message("[src] makes an excited booping sound.") + spawn(50) + amount ++ + anchored = 0 + mode = BOT_IDLE + target = null + path = new() + return + + oldloc = loc + +/obj/machinery/bot/floorbot/proc/nag() //Annoy everyone on the channel to refill us! + if(!nagged) + speak("Requesting refill at [get_area(src)]!", radio_frequency) + nagged = 1 + +/obj/machinery/bot/floorbot/proc/is_hull_breach(var/turf/t) //Ignore space tiles not considered part of a structure, also ignores shuttle docking areas. + var/area/t_area = get_area(t) + if (t_area && (t_area.name == "Space" || findtext(t_area.name, "huttle"))) + return 0 else - visible_message("[src] begins to improve the floor.") - src.repairing = 1 + return 1 + +//Floorbots, having several functions, need sort out special conditions here. +obj/machinery/bot/floorbot/process_scan(var/scan_target) + var/result + var/turf/simulated/floor/F + switch(process_type) + if(HULL_BREACH) //The most common job, patching breaches in the station's hull. + if(is_hull_breach(scan_target)) //Ensure that the targeted space turf is actually part of the station, and not random space. + result = scan_target + if(BRIDGE_MODE) //Only space turfs in our chosen direction are considered. + if(get_dir(src, scan_target) == targetdirection) + result = scan_target + if(REPLACE_TILE) + F = scan_target + if(F.is_plating()) //The floor must not already have a tile. + result = F + if(FIX_TILE) //Selects only damaged floors. + F = scan_target + if(F.broken || F.burnt) + result = F + if(TILE_EMAG) //Emag mode! Rip up the floor and cause breaches to space! + F = scan_target + if(!F.is_plating()) + result = F + else //If no special processing is needed, simply return the result. + result = scan_target + return result + +/obj/machinery/bot/floorbot/proc/repair(var/turf/target_turf) + + if(istype(target_turf, /turf/space/)) + //Must be a hull breach or in bridge mode to continue. + if(!is_hull_breach(target_turf) && !targetdirection) + target = null + return + else if(!istype(target_turf, /turf/simulated/floor)) + return + if(amount <= 0) + mode = BOT_IDLE + target = null + return + var/turf/simulated/floor/F + var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel + anchored = 1 + icon_state = "floorbot-c" + if(istype(target_turf, /turf/space/)) //If we are fixing an area not part of pure space, it is + visible_message(" [targetdirection ? "[src] begins installing a bridge plating." : "[src] begins to repair the hole."] ") + mode = BOT_REPAIRING spawn(50) - src.loc.icon_state = "floor" - src.repairing = 0 - src.amount -= 1 - src.updateicon() - src.anchored = 0 - src.target = null + if(mode == BOT_REPAIRING) + if(autotile) //Build the floor and include a tile. + F = target_turf.ChangeTurf(/turf/simulated/floor) + else //Build a hull plating without a floor tile. + T.build(loc) + mode = BOT_IDLE + amount -= 1 + updateicon() + anchored = 0 + target = null + else + F = target_turf + + mode = BOT_REPAIRING + visible_message(" [src] begins repairing the floor.") + spawn(50) + if(mode == BOT_REPAIRING) + F = target_turf + F.make_plasteel_floor(T) + mode = BOT_IDLE + amount -= 1 + updateicon() + anchored = 0 + target = null /obj/machinery/bot/floorbot/proc/eattile(var/obj/item/stack/tile/plasteel/T) if(!istype(T, /obj/item/stack/tile/plasteel)) return - visible_message("[src] begins to collect tiles.") - src.repairing = 1 + visible_message(" [src] begins to collect tiles.") + mode = BOT_REPAIRING spawn(20) if(isnull(T)) - src.target = null - src.repairing = 0 + target = null + mode = BOT_IDLE return - if(src.amount + T.amount > 50) - var/i = 50 - src.amount - src.amount += i + if(amount + T.amount > 50) + var/i = 50 - amount + amount += i T.amount -= i else - src.amount += T.amount + amount += T.amount qdel(T) - src.updateicon() - src.target = null - src.repairing = 0 + updateicon() + target = null + mode = BOT_IDLE /obj/machinery/bot/floorbot/proc/maketile(var/obj/item/stack/sheet/metal/M) if(!istype(M, /obj/item/stack/sheet/metal)) return - if(M.amount > 1) - return - visible_message("[src] begins to create tiles.") - src.repairing = 1 + visible_message(" [src] begins to create tiles.") + mode = BOT_REPAIRING spawn(20) if(isnull(M)) - src.target = null - src.repairing = 0 + target = null + mode = BOT_IDLE return var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel T.amount = 4 T.loc = M.loc - qdel(M) - src.target = null - src.repairing = 0 + if(M.amount > 1) + M.amount-- + else + qdel(M) + target = null + mode = BOT_IDLE /obj/machinery/bot/floorbot/proc/updateicon() - if(src.amount > 0) - src.icon_state = "floorbot[src.on]" + if(amount > 0) + icon_state = "floorbot[on]" else - src.icon_state = "floorbot[src.on]e" + icon_state = "floorbot[on]e" /obj/machinery/bot/floorbot/explode() - src.on = 0 - src.visible_message("[src] blows apart!") + on = 0 + visible_message("[src] blows apart!") var/turf/Tsec = get_turf(src) var/obj/item/weapon/storage/toolbox/mechanical/N = new /obj/item/weapon/storage/toolbox/mechanical(Tsec) @@ -397,7 +468,7 @@ amount -= 16 else var/obj/item/stack/tile/plasteel/T = new (Tsec) - T.amount = src.amount + T.amount = amount amount = 0 var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread @@ -411,7 +482,7 @@ if(!istype(T, /obj/item/stack/tile/plasteel)) ..() return - if(src.contents.len >= 1) + if(contents.len >= 1) user << "They won't fit in, as there is already stuff inside." return if(T.use(10)) @@ -431,20 +502,20 @@ if(isprox(W)) qdel(W) var/obj/item/weapon/toolbox_tiles_sensor/B = new /obj/item/weapon/toolbox_tiles_sensor() - B.created_name = src.created_name + B.created_name = created_name user.put_in_hands(B) user << "You add the sensor to the toolbox and tiles!" user.unEquip(src, 1) qdel(src) else if (istype(W, /obj/item/weapon/pen)) - var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN) + var/t = copytext(stripped_input(user, "Enter new robot name", name, created_name),1,MAX_NAME_LEN) if (!t) return - if (!in_range(src, usr) && src.loc != usr) + if (!in_range(src, usr) && loc != usr) return - src.created_name = t + created_name = t /obj/item/weapon/toolbox_tiles_sensor/attackby(var/obj/item/W, mob/user as mob) ..() @@ -452,16 +523,16 @@ qdel(W) var/turf/T = get_turf(user.loc) var/obj/machinery/bot/floorbot/A = new /obj/machinery/bot/floorbot(T) - A.name = src.created_name + A.name = created_name user << "You add the robot arm to the odd looking toolbox assembly! Boop beep!" user.unEquip(src, 1) qdel(src) else if (istype(W, /obj/item/weapon/pen)) - var/t = stripped_input(user, "Enter new robot name", src.name, src.created_name) + var/t = stripped_input(user, "Enter new robot name", name, created_name) if (!t) return - if (!in_range(src, usr) && src.loc != usr) + if (!in_range(src, usr) && loc != usr) return - src.created_name = t \ No newline at end of file + created_name = t \ No newline at end of file diff --git a/code/game/machinery/bots/medbot.dm b/code/game/machinery/bots/medbot.dm index 6642dcbbe41..91accb8bcaf 100644 --- a/code/game/machinery/bots/medbot.dm +++ b/code/game/machinery/bots/medbot.dm @@ -13,31 +13,34 @@ anchored = 0 health = 20 maxhealth = 20 - req_access =list(access_medical) + req_one_access =list(access_medical, access_robotics) var/stunned = 0 //It can be stunned by tasers. Delicate circuits. // var/emagged = 0 var/list/botcard_access = list(access_medical) var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents. var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits. - var/frustration = 0 - var/path[] = new() var/mob/living/carbon/patient = null var/mob/living/carbon/oldpatient = null var/oldloc = null var/last_found = 0 var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages - var/currently_healing = 0 var/injection_amount = 15 //How much reagent do we inject at a time? var/heal_threshold = 10 //Start healing when they have this much damage in a category var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents. - + var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users. + var/declare_cooldown = 0 //Prevents spam of critical patient alerts. + var/stationary_mode = 0 //If enabled, the Medibot will not move automatically. + radio_frequency = MED_FREQ //Medical frequency //Setting which reagents to use to treat what by default. By id. var/treatment_brute = "tricordrazine" var/treatment_oxy = "tricordrazine" var/treatment_fire = "tricordrazine" var/treatment_tox = "tricordrazine" var/treatment_virus = "spaceacillin" + var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible. var/shut_up = 0 //self explanatory :) + bot_type = MED_BOT + bot_filter = RADIO_MEDBOT /obj/machinery/bot/medbot/mysterious name = "\improper Mysterious Medibot" @@ -58,43 +61,63 @@ var/skin = null //Same as medbot, set to tox or ointment for the respective kits. w_class = 3.0 - New() + /obj/item/weapon/firstaid_arm_assembly/New() ..() spawn(5) - if(src.skin) - src.overlays += image('icons/obj/aibots.dmi', "kit_skin_[src.skin]") + if(skin) + overlays += image('icons/obj/aibots.dmi', "kit_skin_[skin]") +/obj/machinery/bot/medbot/proc/updateicon() + if(!on) + icon_state = "medibot0" + return + if(mode == BOT_HEALING) + icon_state = "medibots[stationary_mode]" + return + else if(stationary_mode) //Bot has yellow light to indicate stationary mode. + icon_state = "medibot2" + else + icon_state = "medibot1" /obj/machinery/bot/medbot/New() ..() - src.icon_state = "medibot[src.on]" + updateicon() spawn(4) - if(src.skin) - src.overlays += image('icons/obj/aibots.dmi', "medskin_[src.skin]") + if(skin) + overlays += image('icons/obj/aibots.dmi', "medskin_[skin]") - src.botcard = new /obj/item/weapon/card/id(src) - if(isnull(src.botcard_access) || (src.botcard_access.len < 1)) + if(isnull(botcard_access) || (botcard_access.len < 1)) var/datum/job/doctor/J = new/datum/job/doctor - src.botcard.access = J.get_access() + botcard.access = J.get_access() else - src.botcard.access = src.botcard_access + botcard.access = botcard_access + prev_access = botcard.access + add_to_beacons(bot_filter) /obj/machinery/bot/medbot/turn_on() . = ..() - src.icon_state = "medibot[src.on]" - src.updateUsrDialog() + updateicon() + updateUsrDialog() /obj/machinery/bot/medbot/turn_off() ..() - src.patient = null - src.oldpatient = null - src.oldloc = null - src.path = new() - src.currently_healing = 0 - src.last_found = world.time - src.icon_state = "medibot[src.on]" - src.updateUsrDialog() + updateicon() + updateUsrDialog() + +/obj/machinery/bot/medbot/bot_reset() + ..() + patient = null + oldpatient = null + oldloc = null + last_found = world.time + declare_cooldown = 0 + +/obj/machinery/bot/medbot/set_custom_texts() + + text_hack = "You corrupt [name]'s reagent processor circuits." + text_dehack = "You reset [name]'s reagent processor circuits." + text_dehack_fail = "[name] seems damaged and does not respond to reprogramming!" /obj/machinery/bot/medbot/attack_paw(mob/user as mob) return attack_hand(user) @@ -105,99 +128,93 @@ return var/dat dat += hack(user) - dat += "Automatic Medical Unit v1.0

" - dat += "Status: [src.on ? "On" : "Off"]
" - dat += "Maintenance panel panel is [src.open ? "opened" : "closed"]
" + dat += "Medical Unit Controls v1.1

" + dat += "Status: [on ? "On" : "Off"]
" + dat += "Maintenance panel panel is [open ? "opened" : "closed"]
" dat += "Beaker: " - if (src.reagent_glass) - dat += "Loaded \[[src.reagent_glass.reagents.total_volume]/[src.reagent_glass.reagents.maximum_volume]\]" + if (reagent_glass) + dat += "Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]" else dat += "None Loaded" - dat += "
Behaviour controls are [src.locked ? "locked" : "unlocked"]
" - if(!src.locked || issilicon(user)) + dat += "
Behaviour controls are [locked ? "locked" : "unlocked"]
" + if(!locked || issilicon(user)) dat += "Healing Threshold: " dat += "-- " dat += "- " - dat += "[src.heal_threshold] " + dat += "[heal_threshold] " dat += "+ " dat += "++" dat += "
" dat += "Injection Level: " dat += "- " - dat += "[src.injection_amount] " + dat += "[injection_amount] " dat += "+ " dat += "
" dat += "Reagent Source: " - dat += "[src.use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]
" + dat += "[use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]
" - dat += "The speaker switch is [src.shut_up ? "off" : "on"]. Toggle" + dat += "Treat Viral Infections: [treat_virus ? "Yes" : "No"]
" + dat += "The speaker switch is [shut_up ? "off" : "on"]. Toggle
" + dat += "Critical Patient Alerts: [declare_crit ? "Yes" : "No"]
" + dat += "Patrol Station: [auto_patrol ? "Yes" : "No"]
" + dat += "Stationary Mode: [stationary_mode ? "Yes" : "No"]
" - user << browse("Medibot v1.0 controls[dat]", "window=automed") - onclose(user, "automed") + var/datum/browser/popup = new(user, "automed", "Automatic Medical Unit v1.1") + popup.set_content(dat) + popup.open() return /obj/machinery/bot/medbot/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - src.add_fingerprint(usr) - if ((href_list["power"]) && (src.allowed(usr))) - if (src.on && !src.emagged) - turn_off() - else - turn_on() + ..() - else if((href_list["adj_threshold"]) && (!src.locked || issilicon(usr))) + if(href_list["adj_threshold"]) var/adjust_num = text2num(href_list["adj_threshold"]) - src.heal_threshold += adjust_num - if(src.heal_threshold < 5) - src.heal_threshold = 5 - if(src.heal_threshold > 75) - src.heal_threshold = 75 + heal_threshold += adjust_num + if(heal_threshold < 5) + heal_threshold = 5 + if(heal_threshold > 75) + heal_threshold = 75 - else if((href_list["adj_inject"]) && (!src.locked || issilicon(usr))) + else if(href_list["adj_inject"]) var/adjust_num = text2num(href_list["adj_inject"]) - src.injection_amount += adjust_num - if(src.injection_amount < 5) - src.injection_amount = 5 - if(src.injection_amount > 15) - src.injection_amount = 15 + injection_amount += adjust_num + if(injection_amount < 5) + injection_amount = 5 + if(injection_amount > 15) + injection_amount = 15 - else if((href_list["use_beaker"]) && (!src.locked || issilicon(usr))) - src.use_beaker = !src.use_beaker + else if(href_list["use_beaker"]) + use_beaker = !use_beaker - else if (href_list["eject"] && (!isnull(src.reagent_glass))) - if(!src.locked) - src.reagent_glass.loc = get_turf(src) - src.reagent_glass = null - else - usr << "You cannot eject the beaker because the panel is locked." + else if (href_list["eject"] && (!isnull(reagent_glass))) + reagent_glass.loc = get_turf(src) + reagent_glass = null - else if ((href_list["togglevoice"]) && (!src.locked || issilicon(usr))) - src.shut_up = !src.shut_up + else if (href_list["togglevoice"]) + shut_up = !shut_up - else if (href_list["operation"]) - if(!src.emagged) - src.emagged = 2 - src.hacked = 1 - usr << "You corrupt [src]'s reagent processor circuits." - else if(!src.hacked) - usr << "[src] seems damaged and does not respond to reprogramming!" - else - src.hacked = 0 - src.emagged = 0 - usr << "You reset [src]'s reagent circuits." - src.updateUsrDialog() + else if (href_list["critalerts"]) + declare_crit = !declare_crit + + else if (href_list["stationary"]) + stationary_mode = !stationary_mode + path = new() + updateicon() + + else if (href_list["virus"]) + treat_virus = !treat_virus + + updateUsrDialog() return /obj/machinery/bot/medbot/attackby(obj/item/weapon/W as obj, mob/user as mob) if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) - if (src.allowed(user) && !open && !emagged) - src.locked = !src.locked - user << "Controls are now [src.locked ? "locked." : "unlocked."]" - src.updateUsrDialog() + if (allowed(user) && !open && !emagged) + locked = !locked + user << "Controls are now [locked ? "locked." : "unlocked."]" + updateUsrDialog() else if(emagged) user << "ERROR" @@ -207,18 +224,18 @@ user << "Access denied." else if (istype(W, /obj/item/weapon/reagent_containers/glass)) - if(src.locked) + if(locked) user << "You cannot insert a beaker because the panel is locked." return - if(!isnull(src.reagent_glass)) + if(!isnull(reagent_glass)) user << "There is already a beaker loaded." return user.drop_item() W.loc = src - src.reagent_glass = W + reagent_glass = W user << "You insert [W]." - src.updateUsrDialog() + updateUsrDialog() return else @@ -229,106 +246,103 @@ /obj/machinery/bot/medbot/Emag(mob/user as mob) ..() - if(open && !locked) - if(user) user << "You short out [src]'s reagent synthesis circuits." + if(emagged == 2) + declare_crit = 0 + if(user) + user << "You short out [src]'s reagent synthesis circuits." spawn(0) audible_message("[src] buzzes oddly!") flick("medibot_spark", src) - src.patient = null - if(user) src.oldpatient = user - src.currently_healing = 0 - src.last_found = world.time - src.anchored = 0 - src.emagged = 2 - src.on = 1 - src.icon_state = "medibot[src.on]" + if(user) + oldpatient = user + +/obj/machinery/bot/medbot/process_scan(var/mob/living/carbon/human/H) + if (H.stat == 2) + return + + if ((H == oldpatient) && (world.time < last_found + 100)) + return + + if(assess_patient(H)) + last_found = world.time + if((last_newpatient_speak + 300) < world.time) //Don't spam these messages! + var/message = pick("Hey, [H.name]! Hold on, I'm coming.","Wait [H.name]! I want to help!","[H.name], you appear to be injured!") + speak(message) + last_newpatient_speak = world.time + return H + else + return /obj/machinery/bot/medbot/process() - set background = BACKGROUND_ENABLED - - if(!src.on) - src.stunned = 0 + if (!..()) return - if(src.stunned) - src.icon_state = "medibota" - src.stunned-- - - src.oldpatient = src.patient - src.patient = null - src.currently_healing = 0 - - if(src.stunned <= 0) - src.icon_state = "medibot[src.on]" - src.stunned = 0 + if(mode == BOT_HEALING) return - if(src.frustration > 8) - src.oldpatient = src.patient - src.patient = null - src.currently_healing = 0 - src.last_found = world.time - src.path = new() + if(stunned) + icon_state = "medibota" + stunned-- - if(!src.patient) - if(!src.shut_up && prob(1)) + oldpatient = patient + patient = null + mode = BOT_IDLE + + if(stunned <= 0) + updateicon() + stunned = 0 + return + + if(frustration > 8) + oldpatient = patient + patient = null + mode = BOT_IDLE + last_found = world.time + path = new() + + if(!patient) + if(!shut_up && prob(1)) var/message = pick("Radar, put a mask on!","There's always a catch, and it's the best there is.","I knew it, I should've been a plastic surgeon.","What kind of medbay is this? Everyone's dropping like dead flies.","Delicious!") - src.speak(message) + speak(message) + var/scan_range = (stationary_mode ? 1 : DEFAULT_SCAN_RANGE) //If in stationary mode, scan range is limited to adjacent patients. + patient = scan(/mob/living/carbon/human, oldpatient, scan_range) + oldpatient = patient - for (var/mob/living/carbon/C in view(7,src)) //Time to find a patient! - if ((C.stat == 2) || !istype(C, /mob/living/carbon/human)) - continue - - if ((C == src.oldpatient) && (world.time < src.last_found + 100)) - continue - - if(src.assess_patient(C)) - src.patient = C - src.oldpatient = C - src.last_found = world.time - if((src.last_newpatient_speak + 300) < world.time) //Don't spam these messages! - var/message = pick("Hey, [C.name]! Hold on, I'm coming.","Wait [C.name]! I want to help!","[C.name], you appear to be injured!") - src.speak(message) - src.last_newpatient_speak = world.time - break - else - continue - - - if(src.patient && (get_dist(src,src.patient) <= 1)) - if(!src.currently_healing) - src.currently_healing = 1 - src.frustration = 0 - src.medicate_patient(src.patient) + if(patient && (get_dist(src,patient) <= 1)) //Patient is next to us, begin treatment! + if(mode != BOT_HEALING) + mode = BOT_HEALING + updateicon() + frustration = 0 + medicate_patient(patient) return - else if(src.patient && (src.path.len) && (get_dist(src.patient,src.path[src.path.len]) > 2)) - src.path = new() - src.currently_healing = 0 - src.last_found = world.time + //Patient has moved away from us! + else if(patient && (path.len) && (get_dist(patient,path[path.len]) > 2)) + path = new() + mode = BOT_IDLE + last_found = world.time - if(src.patient && src.path.len == 0 && (get_dist(src,src.patient) > 1)) + if(!stationary_mode && patient && path.len == 0 && (get_dist(src,patient) > 1)) spawn(0) - src.path = AStar(src.loc, get_turf(src.patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 30,id=botcard) - if(!src.path) - src.path = list() - if(src.path.len == 0) - src.oldpatient = src.patient - src.patient = null - src.currently_healing = 0 - src.last_found = world.time + path = AStar(loc, get_turf(patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 30,id=botcard) + + if(path.len > 0 && patient) + if(!bot_move(patient)) + oldpatient = patient + patient = null + mode = BOT_IDLE + last_found = world.time return - if(src.path.len > 0 && src.patient) - step_to(src, src.path[1]) - src.path -= src.path[1] - spawn(3) - if(src.path.len) - step_to(src, src.path[1]) - src.path -= src.path[1] + if(path.len > 8 && patient) + frustration++ - if(src.path.len > 8 && src.patient) - src.frustration++ + if(auto_patrol && !stationary_mode && !patient) + if(mode == BOT_IDLE || mode == BOT_START_PATROL) + start_patrol() + + if(mode == BOT_PATROL) + bot_patrol() return @@ -340,127 +354,131 @@ if(C.suiciding) return 0 //Kevorkian school of robotic medical assistants. - if(src.emagged == 2) //Everyone needs our medicine. (Our medicine is toxins) + if(emagged == 2) //Everyone needs our medicine. (Our medicine is toxins) return 1 + if(declare_crit && C.health <= 0) //Critical condition! Call for help! + declare(C) + //If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS. - if((src.reagent_glass) && (src.use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15)))) - for(var/datum/reagent/R in src.reagent_glass.reagents.reagent_list) + if((reagent_glass) && (use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15)))) + for(var/datum/reagent/R in reagent_glass.reagents.reagent_list) if(!C.reagents.has_reagent(R.id)) return 1 //They're injured enough for it! - if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_brute))) + if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_brute))) return 1 //If they're already medicated don't bother! - if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(src.treatment_oxy))) + if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(treatment_oxy))) return 1 - if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_fire))) + if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_fire))) return 1 - if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_tox))) + if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_tox))) return 1 + if(treat_virus) + for(var/datum/disease/D in C.viruses) + if((D.hidden[SCANNER]) || (D.hidden[PANDEMIC])) //the medibot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines. + return 0 + if(D.severity == D.non_threat) // medibot doesn't try to heal truly harmless viruses + return 0 + if((D.stage > 1) || (D.spread_type == AIRBORNE)) // medibot can't detect a virus in its initial stage unless it spreads airborne. - for(var/datum/disease/D in C.viruses) - if((D.hidden[SCANNER]) || (D.hidden[PANDEMIC])) //the medibot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines. - return 0 - if(D.severity == D.non_threat) // medibot doesn't try to heal truly harmless viruses - return 0 - if((D.stage > 1) || (D.spread_type == AIRBORNE)) // medibot can't detect a virus in its initial stage unless it spreads airborne. - - if (!C.reagents.has_reagent(src.treatment_virus)) - return 1 //STOP DISEASE FOREVER + if (!C.reagents.has_reagent(treatment_virus)) + return 1 //STOP DISEASE FOREVER return 0 /obj/machinery/bot/medbot/proc/medicate_patient(mob/living/carbon/C as mob) - if(!src.on) + if(!on) return if(!istype(C)) - src.oldpatient = src.patient - src.patient = null - src.currently_healing = 0 - src.last_found = world.time + oldpatient = patient + patient = null + mode = BOT_IDLE + last_found = world.time return if(C.stat == 2) var/death_message = pick("No! NO!","Live, damnit! LIVE!","I...I've never lost a patient before. Not today, I mean.") - src.speak(death_message) - src.oldpatient = src.patient - src.patient = null - src.currently_healing = 0 - src.last_found = world.time + speak(death_message) + oldpatient = patient + patient = null + mode = BOT_IDLE + last_found = world.time return var/reagent_id = null - if(src.emagged == 2) //Emagged! Time to poison everybody. + if(emagged == 2) //Emagged! Time to poison everybody. reagent_id = "toxin" else - var/virus = 0 - for(var/datum/disease/D in C.viruses) - if((!D.hidden[SCANNER]) && (!D.hidden[PANDEMIC])) //detectable virus - if(D.severity != D.non_threat) //virus is harmful - if((D.stage > 1) || (D.spread_type == AIRBORNE)) - virus = 1 + if(treat_virus) + var/virus = 0 + for(var/datum/disease/D in C.viruses) + if((!D.hidden[SCANNER]) && (!D.hidden[PANDEMIC])) //detectable virus + if(D.severity != D.non_threat) //virus is harmful + if((D.stage > 1) || (D.spread_type == AIRBORNE)) + virus = 1 - if (!reagent_id && (virus)) - if(!C.reagents.has_reagent(src.treatment_virus)) - reagent_id = src.treatment_virus + if (!reagent_id && (virus)) + if(!C.reagents.has_reagent(treatment_virus)) + reagent_id = treatment_virus if (!reagent_id && (C.getBruteLoss() >= heal_threshold)) - if(!C.reagents.has_reagent(src.treatment_brute)) - reagent_id = src.treatment_brute + if(!C.reagents.has_reagent(treatment_brute)) + reagent_id = treatment_brute if (!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold))) - if(!C.reagents.has_reagent(src.treatment_oxy)) - reagent_id = src.treatment_oxy + if(!C.reagents.has_reagent(treatment_oxy)) + reagent_id = treatment_oxy if (!reagent_id && (C.getFireLoss() >= heal_threshold)) - if(!C.reagents.has_reagent(src.treatment_fire)) - reagent_id = src.treatment_fire + if(!C.reagents.has_reagent(treatment_fire)) + reagent_id = treatment_fire if (!reagent_id && (C.getToxLoss() >= heal_threshold)) - if(!C.reagents.has_reagent(src.treatment_tox)) - reagent_id = src.treatment_tox + if(!C.reagents.has_reagent(treatment_tox)) + reagent_id = treatment_tox //If the patient is injured but doesn't have our special reagent in them then we should give it to them first - if(reagent_id && src.use_beaker && src.reagent_glass && src.reagent_glass.reagents.total_volume) - for(var/datum/reagent/R in src.reagent_glass.reagents.reagent_list) + if(reagent_id && use_beaker && reagent_glass && reagent_glass.reagents.total_volume) + for(var/datum/reagent/R in reagent_glass.reagents.reagent_list) if(!C.reagents.has_reagent(R.id)) reagent_id = "internal_beaker" break if(!reagent_id) //If they don't need any of that they're probably cured! - src.oldpatient = src.patient - src.patient = null - src.currently_healing = 0 - src.last_found = world.time + oldpatient = patient + patient = null + mode = BOT_IDLE + last_found = world.time var/message = pick("All patched up!","An apple a day keeps me away.","Feel better soon!") - src.speak(message) + speak(message) + updateicon() return else - src.icon_state = "medibots" - C.visible_message("[src] is trying to inject [src.patient]!", \ - "[src] is trying to inject [src.patient]!") + C.visible_message("[src] is trying to inject [patient]!", \ + "[src] is trying to inject [patient]!") spawn(30) - if ((get_dist(src, src.patient) <= 1) && (src.on)) + if ((get_dist(src, patient) <= 1) && (on)) if(reagent_id == "internal_beaker") - if(src.use_beaker && src.reagent_glass && src.reagent_glass.reagents.total_volume) - src.reagent_glass.reagents.trans_to(src.patient,src.injection_amount) //Inject from beaker instead. - src.reagent_glass.reagents.reaction(src.patient, 2) + if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume) + reagent_glass.reagents.trans_to(patient,injection_amount) //Inject from beaker instead. + reagent_glass.reagents.reaction(patient, 2) else - src.patient.reagents.add_reagent(reagent_id,src.injection_amount) - C.visible_message("[src] injects [src.patient] with the syringe!", \ - "[src] injects [src.patient] with the syringe!") + patient.reagents.add_reagent(reagent_id,injection_amount) + C.visible_message("[src] injects [patient] with the syringe!", \ + "[src] injects [patient] with the syringe!") - src.icon_state = "medibot[src.on]" - src.currently_healing = 0 + mode = BOT_IDLE + updateicon() return reagent_id = null @@ -468,11 +486,11 @@ /obj/machinery/bot/medbot/bullet_act(var/obj/item/projectile/Proj) if(Proj.flag == "taser") - src.stunned = min(stunned+10,20) + stunned = min(stunned+10,20) ..() /obj/machinery/bot/medbot/explode() - src.on = 0 + on = 0 visible_message("[src] blows apart!") var/turf/Tsec = get_turf(src) @@ -482,9 +500,9 @@ new /obj/item/device/healthanalyzer(Tsec) - if(src.reagent_glass) - src.reagent_glass.loc = Tsec - src.reagent_glass = null + if(reagent_glass) + reagent_glass.loc = Tsec + reagent_glass = null if (prob(50)) new /obj/item/robot_parts/l_arm(Tsec) @@ -495,54 +513,14 @@ qdel(src) return -/obj/machinery/bot/medbot/Bump(M as mob|obj) //Leave no door unopened! - if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard))) - var/obj/machinery/door/D = M - if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard)) - D.open() - src.frustration = 0 - else if ((istype(M, /mob/living/)) && (!src.anchored)) - src.loc = M:loc - src.frustration = 0 - return - -/* terrible -/obj/machinery/bot/medbot/Bumped(atom/movable/M as mob|obj) - spawn(0) - if (M) - var/turf/T = get_turf(src) - M:loc = T -*/ - -/* - * Pathfinding procs, allow the medibot to path through doors it has access to. - */ - -//Pretty ugh -/* -/turf/proc/AdjacentTurfsAllowMedAccess() - var/L[] = new() - for(var/turf/t in oview(src,1)) - if(!t.density) - if(!LinkBlocked(src, t) && !TurfBlockedNonWindowNonDoor(t,get_access("Medical Doctor"))) - L.Add(t) - return L - - -//It isn't blocked if we can open it, man. -/proc/TurfBlockedNonWindowNonDoor(turf/loc, var/list/access) - for(var/obj/O in loc) - if(O.density && !istype(O, /obj/structure/window) && !istype(O, /obj/machinery/door)) - return 1 - - if (O.density && (istype(O, /obj/machinery/door)) && (access.len)) - var/obj/machinery/door/D = O - for(var/req in D.req_access) - if(!(req in access)) //doesn't have this access - return 1 - - return 0 -*/ +/obj/machinery/bot/medbot/proc/declare(var/crit_patient) + if(declare_cooldown) + return + var/area/location = get_area(src) + speak("Medical emergency! [crit_patient ? "[crit_patient]" : "A patient"] is in critical condition at [location]!",radio_frequency) + declare_cooldown = 1 + spawn(200) //Twenty seconds + declare_cooldown = 0 /* * Medbot Assembly -- Can be made out of all three medkits. @@ -555,7 +533,7 @@ return //Making a medibot! - if(src.contents.len >= 1) + if(contents.len >= 1) user << "You need to empty [src] out first." return @@ -577,33 +555,33 @@ /obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() if(istype(W, /obj/item/weapon/pen)) - var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN) + var/t = copytext(stripped_input(user, "Enter new robot name", name, created_name),1,MAX_NAME_LEN) if (!t) return - if (!in_range(src, usr) && src.loc != usr) + if (!in_range(src, usr) && loc != usr) return - src.created_name = t + created_name = t else switch(build_step) if(0) if(istype(W, /obj/item/device/healthanalyzer)) user.drop_item() qdel(W) - src.build_step++ + build_step++ user << "You add the health sensor to [src]." - src.name = "First aid/robot arm/health analyzer assembly" - src.overlays += image('icons/obj/aibots.dmi', "na_scanner") + name = "First aid/robot arm/health analyzer assembly" + overlays += image('icons/obj/aibots.dmi', "na_scanner") if(1) if(isprox(W)) user.drop_item() qdel(W) - src.build_step++ + build_step++ user << "You complete the Medibot! Beep boop." var/turf/T = get_turf(src) var/obj/machinery/bot/medbot/S = new /obj/machinery/bot/medbot(T) - S.skin = src.skin - S.name = src.created_name + S.skin = skin + S.name = created_name user.unEquip(src, 1) qdel(src) diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm index bad30b9b2e5..e796be551c6 100644 --- a/code/game/machinery/bots/mulebot.dm +++ b/code/game/machinery/bots/mulebot.dm @@ -19,34 +19,28 @@ var/global/mulebot_count = 0 fire_dam_coeff = 0.7 brute_dam_coeff = 0.5 var/atom/movable/load = null // the loaded crate (usually) - var/beacon_freq = 1400 - var/control_freq = 1447 + var/list/delivery_beacons = list() //List of beacons that serve as delivery locations. + beacon_freq = 1400 + control_freq = 1447 + bot_type = MULE_BOT + bot_filter = RADIO_MULEBOT suffix = "" var/turf/target // this is turf to navigate to (location of beacon) var/loaddir = 0 // this the direction to unload onto/load from - var/new_destination = "" // pending new destination (waiting for beacon response) - var/destination = "" // destination description var/home_destination = "" // tag of home beacon req_access = list(access_cargo) // added robotics access so assembly line drop-off works properly -veyveyr //I don't think so, Tim. You need to add it to the MULE's hidden robot ID card. -NEO - var/path[] = new() - var/mode = 0 //0 = idle/ready - //1 = loading/unloading - //2 = moving to deliver - //3 = returning to home - //4 = blocked - //5 = computing navigation - //6 = waiting for nav computation - //7 = no destination beacon found (or no route) + mode = BOT_IDLE - var/blockcount = 0 //number of times retried a blocked path + blockcount = 0 //number of times retried a blocked path var/reached_target = 1 //true if already reached the target - var/refresh = 1 // true to refresh dialogue - var/auto_return = 1 // true if auto return to home beacon after unload - var/auto_pickup = 1 // true if auto-pickup at beacon + var/refresh = 1 // true to refresh dialogue + var/auto_return = 1 // true if auto return to home beacon after unload + var/auto_pickup = 1 // true if auto-pickup at beacon + var/report_delivery = 1 // true if bot will announce an arrival to a location. var/obj/item/weapon/stock_parts/cell/cell var/datum/wires/mulebot/wires = null @@ -67,18 +61,16 @@ var/global/mulebot_count = 0 /obj/machinery/bot/mulebot/New() ..() wires = new(src) - botcard = new(src) var/datum/job/cargo_tech/J = new/datum/job/cargo_tech botcard.access = J.get_access() + prev_access = botcard.access // botcard.access += access_robotics //Why --Ikki cell = new(src) cell.charge = 2000 cell.maxcharge = 2000 spawn(5) // must wait for map loading to finish - if(radio_controller) - radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT) - radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS) + add_to_beacons(bot_filter) mulebot_count += 1 if(!suffix) @@ -100,8 +92,8 @@ var/global/mulebot_count = 0 locked = !locked user << "You [locked ? "lock" : "unlock"] the mulebot's controls!" flick("mulebot-emagged", src) - playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 0) - else if(istype(I, /obj/item/weapon/card/id)) + playsound(loc, 'sound/effects/sparks1.ogg', 100, 0) + else if(istype(I, /obj/item/weapon/card/id) || istype(I, /obj/item/device/pda)) if(toggle_lock(user)) user << "Controls [(locked ? "locked" : "unlocked")]." @@ -118,30 +110,30 @@ var/global/mulebot_count = 0 open = !open if(open) - src.visible_message("[user] opens the maintenance hatch of [src]", "You open [src]'s maintenance hatch.") + visible_message("[user] opens the maintenance hatch of [src]", "You open [src]'s maintenance hatch.") on = 0 icon_state="mulebot-hatch" else - src.visible_message("[user] closes the maintenance hatch of [src]", "You close [src]'s maintenance hatch.") + visible_message("[user] closes the maintenance hatch of [src]", "You close [src]'s maintenance hatch.") icon_state = "mulebot0" updateDialog() else if (istype(I, /obj/item/weapon/wrench)) - if (src.health < maxhealth) - src.health = min(maxhealth, src.health+25) + if (health < maxhealth) + health = min(maxhealth, health+25) user.visible_message( - "[user] repairs [src]!", + "[user] repairs [src]!", "You repair [src]!" ) else - user << "[src] does not need a repair!" + user << " [src] does not need a repair!" else if(istype(I, /obj/item/device/multitool) || istype(I, /obj/item/weapon/wirecutters)) if(open) attack_hand(usr) else if(load && ismob(load)) // chance to knock off rider if(prob(1+I.force * 2)) unload(0) - user.visible_message("[user] knocks [load] off [src] with \the [I]!", "You knock [load] off [src] with \the [I]!") + user.visible_message(" [user] knocks [load] off [src] with \the [I]!", " You knock [load] off [src] with \the [I]!") else user << "You hit [src] with \the [I] but to no effect." else @@ -164,7 +156,7 @@ var/global/mulebot_count = 0 if(prob(50) && !isnull(load)) unload(0) if(prob(25)) - src.visible_message("Something shorts out inside [src]!") + visible_message(" Something shorts out inside [src]!") wires.RandomCut() ..() @@ -182,29 +174,30 @@ var/global/mulebot_count = 0 /obj/machinery/bot/mulebot/interact(var/mob/user, var/ai=0) var/dat - dat += "

Multiple Utility Load Effector Mk. IV

" + dat += "

Multiple Utility Load Effector Mk. V

" dat += "ID: [suffix]
" dat += "Power: [on ? "On" : "Off"]
" if(!open) dat += "

Status

" + dat += "
" switch(mode) - if(0) - dat += "Ready" - if(1) - dat += "Loading/Unloading" - if(2) - dat += "Navigating to Delivery Location" - if(3) - dat += "Navigating to Home" - if(4) - dat += "Waiting for clear path" - if(5,6) - dat += "Calculating navigation path" - if(7) - dat += "Unable to reach destination" + if(BOT_IDLE) + dat += "Ready" + if(BOT_LOADING) + dat += "[mode_name[BOT_LOADING]]" + if(BOT_DELIVER) + dat += "[mode_name[BOT_DELIVER]]" + if(BOT_GO_HOME) + dat += "[mode_name[BOT_GO_HOME]]" + if(BOT_BLOCKED) + dat += "[mode_name[BOT_BLOCKED]]" + if(BOT_NAV,BOT_WAIT_FOR_NAV) + dat += "[mode_name[BOT_NAV]]" + if(BOT_NO_ROUTE) + dat += "[mode_name[BOT_NO_ROUTE]]" dat += "
" dat += "Current Load: [load ? load.name : "none"]
" @@ -225,6 +218,7 @@ var/global/mulebot_count = 0 dat += "Set Home
" dat += "Toggle Auto Return Home ([auto_return ? "On":"Off"])
" dat += "Toggle Auto Pickup Crate ([auto_pickup ? "On":"Off"])
" + dat += "Toggle Delivery Reporting ([report_delivery ? "On" : "Off"])
" if(load) dat += "Unload Now
" @@ -245,9 +239,9 @@ var/global/mulebot_count = 0 //user << browse("M.U.L.E. Mk. III [suffix ? "([suffix])" : ""][dat]", "window=mulebot;size=350x500") //onclose(user, "mulebot") - var/datum/browser/popup = new(user, "mulebot", "M.U.L.E. Mk. III [suffix ? "([suffix])" : ""]", 350, 500) + var/datum/browser/popup = new(user, "mulebot", "M.U.L.E. Mk. V [suffix ? "([suffix])" : ""]", 350, 500) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() return @@ -261,7 +255,7 @@ var/global/mulebot_count = 0 return if (usr.stat) return - if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon))) + if ((in_range(src, usr) && istype(loc, /turf)) || (istype(usr, /mob/living/silicon))) usr.set_machine(src) switch(href_list["op"]) @@ -269,7 +263,7 @@ var/global/mulebot_count = 0 toggle_lock(usr) if("power") - if (src.on) + if (on) turn_off() else if (cell && !open) if (!turn_on()) @@ -305,23 +299,23 @@ var/global/mulebot_count = 0 if("stop") - if(mode >=2) - mode = 0 + if(mode >= BOT_DELIVER) + bot_reset() updateDialog() if("go") - if(mode == 0) + if(mode == BOT_IDLE) start() updateDialog() if("home") - if(mode == 0 || mode == 2) + if(mode == BOT_IDLE || mode == BOT_DELIVER) start_home() updateDialog() if("destination") refresh=0 - var/new_dest = input("Enter new destination tag", "Mulebot [suffix ? "([suffix])" : ""]", destination) as text|null + var/new_dest = input("Select M.U.L.E. Destination", "Mulebot [suffix ? "([suffix])" : ""]", destination) as null|anything in delivery_beacons refresh=1 if(new_dest) set_destination(new_dest) @@ -357,12 +351,15 @@ var/global/mulebot_count = 0 if("autopick") auto_pickup = !auto_pickup + if("report") + report_delivery = !report_delivery + if("close") usr.unset_machine() usr << browse(null,"window=mulebot") updateDialog() - //src.updateUsrDialog() + //updateUsrDialog() else usr << browse(null, "window=mulebot") usr.unset_machine() @@ -375,7 +372,7 @@ var/global/mulebot_count = 0 return !open && cell && cell.charge > 0 && wires.HasPower() /obj/machinery/bot/mulebot/proc/toggle_lock(var/mob/user) - if(src.allowed(user)) + if(allowed(user)) locked = !locked updateDialog() return 1 @@ -403,8 +400,8 @@ var/global/mulebot_count = 0 // called to load a crate /obj/machinery/bot/mulebot/proc/load(var/atom/movable/C) if(wires.LoadCheck() && !istype(C,/obj/structure/closet/crate)) - src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.") - playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) return // if not emagged, only allow crates to be loaded //I'm sure someone will come along and ask why this is here... well people were dragging screen items onto the mule, and that was not cool. @@ -416,16 +413,16 @@ var/global/mulebot_count = 0 if(get_dist(C, src) > 1 || load || !on) return - mode = 1 + mode = BOT_LOADING // if a create, close before loading var/obj/structure/closet/crate/crate = C if(istype(crate)) crate.close() - C.loc = src.loc + C.loc = loc sleep(2) - if(C.loc != src.loc) //To prevent you from going onto more thano ne bot. + if(C.loc != loc) //To prevent you from going onto more thano ne bot. return C.loc = src load = C @@ -441,7 +438,7 @@ var/global/mulebot_count = 0 M.client.perspective = EYE_PERSPECTIVE M.client.eye = src - mode = 0 + mode = BOT_IDLE send_status() // called to unload the bot @@ -451,7 +448,7 @@ var/global/mulebot_count = 0 if(!load) return - mode = 1 + mode = BOT_LOADING overlays.Cut() if(ismob(load)) @@ -461,11 +458,11 @@ var/global/mulebot_count = 0 M.client.eye = src - load.loc = src.loc + load.loc = loc load.pixel_y -= 9 load.layer = initial(load.layer) if(dirn) - var/turf/T = src.loc + var/turf/T = loc var/turf/newT = get_step(T,dirn) if(load.CanPass(load,newT)) //Can't get off onto anything that wouldn't let you pass normally step(load, dirn) @@ -477,9 +474,9 @@ var/global/mulebot_count = 0 // with items dropping as mobs are loaded for(var/atom/movable/AM in src) - if(AM == cell || AM == botcard) continue + if(AM == cell || istype(AM , botcard) || AM == Radio) continue - AM.loc = src.loc + AM.loc = loc AM.layer = initial(AM.layer) AM.pixel_y = initial(AM.pixel_y) if(ismob(AM)) @@ -487,8 +484,17 @@ var/global/mulebot_count = 0 if(M.client) M.client.perspective = MOB_PERSPECTIVE M.client.eye = src - mode = 0 + mode = BOT_IDLE +/obj/machinery/bot/mulebot/call_bot() + ..() + var/area/dest_area + if (path && path.len) + target = ai_waypoint //Target is the end point of the path, the waypoint set by the AI. + dest_area = get_area(target) + destination = format_text(dest_area.name) + pathset = 1 //Indicates the AI's custom path is initialized. + start() /obj/machinery/bot/mulebot/process() if(!has_power()) @@ -520,13 +526,14 @@ var/global/mulebot_count = 0 /obj/machinery/bot/mulebot/proc/process_bot() //if(mode) world << "Mode: [mode]" + switch(mode) - if(0) // idle + if(BOT_IDLE) // idle icon_state = "mulebot0" return - if(1) // loading/unloading + if(BOT_LOADING) // loading/unloading return - if(2,3,4) // navigating to deliver,home, or blocked + if(BOT_DELIVER,BOT_GO_HOME,BOT_BLOCKED) // navigating to deliver,home, or blocked if(loc == target) // reached target at_target() @@ -569,14 +576,14 @@ var/global/mulebot_count = 0 path -= loc - if(mode==4) + if(mode == BOT_BLOCKED) spawn(1) send_status() if(destination == home_destination) - mode = 3 + mode = BOT_GO_HOME else - mode = 2 + mode = BOT_DELIVER else // failed to move @@ -585,73 +592,74 @@ var/global/mulebot_count = 0 blockcount++ - mode = 4 + mode = BOT_BLOCKED if(blockcount == 3) - src.visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.") - playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) + visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.") + playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0) if(blockcount > 10) // attempt 10 times before recomputing // find new path excluding blocked turf - src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.") - playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) spawn(2) calc_path(next) if(path.len > 0) - src.visible_message("[src] makes a delighted ping!", "You hear a ping.") - playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) - mode = 4 - mode =6 + visible_message("[src] makes a delighted ping!", "You hear a ping.") + playsound(loc, 'sound/machines/ping.ogg', 50, 0) + mode = BOT_BLOCKED + mode = BOT_WAIT_FOR_NAV return return else - src.visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.") - playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) + visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.") + playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0) //world << "Bad turf." - mode = 5 + mode = BOT_NAV return else //world << "No path." - mode = 5 + mode = BOT_NAV return - if(5) // calculate new path + if(BOT_NAV) // calculate new path //world << "Calc new path." - mode = 6 + mode = BOT_WAIT_FOR_NAV spawn(0) calc_path() if(path.len > 0) blockcount = 0 - mode = 4 - src.visible_message("[src] makes a delighted ping!", "You hear a ping.") - playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) + mode = BOT_BLOCKED + visible_message("[src] makes a delighted ping!", "You hear a ping.") + playsound(loc, 'sound/machines/ping.ogg', 50, 0) else - src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.") - playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) - mode = 7 + mode = BOT_NO_ROUTE //if(6) //world << "Pending path calc." //if(7) //world << "No dest / no route." + return // calculates a path to the current destination // given an optional turf to avoid -/obj/machinery/bot/mulebot/proc/calc_path(var/turf/avoid = null) - src.path = AStar(src.loc, src.target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 250, id=botcard, exclude=avoid) - if(!src.path) - src.path = list() +/obj/machinery/bot/mulebot/calc_path(var/turf/avoid = null) + path = AStar(loc, target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 250, id=botcard, exclude=avoid) + if(!path) + path = list() // sets the current destination // signals all beacons matching the delivery code // beacons will return a signal giving their locations -/obj/machinery/bot/mulebot/proc/set_destination(var/new_dest) +/obj/machinery/bot/mulebot/set_destination(var/new_dest) spawn(0) new_destination = new_dest post_signal(beacon_freq, "findbeacon", "delivery") @@ -660,9 +668,9 @@ var/global/mulebot_count = 0 // starts bot moving to current destination /obj/machinery/bot/mulebot/proc/start() if(destination == home_destination) - mode = 3 + mode = BOT_GO_HOME else - mode = 2 + mode = BOT_DELIVER icon_state = "mulebot[(wires.MobAvoid() != 0)]" // starts bot moving to home @@ -670,17 +678,27 @@ var/global/mulebot_count = 0 /obj/machinery/bot/mulebot/proc/start_home() spawn(0) set_destination(home_destination) - mode = 4 + mode = BOT_BLOCKED icon_state = "mulebot[(wires.MobAvoid() != 0)]" // called when bot reaches current target /obj/machinery/bot/mulebot/proc/at_target() if(!reached_target) - src.visible_message("[src] makes a chiming sound!", "You hear a chime.") - playsound(src.loc, 'sound/machines/chime.ogg', 50, 0) + radio_frequency = SUPP_FREQ //Supply channel + visible_message("[src] makes a chiming sound!", "You hear a chime.") + playsound(loc, 'sound/machines/chime.ogg', 50, 0) reached_target = 1 + if(pathset) //The AI called us here, so notify it of our arrival. + loaddir = dir //The MULE will attempt to load a crate in whatever direction the MULE is "facing". + if(calling_ai) + calling_ai << "\icon[src] [src] wirelessly plays a chiming sound!" + playsound(calling_ai, 'sound/machines/chime.ogg',40, 0) + calling_ai = null + radio_frequency = AIPRIV_FREQ //Report on AI Private instead if the AI is controlling us. + if(load) // if loaded, unload at target + speak("Destination [destination] reached. Unloading [load].",radio_frequency) unload(loaddir) else // not loaded @@ -695,14 +713,16 @@ var/global/mulebot_count = 0 AM = locate(/obj/structure/closet/crate) in get_step(loc,loaddir) if(AM) load(AM) + if(report_delivery) + speak("Now loading [load] at [get_area(src)].", radio_frequency) // whatever happened, check to see if we return home if(auto_return && destination != home_destination) // auto return set and not at home already start_home() - mode = 4 + mode = BOT_BLOCKED else - mode = 0 // otherwise go idle + bot_reset() // otherwise go idle send_status() // report status to anyone listening @@ -714,13 +734,12 @@ var/global/mulebot_count = 0 var/mob/M = obs if(ismob(M)) if(istype(M,/mob/living/silicon/robot)) - src.visible_message("[src] bumps into [M]!") + visible_message("[src] bumps into [M]!") else - src.visible_message("[src] knocks over [M]!") + visible_message("[src] knocks over [M]!") M.stop_pulling() M.Stun(8) M.Weaken(5) - M.lying = 1 ..() /obj/machinery/bot/mulebot/alter_health() @@ -730,8 +749,8 @@ var/global/mulebot_count = 0 // called from mob/living/carbon/human/Crossed() // when mulebot is in the same loc /obj/machinery/bot/mulebot/proc/RunOver(var/mob/living/carbon/human/H) - src.visible_message("[src] drives over [H]!") - playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) + visible_message("[src] drives over [H]!") + playsound(loc, 'sound/effects/splat.ogg', 50, 1) var/damage = rand(5,15) H.apply_damage(2*damage, BRUTE, "head") @@ -741,7 +760,7 @@ var/global/mulebot_count = 0 H.apply_damage(0.5*damage, BRUTE, "l_arm") H.apply_damage(0.5*damage, BRUTE, "r_arm") - var/obj/effect/decal/cleanable/blood/B = new(src.loc) + var/obj/effect/decal/cleanable/blood/B = new(loc) B.blood_DNA = list() B.blood_DNA[H.dna.unique_enzymes] = H.dna.blood_type @@ -779,7 +798,7 @@ var/global/mulebot_count = 0 // process control input switch(recv) if("stop") - mode = 0 + bot_reset() return if("go") @@ -815,6 +834,7 @@ var/global/mulebot_count = 0 // receive response from beacon recv = signal.data["beacon"] + if(wires.BeaconRX()) if(recv == new_destination) // if the recvd beacon location matches the set destination // the we will navigate there @@ -829,12 +849,18 @@ var/global/mulebot_count = 0 calc_path() updateDialog() + //Detects and stores current active delivery beacons. + if(signal.data["beacon"]) + if(!delivery_beacons) + delivery_beacons = new() + delivery_beacons[signal.data["beacon"] ] = signal.source + // send a radio signal with a single data key/value pair -/obj/machinery/bot/mulebot/proc/post_signal(var/freq, var/key, var/value) +/obj/machinery/bot/mulebot/post_signal(var/freq, var/key, var/value) post_signal_multiple(freq, list("[key]" = value) ) // send a radio signal with multiple data key/values -/obj/machinery/bot/mulebot/proc/post_signal_multiple(var/freq, var/list/keyval) +/obj/machinery/bot/mulebot/post_signal_multiple(var/freq, var/list/keyval) if(freq == beacon_freq && !(wires.BeaconRX())) return @@ -856,17 +882,17 @@ var/global/mulebot_count = 0 //world << "sent [key],[keyval[key]] on [freq]" if (signal.data["findbeacon"]) frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS) - else if (signal.data["type"] == "mulebot") + else if (signal.data["type"] == MULE_BOT) frequency.post_signal(src, signal, filter = RADIO_MULEBOT) else frequency.post_signal(src, signal) // signals bot status etc. to controller -/obj/machinery/bot/mulebot/proc/send_status() +/obj/machinery/bot/mulebot/send_status() var/list/kv = list( - "type" = "mulebot", + "type" = MULE_BOT, "name" = suffix, - "loca" = (loc ? loc.loc : "Unknown"), // somehow loc can be null and cause a runtime - Quarxink + "loca" = get_area(src), "mode" = mode, "powr" = (cell ? cell.percent() : 0), "dest" = destination, @@ -886,7 +912,7 @@ var/global/mulebot_count = 0 /obj/machinery/bot/mulebot/explode() - src.visible_message("[src] blows apart!") + visible_message("[src] blows apart!") var/turf/Tsec = get_turf(src) new /obj/item/device/assembly/prox_sensor(Tsec) @@ -902,6 +928,6 @@ var/global/mulebot_count = 0 s.set_up(3, 1, src) s.start() - new /obj/effect/decal/cleanable/oil(src.loc) + new /obj/effect/decal/cleanable/oil(loc) unload(0) qdel(src) diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index dc7a6800c8a..25c76ba6872 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -17,45 +17,23 @@ var/threatlevel = 0 var/target_lastloc //Loc of target when arrested. var/last_found //There's a delay - var/frustration = 0 // var/emagged = 0 //Emagged Secbots view everyone as a criminal - var/declare_arrests = 1 //When making an arrest, should it notify everyone wearing sechuds? + var/declare_arrests = 1 //When making an arrest, should it notify everyone on the security channel? var/idcheck = 0 //If true, arrest people with no IDs - var/weaponscheck = 0 //If true, arrest people for weapons if they don't have access + var/weaponscheck = 0 //If true, arrest people for weapons if they lack access var/check_records = 1 //Does it check security records? var/arrest_type = 0 //If true, don't handcuff - - var/mode = 0 -#define SECBOT_IDLE 0 // idle -#define SECBOT_HUNT 1 // found target, hunting -#define SECBOT_PREP_ARREST 2 // at target, preparing to arrest -#define SECBOT_ARREST 3 // arresting target -#define SECBOT_START_PATROL 4 // start patrol -#define SECBOT_PATROL 5 // patrolling -#define SECBOT_SUMMON 6 // summoned by PDA - - var/auto_patrol = 0 // set to make bot automatically patrol - - var/beacon_freq = 1445 // navigation beacon frequency - var/control_freq = 1447 // bot control frequency + radio_frequency = SEC_FREQ //Security channel + bot_type = SEC_BOT + bot_filter = RADIO_SECBOT //List of weapons that secbots will not arrest for var/safe_weapons = list(\ /obj/item/weapon/gun/energy/laser/bluetag,\ /obj/item/weapon/gun/energy/laser/redtag,\ - /obj/item/weapon/gun/energy/laser/practice) - - var/turf/patrol_target // this is turf to navigate to (location of beacon) - var/new_destination // pending new destination (waiting for beacon response) - var/destination // destination description tag - var/next_destination // the next destination in the patrol route - var/list/path = new // list of path turfs - - var/blockcount = 0 //number of times retried a blocked path - var/awaiting_beacon = 0 // count of pticks awaiting a beacon response - - var/nearest_beacon // the nearest beacon's tag - var/turf/nearest_beacon_loc // the nearest beacon's location + /obj/item/weapon/gun/energy/laser/practice,\ + /obj/item/weapon/melee/telebaton,\ + /obj/item/weapon/gun/energy/kinetic_accelerator) /obj/machinery/bot/secbot/beepsky @@ -68,7 +46,7 @@ /obj/machinery/bot/secbot/pingsky name = "Officer Pingsky" desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment." - declare_arrests = 0 + radio_frequency = AIPRIV_FREQ /obj/item/weapon/secbot_assembly name = "incomplete securitron assembly" @@ -83,30 +61,38 @@ /obj/machinery/bot/secbot/New() ..() - src.icon_state = "secbot[src.on]" + icon_state = "secbot[on]" spawn(3) - src.botcard = new /obj/item/weapon/card/id(src) - var/datum/job/detective/J = new /datum/job/detective - src.botcard.access = J.get_access() - if(radio_controller) - radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT) - radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS) + + var/datum/job/detective/J = new/datum/job/detective + botcard.access = J.get_access() + prev_access = botcard.access + add_to_beacons(bot_filter) /obj/machinery/bot/secbot/turn_on() ..() - src.icon_state = "secbot[src.on]" - src.updateUsrDialog() + icon_state = "secbot[on]" + updateUsrDialog() /obj/machinery/bot/secbot/turn_off() ..() - src.target = null - src.oldtarget_name = null - src.anchored = 0 - src.mode = SECBOT_IDLE + icon_state = "secbot[on]" + updateUsrDialog() + +/obj/machinery/bot/secbot/bot_reset() + ..() + target = null + oldtarget_name = null + anchored = 0 walk_to(src,0) - src.icon_state = "secbot[src.on]" - src.updateUsrDialog() + last_found = world.time + +/obj/machinery/bot/secbot/set_custom_texts() + + text_hack = "You overload [name]'s target identification system." + text_dehack = "You reboot [name] and restore the target identification." + text_dehack_fail = "[name] refuses to accept your authority!" /obj/machinery/bot/secbot/attack_hand(mob/user as mob) . = ..() @@ -119,147 +105,118 @@ var/dat dat += hack(user) dat += text({" +Securitron v1.6 controls

Status: []
-Behaviour controls are [src.locked ? "locked" : "unlocked"]
-Maintenance panel panel is [src.open ? "opened" : "closed"]
"}, +Behaviour controls are [locked ? "locked" : "unlocked"]
+Maintenance panel panel is [open ? "opened" : "closed"]"}, -"[src.on ? "On" : "Off"]" ) +"[on ? "On" : "Off"]" ) - if(!src.locked || issilicon(user)) + if(!locked || issilicon(user)) dat += text({"
Arrest Unidentifiable Persons: []
Arrest for Unauthorized Weapons: []
Arrest for Warrant: []
-
Operating Mode: []
Report Arrests[]
Auto Patrol: []"}, -"[src.idcheck ? "Yes" : "No"]", -"[src.weaponscheck ? "Yes" : "No"]", -"[src.check_records ? "Yes" : "No"]", -"[src.arrest_type ? "Detain" : "Arrest"]", -"[src.declare_arrests ? "Yes" : "No"]", +"[idcheck ? "Yes" : "No"]", +"[weaponscheck ? "Yes" : "No"]", +"[check_records ? "Yes" : "No"]", +"[arrest_type ? "Detain" : "Arrest"]", +"[declare_arrests ? "Yes" : "No"]", "[auto_patrol ? "On" : "Off"]" ) - var/datum/browser/popup = new(user, "autosec", "Securitron v1.5.1 controls") + var/datum/browser/popup = new(user, "autosec", "Automatic Security Unit v1.6") popup.set_content(dat) popup.open() return /obj/machinery/bot/secbot/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - if((href_list["power"]) && (src.allowed(usr))) - if (src.on && !src.emagged) - turn_off() - else - turn_on() - return + + ..() switch(href_list["operation"]) if("idcheck") - src.idcheck = !src.idcheck - src.updateUsrDialog() + idcheck = !idcheck + updateUsrDialog() if("weaponscheck") - src.weaponscheck = !src.weaponscheck - src.updateUsrDialog() + weaponscheck = !weaponscheck + updateUsrDialog() if("ignorerec") - src.check_records = !src.check_records - src.updateUsrDialog() + check_records = !check_records + updateUsrDialog() if("switchmode") - src.arrest_type = !src.arrest_type - src.updateUsrDialog() - if("patrol") - auto_patrol = !auto_patrol - mode = SECBOT_IDLE + arrest_type = !arrest_type updateUsrDialog() if("declarearrests") - src.declare_arrests = !src.declare_arrests - src.updateUsrDialog() - if("hack") - if(!src.emagged) - src.emagged = 2 - src.hacked = 1 - usr << "You overload [src]'s target identification system." - else if(!src.hacked) - usr << "[src] refuses to accept your authority!" - else - src.emagged = 0 - src.hacked = 0 - usr << "You reboot [src] and restore the target identification." - src.updateUsrDialog() + declare_arrests = !declare_arrests + updateUsrDialog() + /obj/machinery/bot/secbot/attackby(obj/item/weapon/W as obj, mob/user as mob) if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) - if(src.allowed(user) && !open && !emagged) - src.locked = !src.locked - user << "Controls are now [src.locked ? "locked." : "unlocked."]" + if(allowed(user) && !open && !emagged) + locked = !locked + user << "Controls are now [locked ? "locked." : "unlocked."]" else if(emagged) user << "ERROR" if(open) user << "Please close the access panel before locking it." else - user << "Access denied." + user << " Access denied." else ..() if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry. return - if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!src.target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. + if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. threatlevel = user.assess_threat(src) threatlevel += 6 if(threatlevel >= 4) - src.target = user - src.mode = SECBOT_HUNT + target = user + mode = BOT_HUNT /obj/machinery/bot/secbot/Emag(mob/user as mob) ..() - if(open && !locked) - if(user) user << "You short out [src]'s target assessment circuits." - spawn(0) - audible_message("[src] buzzes oddly!") - src.target = null - if(user) src.oldtarget_name = user.name - src.last_found = world.time - src.anchored = 0 - src.declare_arrests = 0 - src.emagged = 2 - src.on = 1 - src.icon_state = "secbot[src.on]" - mode = SECBOT_IDLE + + if(emagged == 2) + if(user) + user << " You short out [src]'s target assessment circuits." + oldtarget_name = user.name + audible_message("[src] buzzes oddly!") + declare_arrests = 0 + icon_state = "secbot[on]" /obj/machinery/bot/secbot/process() - set background = BACKGROUND_ENABLED - - if(!src.on) + if (!..()) return switch(mode) - if(SECBOT_IDLE) // idle + if(BOT_IDLE) // idle walk_to(src,0) look_for_perp() // see if any criminals are in range if(!mode && auto_patrol) // still idle, and set to patrol - mode = SECBOT_START_PATROL // switch to patrol mode + mode = BOT_START_PATROL // switch to patrol mode - if(SECBOT_HUNT) // hunting for perp + if(BOT_HUNT) // hunting for perp // if can't reach perp for long enough, go idle - if(src.frustration >= 8) + if(frustration >= 8) walk_to(src,0) back_to_idle() return if(target) // make sure target exists - if(src.Adjacent(target) && isturf(src.target.loc)) // if right next to perp - playsound(src.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) - src.icon_state = "secbot-c" + if(Adjacent(target) && isturf(target.loc)) // if right next to perp + playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) + icon_state = "secbot-c" spawn(2) - src.icon_state = "secbot[src.on]" - var/mob/living/carbon/M = src.target + icon_state = "secbot[on]" + var/mob/living/carbon/M = target if(istype(M, /mob/living/carbon/human)) if( M.stuttering < 5 && !(HULK in M.mutations) ) M.stuttering = 5 @@ -272,46 +229,46 @@ Auto Patrol: []"}, if(declare_arrests) var/area/location = get_area(src) - broadcast_hud_message("[src.name] is [arrest_type ? "detaining" : "arresting"] level [threatlevel] scumbag [target.name] in [location]", src) - target.visible_message("[src.target] has been stunned by [src]!",\ - "[src.target] has been stunned by [src]!") + speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag [target] in [location].", radio_frequency) + target.visible_message("[target] has been stunned by [src]!",\ + "[target] has been stunned by [src]!") - mode = SECBOT_PREP_ARREST - src.anchored = 1 - src.target_lastloc = M.loc + mode = BOT_PREP_ARREST + anchored = 1 + target_lastloc = M.loc return else // not next to perp - var/turf/olddist = get_dist(src, src.target) - walk_to(src, src.target,1,4) - if((get_dist(src, src.target)) >= (olddist)) - src.frustration++ + var/turf/olddist = get_dist(src, target) + walk_to(src, target,1,4) + if((get_dist(src, target)) >= (olddist)) + frustration++ else - src.frustration = 0 + frustration = 0 else back_to_idle() - if(SECBOT_PREP_ARREST) // preparing to arrest target + if(BOT_PREP_ARREST) // preparing to arrest target // see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again. - if( !src.Adjacent(target) || !isturf(src.target.loc) || src.target.weakened < 2 ) + if( !Adjacent(target) || !isturf(target.loc) || target.weakened < 2 ) back_to_hunt() return if(iscarbon(target) && target.canBeHandcuffed()) - if(!src.arrest_type) - if(!src.target.handcuffed) //he's not cuffed? Try to cuff him! - mode = SECBOT_ARREST - playsound(src.loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2) - target.visible_message("[src] is trying to put zipties on [src.target]!",\ - "[src] is trying to put zipties on [src.target]!") + if(!arrest_type) + if(!target.handcuffed) //he's not cuffed? Try to cuff him! + mode = BOT_ARREST + playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2) + target.visible_message("[src] is trying to put zipties on [target]!",\ + "[src] is trying to put zipties on [target]!") spawn(60) - if( !src.Adjacent(target) || !isturf(src.target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing. + if( !Adjacent(target) || !isturf(target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing. return - if(!src.target.handcuffed) + if(!target.handcuffed) target.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(target) target.update_inv_handcuffed(0) //update the handcuffs overlay - playsound(src.loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0) + playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0) back_to_idle() else back_to_idle() @@ -320,362 +277,95 @@ Auto Patrol: []"}, back_to_idle() return - if(SECBOT_ARREST) - + if(BOT_ARREST) if (!target) - src.anchored = 0 - mode = SECBOT_IDLE - src.last_found = world.time + anchored = 0 + mode = BOT_IDLE + last_found = world.time frustration = 0 return - if(src.target.handcuffed) //no target or target cuffed? back to idle. + if(target.handcuffed) //no target or target cuffed? back to idle. back_to_idle() return - if( !src.Adjacent(target) || !isturf(src.target.loc) || (src.target.loc != src.target_lastloc && src.target.weakened < 2) ) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again. + if( !Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.weakened < 2) ) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again. back_to_hunt() return + else //Try arresting again if the target escapes. + mode = BOT_PREP_ARREST + anchored = 0 + + if(BOT_START_PATROL) + look_for_perp() + start_patrol() + + if(BOT_PATROL) + look_for_perp() + bot_patrol() - if(SECBOT_START_PATROL) // start a patrol - - if(path.len > 0 && patrol_target) // have a valid path, so just resume - mode = SECBOT_PATROL - return - - else if(patrol_target) // has patrol target already - spawn(0) - calc_path() // so just find a route to it - if(path.len == 0) - patrol_target = 0 - return - mode = SECBOT_PATROL - - - else // no patrol target, so need a new one - find_patrol_target() - speak("Engaging patrol mode.") - - - if(SECBOT_PATROL) // patrol mode - - patrol_step() - spawn(5) - if(mode == SECBOT_PATROL) - patrol_step() - - if(SECBOT_SUMMON) // summoned to PDA - patrol_step() - spawn(4) - if(mode == SECBOT_SUMMON) - patrol_step() - sleep(4) - patrol_step() return /obj/machinery/bot/secbot/proc/back_to_idle() - src.anchored = 0 - mode = SECBOT_IDLE - src.target = null - src.last_found = world.time + anchored = 0 + mode = BOT_IDLE + target = null + last_found = world.time frustration = 0 spawn(0) process() //ensure bot quickly responds /obj/machinery/bot/secbot/proc/back_to_hunt() - src.anchored = 0 - src.frustration = 0 - mode = SECBOT_HUNT + anchored = 0 + frustration = 0 + mode = BOT_HUNT spawn(0) process() //ensure bot quickly responds - -// perform a single patrol step -/obj/machinery/bot/secbot/proc/patrol_step() - - if(loc == patrol_target) // reached target - at_patrol_target() - return - - else if(path.len > 0 && patrol_target) // valid path - - var/turf/next = path[1] - if(next == loc) - path -= next - return - - - if(istype( next, /turf/simulated)) - - var/moved = step_towards(src, next) // attempt to move - if(moved) // successful move - blockcount = 0 - path -= loc - - look_for_perp() - else // failed to move - - blockcount++ - - if(blockcount > 5) // attempt 5 times before recomputing - // find new path excluding blocked turf - - spawn(2) - calc_path(next) - if(path.len == 0) - find_patrol_target() - else - blockcount = 0 - - return - - return - - else // not a valid turf - mode = SECBOT_IDLE - return - - else // no path, so calculate new one - mode = SECBOT_START_PATROL - - -// finds a new patrol target -/obj/machinery/bot/secbot/proc/find_patrol_target() - send_status() - if(awaiting_beacon) // awaiting beacon response - awaiting_beacon++ - if(awaiting_beacon > 5) // wait 5 secs for beacon response - find_nearest_beacon() // then go to nearest instead - return - - if(next_destination) - set_destination(next_destination) - else - find_nearest_beacon() - return - - -// finds the nearest beacon to self -// signals all beacons matching the patrol code -/obj/machinery/bot/secbot/proc/find_nearest_beacon() - nearest_beacon = null - new_destination = "__nearest__" - post_signal(beacon_freq, "findbeacon", "patrol") - awaiting_beacon = 1 - spawn(10) - awaiting_beacon = 0 - if(nearest_beacon) - set_destination(nearest_beacon) - else - auto_patrol = 0 - mode = SECBOT_IDLE - speak("Disengaging patrol mode.") - send_status() - - -/obj/machinery/bot/secbot/proc/at_patrol_target() - if(auto_patrol) - find_patrol_target() - else - mode = SECBOT_IDLE - return - - -// sets the current destination -// signals all beacons matching the patrol code -// beacons will return a signal giving their locations -/obj/machinery/bot/secbot/proc/set_destination(var/new_dest) - new_destination = new_dest - post_signal(beacon_freq, "findbeacon", "patrol") - awaiting_beacon = 1 - - -// receive a radio signal -// used for beacon reception - -/obj/machinery/bot/secbot/receive_signal(datum/signal/signal) - //log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/bot/secbot/receive_signal([signal.debug_print()])") - if(!on) - return - - /* - world << "rec signal: [signal.source]" - for(var/x in signal.data) - world << "* [x] = [signal.data[x]]" - */ - - var/recv = signal.data["command"] - // process all-bot input - if(recv=="bot_status") - send_status() - - // check to see if we are the commanded bot - if(signal.data["active"] == src) - // process control input - switch(recv) - if("stop") - mode = SECBOT_IDLE - auto_patrol = 0 - return - - if("go") - mode = SECBOT_IDLE - auto_patrol = 1 - return - - if("summon") - patrol_target = signal.data["target"] - next_destination = destination - destination = null - awaiting_beacon = 0 - mode = SECBOT_SUMMON - calc_path() - speak("Responding.") - - return - - - - // receive response from beacon - recv = signal.data["beacon"] - var/valid = signal.data["patrol"] - if(!recv || !valid) - return - - if(recv == new_destination) // if the recvd beacon location matches the set destination - // the we will navigate there - destination = new_destination - patrol_target = signal.source.loc - next_destination = signal.data["next_patrol"] - awaiting_beacon = 0 - - // if looking for nearest beacon - else if(new_destination == "__nearest__") - var/dist = get_dist(src,signal.source.loc) - if(nearest_beacon) - - // note we ignore the beacon we are located at - if(dist>1 && dist 1) - nearest_beacon = recv - nearest_beacon_loc = signal.source.loc - return - - -// send a radio signal with a single data key/value pair -/obj/machinery/bot/secbot/proc/post_signal(var/freq, var/key, var/value) - post_signal_multiple(freq, list("[key]" = value) ) - -// send a radio signal with multiple data key/values -/obj/machinery/bot/secbot/proc/post_signal_multiple(var/freq, var/list/keyval) - - var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq) - - if(!frequency) return - - var/datum/signal/signal = new() - signal.source = src - signal.transmission_method = 1 - //for(var/key in keyval) - // signal.data[key] = keyval[key] - signal.data = keyval - //world << "sent [key],[keyval[key]] on [freq]" - if(signal.data["findbeacon"]) - frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS) - else if(signal.data["type"] == "secbot") - frequency.post_signal(src, signal, filter = RADIO_SECBOT) - else - frequency.post_signal(src, signal) - -// signals bot status etc. to controller -/obj/machinery/bot/secbot/proc/send_status() - var/list/kv = list( - "type" = "secbot", - "name" = name, - "loca" = loc.loc, // area - "mode" = mode - ) - post_signal_multiple(control_freq, kv) - - - -// calculates a path to the current destination -// given an optional turf to avoid -/obj/machinery/bot/secbot/proc/calc_path(var/turf/avoid = null) - src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 120, id=botcard, exclude=avoid) - if(!src.path) - src.path = list() - - // look for a criminal in view of the bot /obj/machinery/bot/secbot/proc/look_for_perp() - src.anchored = 0 + anchored = 0 for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal if((C.stat) || (C.handcuffed)) continue - if((C.name == src.oldtarget_name) && (world.time < src.last_found + 100)) + if((C.name == oldtarget_name) && (world.time < last_found + 100)) continue - src.threatlevel = C.assess_threat(src) + threatlevel = C.assess_threat(src) - if(!src.threatlevel) + if(!threatlevel) continue - else if(src.threatlevel >= 4) - src.target = C - src.oldtarget_name = C.name - src.speak("Level [src.threatlevel] infraction alert!") - playsound(src.loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0) - src.visible_message("[src] points at [C.name]!") - mode = SECBOT_HUNT + else if(threatlevel >= 4) + target = C + oldtarget_name = C.name + speak("Level [threatlevel] infraction alert!") + playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0) + visible_message("[src] points at [C.name]!") + mode = BOT_HUNT spawn(0) process() // ensure bot quickly responds to a perp break else continue - /obj/machinery/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item) if(istype(slot_item, /obj/item/weapon/gun) || istype(slot_item, /obj/item/weapon/melee)) if(!(slot_item.type in safe_weapons)) return 1 return 0 -/obj/machinery/bot/secbot/Bump(M as mob|obj) //Leave no door unopened! - if((istype(M, /obj/machinery/door)) && (!isnull(src.botcard))) - var/obj/machinery/door/D = M - if(!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard)) - D.open() - src.frustration = 0 - else if((istype(M, /mob/living/)) && (!src.anchored)) - src.loc = M:loc - src.frustration = 0 - return - -/* terrible -/obj/machinery/bot/secbot/Bumped(atom/movable/M as mob|obj) - spawn(0) - if(M) - var/turf/T = get_turf(src) - M:loc = T -*/ - /obj/machinery/bot/secbot/explode() walk_to(src,0) - src.visible_message("[src] blows apart!") + visible_message("[src] blows apart!") var/turf/Tsec = get_turf(src) var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec) Sa.build_step = 1 Sa.overlays += "hs_hole" - Sa.created_name = src.name + Sa.created_name = name new /obj/item/device/assembly/prox_sensor(Tsec) new /obj/item/weapon/melee/baton(Tsec) @@ -686,14 +376,14 @@ Auto Patrol: []"}, s.set_up(3, 1, src) s.start() - new /obj/effect/decal/cleanable/oil(src.loc) + new /obj/effect/decal/cleanable/oil(loc) qdel(src) /obj/machinery/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob) ..() if(!isalien(target)) - src.target = user - src.mode = SECBOT_HUNT + target = user + mode = BOT_HUNT //Secbot Construction @@ -703,7 +393,7 @@ Auto Patrol: []"}, ..() return - if(src.type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets. + if(type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets. return if(S.secured) diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index d1892e8f628..0d8bc250c32 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -459,31 +459,18 @@ targets += C //if the perp has passed all previous tests, congrats, it is now a "shoot-me!" nominee - if(targets.len > 0) //if there are targets to shoot - - var/atom/t = pick(targets) //pick a perp from the list of targets. Targets go first because they are the most important - - if(istype(t, /mob/living)) //if a mob - var/mob/living/M = t //simple typecasting - if(M.stat != DEAD) //if the target is not dead - spawn() - popUp() //pop the turret up if it's not already up. - dir = get_dir(src, M) //even if you can't shoot, follow the target - spawn() - shootAt(M) //shoot the target, finally - - else - if(secondarytargets.len > 0) //if there are no primary targets, go for secondary targets - var/mob/t = pick(secondarytargets) - if(istype(t, /mob/living)) - if(t.stat != DEAD) - spawn() - popUp() - dir=get_dir(src, t) - shootAt(t) - else + if(!tryToShootAt(targets)) + if(!tryToShootAt(secondarytargets)) // if no valid targets, go for secondary targets spawn() - popDown() + popDown() // no valid targets, close the cover + + +/obj/machinery/porta_turret/proc/tryToShootAt(var/list/mob/living/targets) + while(targets.len > 0) + var/mob/living/M = pick(targets) + targets -= M + if(target(M)) + return 1 /obj/machinery/porta_turret/proc/popUp() //pops the turret up @@ -573,15 +560,19 @@ return threatcount -/obj/machinery/porta_turret/proc/shootAt(atom/movable/target) //shoots at a target +/obj/machinery/porta_turret/proc/target(var/mob/living/target) if(disabled) return + if(target && (target.stat != DEAD) && (!(target.lying) || emagged)) + spawn() + popUp() //pop the turret up if it's not already up. + dir = get_dir(src, target) //even if you can't shoot, follow the target + spawn() + shootAt(target) + return 1 + return - if(lasercolor && istype(target,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = target - if(H.lying) - return - +/obj/machinery/porta_turret/proc/shootAt(var/mob/living/target) if(!emagged) //if it hasn't been emagged, it has to obey a cooldown rate if(last_fired || !raised) //prevents rapid-fire shooting, unless it's been emagged return diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 70058da3def..a5342f470df 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -773,8 +773,7 @@ /obj/item/clothing/head/helmet/gladiator = 1,/obj/item/clothing/under/gimmick/rank/captain/suit = 1,/obj/item/clothing/head/flatcap = 1, /obj/item/clothing/suit/labcoat/mad = 1,/obj/item/clothing/glasses/gglasses = 1,/obj/item/clothing/shoes/jackboots = 1, /obj/item/clothing/under/schoolgirl = 1,/obj/item/clothing/head/kitty = 1,/obj/item/clothing/under/blackskirt = 1,/obj/item/clothing/head/beret = 1, - /obj/item/clothing/tie/waistcoat = 1,/obj/item/clothing/under/suit_jacket = 1,/obj/item/clothing/head/that =1,/obj/item/clothing/head/cueball = 1, - /obj/item/clothing/under/scratch = 1,/obj/item/clothing/under/kilt = 1,/obj/item/clothing/head/beret = 1,/obj/item/clothing/tie/waistcoat = 1, + /obj/item/clothing/tie/waistcoat = 1,/obj/item/clothing/under/suit_jacket = 1,/obj/item/clothing/head/that =1,/obj/item/clothing/under/kilt = 1,/obj/item/clothing/head/beret = 1,/obj/item/clothing/tie/waistcoat = 1, /obj/item/clothing/glasses/monocle =1,/obj/item/clothing/head/bowler = 1,/obj/item/weapon/cane = 1,/obj/item/clothing/under/sl_suit = 1, /obj/item/clothing/mask/fakemoustache = 1,/obj/item/clothing/suit/bio_suit/plaguedoctorsuit = 1,/obj/item/clothing/head/plaguedoctorhat = 1, /obj/item/clothing/under/owl = 1,/obj/item/clothing/mask/gas/owl_mask = 1,/obj/item/clothing/suit/apron = 1,/obj/item/clothing/under/waiter = 1, diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm index a0010e1a893..52818f4c72a 100644 --- a/code/game/mecha/combat/marauder.dm +++ b/code/game/mecha/combat/marauder.dm @@ -94,50 +94,21 @@ return /obj/mecha/combat/marauder/relaymove(mob/user,direction) - if(user != src.occupant) //While not "realistic", this piece is player friendly. - user.loc = get_turf(src) - user << "You climb out from [src]" - return 0 - if(!can_move) - return 0 if(zoom) if(world.time - last_message > 20) src.occupant_message("Unable to move while in zoom mode.") last_message = world.time return 0 - if(connected_port) - if(world.time - last_message > 20) - src.occupant_message("Unable to move while connected to the air system port") - last_message = world.time - return 0 - if(!thrusters && pr_inertial_movement && src.pr_inertial_movement.active()) - return 0 - if(state || !has_charge(step_energy_drain)) - return 0 - var/tmp_step_in = step_in - var/tmp_step_energy_drain = step_energy_drain - var/move_result = 0 - if(internal_damage&MECHA_INT_CONTROL_LOST) - move_result = mechsteprand() - else if(src.dir!=direction) - move_result = mechturn(direction) - else - move_result = mechstep(direction) - if(move_result) - if(istype(src.loc, /turf/space)) - if(!src.check_for_support() && pr_inertial_movement) - src.pr_inertial_movement.start(list(src,direction)) - if(thrusters) - src.pr_inertial_movement.set_process_args(list(src,direction)) - tmp_step_energy_drain = step_energy_drain*2 + return ..() - can_move = 0 - spawn(tmp_step_in) can_move = 1 - use_power(tmp_step_energy_drain) + +/obj/mecha/combat/marauder/Process_Spacemove(var/movement_dir = 0) + if(..()) + return 1 + if(thrusters && movement_dir && use_power(step_energy_drain)) return 1 return 0 - /obj/mecha/combat/marauder/verb/toggle_thrusters() set category = "Exosuit Interface" set name = "Toggle thrusters" diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 48222dd1db1..5e844cdcdf7 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -739,17 +739,19 @@ return 0 var/result = 0 var/obj/item/stack/sheet/res = new type(src) - var/total_amount = round(resources[mat_string]/MINERAL_MATERIAL_AMOUNT) - res.amount = min(total_amount,res.max_amount) - if(res.amount>0) + if(amount>0 && amount<=50) + var/total_amount = round(resources[mat_string]/MINERAL_MATERIAL_AMOUNT) + res.amount = min(amount,total_amount) resources[mat_string] -= res.amount*MINERAL_MATERIAL_AMOUNT res.Move(src.loc) result = res.amount else + result = 0 qdel(res) return result + /obj/machinery/mecha_part_fabricator/attackby(obj/W as obj, mob/user as mob) if(default_deconstruction_screwdriver(user, "fab-o", "fab-idle", W)) return diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 338ed1bae87..acbe4455335 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -57,7 +57,6 @@ var/list/internals_req_access = list(access_engine,access_robotics)//required access level to open cell compartment var/datum/global_iterator/pr_int_temp_processor //normalizes internal air mixture temperature - var/datum/global_iterator/pr_inertial_movement //controls intertial movement in spesss var/datum/global_iterator/pr_give_air //moves air from tank to cabin var/datum/global_iterator/pr_internal_damage //processes internal damage @@ -130,12 +129,10 @@ internal_tank = null qdel(pr_int_temp_processor) - qdel(pr_inertial_movement) qdel(pr_give_air) qdel(pr_internal_damage) qdel(spark_system) pr_int_temp_processor = null - pr_inertial_movement = null pr_give_air = null pr_internal_damage = null spark_system = null @@ -183,7 +180,6 @@ /obj/mecha/proc/add_iterators() pr_int_temp_processor = new /datum/global_iterator/mecha_preserve_temp(list(src)) - pr_inertial_movement = new /datum/global_iterator/mecha_intertial_movement(null,0) pr_give_air = new /datum/global_iterator/mecha_tank_give_air(list(src)) pr_internal_damage = new /datum/global_iterator/mecha_internal_damage(list(src),0) @@ -206,13 +202,6 @@ return 1 - -/obj/mecha/proc/check_for_support() - if(locate(/obj/structure/grille, orange(1, src)) || locate(/obj/structure/lattice, orange(1, src)) || locate(/turf/simulated, orange(1, src)) || locate(/turf/unsimulated, orange(1, src))) - return 1 - else - return 0 - /obj/mecha/examine(mob/user) ..() var/integrity = health/initial(health)*100 @@ -304,11 +293,15 @@ //////// Movement procs //////// ////////////////////////////////// -/obj/mecha/Move() +/obj/mecha/Move(atom/newloc, direct) . = ..() if(.) events.fireEvent("onMove",get_turf(src)) - return + +/obj/mecha/Process_Spacemove(var/movement_dir = 0) + if(occupant) + return occupant.Process_Spacemove(movement_dir) //We'll just say you used the clamp to grab the wall + return ..() /obj/mecha/relaymove(mob/user,direction) if(user != src.occupant) //While not "realistic", this piece is player friendly. @@ -331,7 +324,7 @@ /obj/mecha/proc/dyndomove(direction) if(!can_move) return 0 - if(pr_inertial_movement && src.pr_inertial_movement.active()) + if(!Process_Spacemove(direction)) return 0 if(!has_charge(step_energy_drain)) return 0 @@ -341,14 +334,9 @@ else if(src.dir!=direction) move_result = mechturn(direction) else - move_result = mechstep(direction) + move_result = mechstep(direction) if(move_result) can_move = 0 - use_power(step_energy_drain) - if(istype(src.loc, /turf/space)) - if(!src.check_for_support() && pr_inertial_movement) - src.pr_inertial_movement.start(list(src,direction)) - src.log_message("Movement control lost. Inertial movement started.") if(do_after(step_in)) can_move = 1 return 1 @@ -1714,16 +1702,6 @@ var/year_integer = text2num(year) // = 2013??? return stop() return -/datum/global_iterator/mecha_intertial_movement //inertial movement in space - delay = 7 - - process(var/obj/mecha/mecha as obj,direction) - if(direction) - if(!step(mecha, direction)||mecha.check_for_support()) - src.stop() - else - src.stop() - return /datum/global_iterator/mecha_internal_damage // processing internal damage diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm index 2919abd0090..c8cb4754943 100644 --- a/code/game/objects/effects/decals/misc.dm +++ b/code/game/objects/effects/decals/misc.dm @@ -6,11 +6,6 @@ anchored = 1 mouse_opacity = 0 -/obj/effect/decal/point/point() - set src in oview() - set hidden = 1 - return - // Used for spray that you spray at walls, tables, hydrovats etc /obj/effect/decal/spraystill density = 0 diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index 92deb65c46a..34979a6dae0 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -684,9 +684,9 @@ steam.start() -- spawns the effect /datum/effect/effect/system/ion_trail_follow/set_up(atom/atom) attach(atom) - oldposition = get_turf(atom) -/datum/effect/effect/system/ion_trail_follow/start() + +/datum/effect/effect/system/ion_trail_follow/start() //Whoever is responsible for this abomination of code should become an hero if(!src.on) src.on = 1 src.processing = 1 @@ -696,26 +696,22 @@ steam.start() -- spawns the effect if(T != src.oldposition) if(!has_gravity(T)) var/obj/effect/effect/ion_trails/I = new /obj/effect/effect/ion_trails(src.oldposition) - src.oldposition = T I.dir = src.holder.dir flick("ion_fade", I) I.icon_state = "blank" spawn( 20 ) if(I) I.delete() - spawn(2) - if(src.on) - src.processing = 1 - src.start() - else - spawn(2) - if(src.on) - src.processing = 1 - src.start() + src.oldposition = T + spawn(2) + if(src.on) + src.processing = 1 + src.start() /datum/effect/effect/system/ion_trail_follow/proc/stop() src.processing = 0 src.on = 0 + oldposition = null diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 94915cfa2cc..ff65e9a4ecd 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -141,14 +141,6 @@ new /obj/item/clothing/head/that(src.loc) qdel(src) -/obj/effect/landmark/costume/scratch/New() - new /obj/item/clothing/gloves/white(src.loc) - new /obj/item/clothing/shoes/sneakers/white(src.loc) - new /obj/item/clothing/under/scratch(src.loc) - if (prob(30)) - new /obj/item/clothing/head/cueball(src.loc) - qdel(src) - /obj/effect/landmark/costume/highlander/New() new /obj/item/clothing/under/kilt(src.loc) new /obj/item/clothing/head/beret(src.loc) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 0e652086ee9..e9f9eedb451 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -302,12 +302,18 @@ var/global/list/obj/item/device/pda/PDAs = list() dat += "

Engineering Functions

" dat += "" if (cartridge.access_medical) dat += "

Medical Functions

" dat += "" + else dat += "" if (cartridge.access_security) dat += "

Security Functions

" @@ -330,6 +336,8 @@ var/global/list/obj/item/device/pda/PDAs = list() if (cartridge) if (cartridge.access_janitor) dat += "
  • Custodial Locator
  • " + if(istype(cartridge.radio, /obj/item/radio/integrated/cleanbot)) + dat += "
  • Cleanbot Access
  • " if (istype(cartridge.radio, /obj/item/radio/integrated/signal)) dat += "
  • Signaler System
  • " if (cartridge.access_reagent_scanner) @@ -473,9 +481,9 @@ var/global/list/obj/item/device/pda/PDAs = list() mode = 0 else mode = round(mode/10) - if(mode==4)//Fix for cartridges. Redirects to hub. + if(mode==4 || mode == 5)//Fix for cartridges. Redirects to hub. mode = 0 - else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu. + else if(mode >= 40 && mode <= 59)//Fix for cartridges. Redirects to refresh the menu. cartridge.mode = mode cartridge.unlock() if ("Authenticate")//Checks for ID @@ -1126,4 +1134,4 @@ var/global/list/obj/item/device/pda/PDAs = list() for(var/obj/item/device/pda/P in PDAs) if(!P.owner || P.toff || P.hidden) continue . += P - return . + return . diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm index 79ca2f0b61b..e42c3cf453a 100644 --- a/code/game/objects/items/devices/PDA/cart.dm +++ b/code/game/objects/items/devices/PDA/cart.dm @@ -38,21 +38,37 @@ icon_state = "cart-e" access_engine = 1 + /obj/item/weapon/cartridge/engineering/New() + ..() + radio = new /obj/item/radio/integrated/floorbot(src) + /obj/item/weapon/cartridge/atmos name = "\improper BreatheDeep cartridge" icon_state = "cart-a" access_atmos = 1 + /obj/item/weapon/cartridge/atmos/New() + ..() + radio = new /obj/item/radio/integrated/floorbot(src) + /obj/item/weapon/cartridge/medical name = "\improper Med-U cartridge" icon_state = "cart-m" access_medical = 1 + /obj/item/weapon/cartridge/medical/New() + ..() + radio = new /obj/item/radio/integrated/medbot(src) + /obj/item/weapon/cartridge/chemistry name = "\improper ChemWhiz cartridge" icon_state = "cart-chem" access_reagent_scanner = 1 + /obj/item/weapon/cartridge/chemistry/New() + ..() + radio = new /obj/item/radio/integrated/medbot(src) + /obj/item/weapon/cartridge/security name = "\improper R.O.B.U.S.T. cartridge" icon_state = "cart-s" @@ -79,6 +95,10 @@ icon_state = "cart-j" access_janitor = 1 +/obj/item/weapon/cartridge/janitor/New() + ..() + radio = new /obj/item/radio/integrated/cleanbot(src) + /obj/item/weapon/cartridge/lawyer name = "\improper P.R.O.V.E. cartridge" icon_state = "cart-s" @@ -167,6 +187,10 @@ access_engine = 1 access_atmos = 1 +/obj/item/weapon/cartridge/ce/New() + ..() + radio = new /obj/item/radio/integrated/floorbot(src) + /obj/item/weapon/cartridge/cmo name = "\improper Med-U DELUXE cartridge" icon_state = "cart-cmo" @@ -175,6 +199,10 @@ access_reagent_scanner = 1 access_medical = 1 +/obj/item/weapon/cartridge/cmo/New() + ..() + radio = new /obj/item/radio/integrated/medbot(src) + /obj/item/weapon/cartridge/rd name = "\improper Signal Ace DELUXE cartridge" icon_state = "cart-rd" @@ -249,6 +277,67 @@ frequency.post_signal(src, status_signal) +/obj/item/weapon/cartridge/proc/bot_control(var/obj/item/radio/integrated/SC) + + + if(!SC) + menu = "Interlink Error - Please reinsert cartridge." + return + + if(!SC.active) + // list of bots + if(!SC.botlist || (SC.botlist && SC.botlist.len==0)) + menu += "No bots found.
    " + + else + for(var/obj/machinery/bot/B in SC.botlist) + menu += "[B] at [get_area(B)]
    " + + menu += "
    Scan for active bots
    " + + else // bot selected, control it + + menu += "[SC.active]
    Status: (refresh)
    " + + if(!SC.botstatus) + menu += "Waiting for response...
    " + else + + menu += "Location: [SC.botstatus["loca"] ]
    " + menu += "Mode: " + + switch(SC.botstatus["mode"]) + if(BOT_IDLE) + menu += "Ready" + if(BOT_HUNT) + menu += "Apprehending target" + if(BOT_PREP_ARREST,BOT_ARREST) + menu += "Arresting target" + if(BOT_START_PATROL) + menu += "Starting patrol" + if(BOT_PATROL) + menu += "On patrol" + if(BOT_SUMMON) + menu += "Responding to summons" + if(BOT_CLEANING) + menu += "Cleaning" + if(BOT_MOVING) + menu += "Proceeding to work site" + if(BOT_REPAIRING) + menu += "Performing repairs" + if(BOT_HEALING) + menu += "Medicating patient" + if(BOT_RESPONDING) + menu += "Proceeding to AI waypoint" + + menu += "
    \[Stop Patrol\] " + menu += "\[Start Patrol\] " + menu += "\[Summon Bot\]
    " + menu += "
    Return to bot list
    " + menu += "Keep an ID inserted to upload access codes upon summoning." + return menu + + /obj/item/weapon/cartridge/proc/generate_menu() switch(mode) if(40) //signaller @@ -457,55 +546,8 @@ Code: menu += "
    " if (46) //beepsky control var/obj/item/radio/integrated/beepsky/SC = radio - if(!SC) - menu = "Interlink Error - Please reinsert cartridge." - return - menu = "

    Securitron Interlink

    " - - if(!SC.active) - // list of bots - if(!SC.botlist || (SC.botlist && SC.botlist.len==0)) - menu += "No bots found.
    " - - else - for(var/obj/machinery/bot/secbot/B in SC.botlist) - menu += "[B] at [B.loc.loc]
    " - - for(var/obj/machinery/bot/ed209/B in SC.botlist) - menu += "[B] at [B.loc.loc]
    " - - menu += "
    Scan for active bots
    " - - else // bot selected, control it - - menu += "[SC.active]
    Status: (refresh)
    " - - if(!SC.botstatus) - menu += "Waiting for response...
    " - else - - menu += "Location: [SC.botstatus["loca"] ]
    " - menu += "Mode: " - - switch(SC.botstatus["mode"]) - if(0) - menu += "Ready" - if(1) - menu += "Apprehending target" - if(2,3) - menu += "Arresting target" - if(4) - menu += "Starting patrol" - if(5) - menu += "On patrol" - if(6) - menu += "Responding to summons" - - menu += "
    \[Stop Patrol\] " - menu += "\[Start Patrol\] " - menu += "\[Summon Bot\]
    " - menu += "
    Return to bot list" + bot_control(SC) if (47) //quartermaster order records menu = "

    Supply Record Interlink

    " @@ -529,7 +571,6 @@ Code: if(!QC) menu = "Interlink Error - Please reinsert cartridge." return - menu = "

    M.U.L.E. bot Interlink V0.8

    " if(!QC.active) @@ -555,19 +596,19 @@ Code: menu += "Mode: " switch(QC.botstatus["mode"]) - if(0) + if(BOT_IDLE) menu += "Ready" - if(1) + if(BOT_LOADING) menu += "Loading/Unloading" - if(2) + if(BOT_DELIVER) menu += "Navigating to Delivery Location" - if(3) + if(BOT_GO_HOME) menu += "Navigating to Home" - if(4) + if(BOT_BLOCKED) menu += "Waiting for clear path" - if(5,6) + if(BOT_NAV,BOT_WAIT_FOR_NAV) menu += "Calculating navigation path" - if(7) + if(BOT_NO_ROUTE) menu += "Unable to locate destination" var/obj/structure/closet/crate/C = QC.botstatus["load"] menu += "
    Current Load: [ !C ? "none" : "[C.name] (unload)" ]
    " @@ -644,6 +685,20 @@ Code: menu += "ERROR: Unable to determine current location." menu += "

    Refresh GPS Locator" + if (50) //Cleanbot control + menu = "

    Cleanbot Interlink

    " + var/obj/item/radio/integrated/cleanbot/SC = radio + bot_control(SC) + + if (51) //floorbot control + menu = "

    Floorbot Interlink

    " + var/obj/item/radio/integrated/floorbot/SC = radio + bot_control(SC) + + if (52) //Medibot control + menu = "

    Medibot Interlink

    " + var/obj/item/radio/integrated/medbot/SC = radio + bot_control(SC) /obj/item/weapon/cartridge/Topic(href, href_list) ..() diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/game/objects/items/devices/PDA/radio.dm index e576cc2e109..ca45bc45567 100644 --- a/code/game/objects/items/devices/PDA/radio.dm +++ b/code/game/objects/items/devices/PDA/radio.dm @@ -4,6 +4,13 @@ icon = 'icons/obj/module.dmi' icon_state = "power_mod" var/obj/item/device/pda/hostpda = null + var/list/botlist = null // list of bots + var/obj/machinery/bot/active // the active bot; if null, show bot list + var/list/botstatus // the status signal sent by the bot + var/bot_type //The type of bot it is. + var/bot_filter //Determines which radio filter to use. + + var/control_freq = 1447 var/on = 0 //Are we currently active?? var/menu_message = "" @@ -12,13 +19,17 @@ ..() if (istype(loc.loc, /obj/item/device/pda)) hostpda = loc.loc + if (bot_filter) + spawn(5) + add_to_radio(bot_filter) -/obj/item/radio/integrated/proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3, s_filter) +/obj/item/radio/integrated/proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3,var/key4, var/value4, s_filter) //world << "Post: [freq]: [key]=[value], [key2]=[value2]" var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq) - if(!frequency) return + if(!frequency) + return var/datum/signal/signal = new() signal.source = src @@ -28,6 +39,8 @@ signal.data[key2] = value2 if(key3) signal.data[key3] = value3 + if(key4) + signal.data[key4] = value4 frequency.post_signal(src, signal, filter = s_filter) @@ -44,33 +57,18 @@ /obj/item/radio/integrated/proc/generate_menu() -/obj/item/radio/integrated/beepsky - var/list/botlist = null // list of bots - var/obj/machinery/bot/secbot/active // the active bot; if null, show bot list - var/list/botstatus // the status signal sent by the bot - var/control_freq = 1447 -// create a new QM cartridge, and register to receive bot control & beacon message -/obj/item/radio/integrated/beepsky/New() - ..() - spawn(5) - if(radio_controller) - radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT) +/obj/item/radio/integrated/receive_signal(datum/signal/signal) + /*var/obj/item/device/pda/P = src.loc -// receive radio signals -// can detect bot status signals -// create/populate list as they are recvd -/obj/item/radio/integrated/beepsky/receive_signal(datum/signal/signal) -// var/obj/item/device/pda/P = src.loc - - /* world << "recvd:[P] : [signal.source]" for(var/d in signal.data) world << "- [d] = [signal.data[d]]" - */ - if (signal.data["type"] == "secbot") + */ + + if (signal.data["type"] == bot_type) if(!botlist) botlist = new() @@ -81,9 +79,7 @@ var/list/b = signal.data botstatus = b.Copy() -// if (istype(P)) P.updateSelfDialog() - -/obj/item/radio/integrated/beepsky/Topic(href, href_list) +/obj/item/radio/integrated/Topic(href, href_list) ..() var/obj/item/device/pda/PDA = src.hostpda @@ -91,32 +87,53 @@ if("control") active = locate(href_list["bot"]) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) if("scanbots") // find all bots botlist = null - post_signal(control_freq, "command", "bot_status", s_filter = RADIO_SECBOT) + post_signal(control_freq, "command", "bot_status", s_filter = bot_filter) if("botlist") active = null if("stop", "go") - post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = RADIO_SECBOT) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) + post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) if("summon") - post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , s_filter = RADIO_SECBOT) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) + post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , "useraccess", PDA.GetAccess(), s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) PDA.cartridge.unlock() +/obj/item/radio/integrated/proc/add_to_radio(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots. + if(radio_controller) + radio_controller.add_object(src, control_freq, filter = bot_filter) + + +/obj/item/radio/integrated/beepsky + bot_filter = RADIO_SECBOT + bot_type = SEC_BOT + +/obj/item/radio/integrated/medbot + bot_filter = RADIO_MEDBOT + bot_type = MED_BOT + +/obj/item/radio/integrated/floorbot + bot_filter = RADIO_FLOORBOT + bot_type = FLOOR_BOT + +/obj/item/radio/integrated/cleanbot + bot_filter = RADIO_CLEANBOT + bot_type = CLEAN_BOT + /obj/item/radio/integrated/mule - var/list/botlist = null // list of bots - var/obj/machinery/bot/mulebot/active // the active bot; if null, show bot list - var/list/botstatus // the status signal sent by the bot + //var/list/botlist = null // list of bots + //var/obj/machinery/bot/mulebot/active // the active bot; if null, show bot list + //var/list/botstatus // the status signal sent by the bot var/list/beacons var/beacon_freq = 1400 - var/control_freq = 1447 + control_freq = 1447 // create a new QM cartridge, and register to receive bot control & beacon message /obj/item/radio/integrated/mule/New() @@ -141,7 +158,7 @@ for(var/d in signal.data) world << "- [d] = [signal.data[d]]" */ - if(signal.data["type"] == "mulebot") + if(signal.data["type"] == MULE_BOT) if(!botlist) botlist = new() @@ -162,52 +179,46 @@ // if(istype(P)) P.updateSelfDialog() /obj/item/radio/integrated/mule/Topic(href, href_list) - ..() + //..() var/obj/item/device/pda/PDA = src.hostpda var/cmd = "command" - if(active) cmd = "command [active.suffix]" + if(active) + cmd = "command [active.suffix]" switch(href_list["op"]) if("control") active = locate(href_list["bot"]) - post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) if("scanbots") // find all bots botlist = null - post_signal(control_freq, "command", "bot_status", s_filter = RADIO_MULEBOT) if("botlist") active = null - if("unload") post_signal(control_freq, cmd, "unload", s_filter = RADIO_MULEBOT) - post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) if("setdest") if(beacons) var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in beacons if(dest) post_signal(control_freq, cmd, "target", "destination", dest, s_filter = RADIO_MULEBOT) - post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) if("retoff") post_signal(control_freq, cmd, "autoret", "value", 0, s_filter = RADIO_MULEBOT) - post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) if("reton") post_signal(control_freq, cmd, "autoret", "value", 1, s_filter = RADIO_MULEBOT) - post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) if("pickoff") post_signal(control_freq, cmd, "autopick", "value", 0, s_filter = RADIO_MULEBOT) - post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) + if("pickon") post_signal(control_freq, cmd, "autopick", "value", 1, s_filter = RADIO_MULEBOT) - post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) if("stop", "go", "home") post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT) - post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) + + post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) PDA.cartridge.unlock() @@ -227,10 +238,10 @@ ..() if(radio_controller) initialize() - + /obj/item/radio/integrated/signal/initialize() if (src.frequency < 1441 || src.frequency > 1489) - src.frequency = sanitize_frequency(src.frequency) + src.frequency = sanitize_frequency(src.frequency) set_frequency(frequency) @@ -256,4 +267,4 @@ radio_connection.post_signal(src, signal) - return + return \ No newline at end of file diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 38101fedab3..9ab05593915 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -228,7 +228,7 @@ spawn(0) src.interact(usr) else if (S.amount >= max_amount) - return 1 + return var/to_transfer as num if (user.get_inactive_hand()==src) to_transfer = 1 diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm index b6201fbefba..455c87b9f4c 100644 --- a/code/game/objects/items/weapons/extinguisher.dm +++ b/code/game/objects/items/weapons/extinguisher.dm @@ -67,27 +67,29 @@ var/direction = get_dir(src,target) - if(usr.buckled && isobj(usr.buckled) && !usr.buckled.anchored ) + if(usr.buckled && isobj(usr.buckled) && !usr.buckled.anchored) spawn(0) var/obj/B = usr.buckled var/movementdirection = turn(direction,180) - B.Move(get_step(usr,movementdirection), movementdirection) + step(B, movementdirection) sleep(1) - B.Move(get_step(usr,movementdirection), movementdirection) + step(B, movementdirection) sleep(1) - B.Move(get_step(usr,movementdirection), movementdirection) + step(B, movementdirection) sleep(1) - B.Move(get_step(usr,movementdirection), movementdirection) + step(B, movementdirection) sleep(2) - B.Move(get_step(usr,movementdirection), movementdirection) + step(B, movementdirection) sleep(2) - B.Move(get_step(usr,movementdirection), movementdirection) + step(B, movementdirection) sleep(3) - B.Move(get_step(usr,movementdirection), movementdirection) + step(B, movementdirection) sleep(3) - B.Move(get_step(usr,movementdirection), movementdirection) + step(B, movementdirection) sleep(3) - B.Move(get_step(usr,movementdirection), movementdirection) + step(B, movementdirection) + + else user.newtonian_move(turn(direction, 180)) var/turf/T = get_turf(target) var/turf/T1 = get_step(T,turn(direction, 90)) @@ -118,9 +120,5 @@ if(W.loc == my_target) break sleep(2) - if(!has_gravity(user)) - user.inertia_dir = get_dir(target, user) - step(user, user.inertia_dir) else - return ..() - return + return ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/gift_wrappaper.dm b/code/game/objects/items/weapons/gift_wrappaper.dm index 0068304bbcf..5396cdd8940 100644 --- a/code/game/objects/items/weapons/gift_wrappaper.dm +++ b/code/game/objects/items/weapons/gift_wrappaper.dm @@ -84,7 +84,9 @@ desc = "You can use this to wrap items in." icon = 'icons/obj/items.dmi' icon_state = "wrap_paper" + flags = NOBLUDGEON amount = 25 + max_amount = 25 /obj/item/stack/wrapping_paper/attack_self(mob/user) user << "You need to use it on a package that has already been wrapped!" diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index f47d382fe15..f404c37e711 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -50,6 +50,11 @@ user.update_inv_r_hand() qdel(src) +/obj/item/weapon/storage/box/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/stack/packageWrap)) + return 0 + ..() + /obj/item/weapon/storage/box/survival diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index 0e6416867dd..ee907422628 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -156,7 +156,7 @@ name = "janicart" icon = 'icons/obj/vehicles.dmi' icon_state = "pussywagon" - anchored = 1 + anchored = 0 density = 1 flags = OPENCONTAINER //copypaste sorry @@ -206,6 +206,8 @@ if(user.stat || user.stunned || user.weakened || user.paralysis) unbuckle() if(istype(user.l_hand, /obj/item/key) || istype(user.r_hand, /obj/item/key)) + if(!Process_Spacemove(direction)) + return step(src, direction) update_mob() handle_rotation() @@ -213,13 +215,6 @@ user << "You'll need the keys in one of your hands to drive this [callme]." -/obj/structure/stool/bed/chair/janicart/Move() - ..() - if(buckled_mob) - if(buckled_mob.buckled == src) - buckled_mob.loc = loc - - /obj/structure/stool/bed/chair/janicart/buckle_mob(mob/M, mob/user) if(M != user || !ismob(M) || get_dist(src, user) > 1 || user.restrained() || user.lying || user.stat || M.buckled || istype(user, /mob/living/silicon)) return diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index b5e4b9c1f0c..f4a0a0a6ed9 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -22,6 +22,28 @@ unbuckle() ..() +/obj/structure/stool/bed/Move(atom/newloc, direct) //Some bed children move + . = ..() + if(buckled_mob) + buckled_mob.buckled = null + if(!buckled_mob.Move(loc, direct)) + loc = buckled_mob.loc //we gotta go back + last_move = buckled_mob.last_move + inertia_dir = last_move + buckled_mob.inertia_dir = last_move + . = 0 + buckled_mob.buckled = src + +/obj/structure/stool/bed/Process_Spacemove(var/movement_dir = 0) + if(buckled_mob) + return buckled_mob.Process_Spacemove(movement_dir) + return ..() + +/obj/structure/stool/bed/CanPass(atom/movable/mover, turf/target, height=1.5) + if(mover == buckled_mob) + return 1 + return ..() + /obj/structure/stool/bed/attack_paw(mob/user as mob) return src.attack_hand(user) @@ -49,9 +71,10 @@ buckled_mob.anchored = initial(buckled_mob.anchored) buckled_mob.update_canmove() - var/M = buckled_mob + var/mob/M = buckled_mob buckled_mob = null + M.newtonian_move(inertia_dir) afterbuckle(M) return @@ -135,13 +158,6 @@ icon_state = "down" M.pixel_y -= buckled_pixel_y_offset -/obj/structure/stool/bed/roller/Move() - ..() - if(buckled_mob) - if(buckled_mob.buckled == src) - buckled_mob.loc = src.loc - else - buckled_mob = null /obj/item/roller name = "roller bed" diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 8838ba46f78..be89e7e6a5c 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -11,6 +11,10 @@ handle_layer() return +/obj/structure/stool/bed/chair/Move(atom/newloc, direct) + ..() + handle_rotation() + /obj/structure/stool/bed/chair/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() if(istype(W, /obj/item/assembly/shock_kit)) @@ -30,10 +34,10 @@ rotate() return -/obj/structure/stool/bed/chair/proc/handle_rotation(direction) //making this into a seperate proc so office chairs can call it on Move() +/obj/structure/stool/bed/chair/proc/handle_rotation(direction) if(buckled_mob) buckled_mob.buckled = null //Temporary, so Move() succeeds. - if(!buckled_mob.Move(direction)) + if(!direction || !buckled_mob.Move(get_step(src, direction), direction)) buckled_mob.buckled = src dir = buckled_mob.dir return 0 @@ -127,11 +131,6 @@ /obj/structure/stool/bed/chair/office anchored = 0 -/obj/structure/stool/bed/chair/office/Move(direction) - if(handle_rotation(direction)) - ..() - handle_layer() - /obj/structure/stool/bed/chair/office/light icon_state = "officechair_white" diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm index ed395cc19e5..9e9afcc61dc 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -55,6 +55,11 @@ for(var/atom/movable/M in src.contents) M.loc = src.loc +/obj/structure/transit_tube_pod/Process_Spacemove() + if(moving) //No drifting while moving in the tubes + return 1 + else return ..() + /obj/structure/transit_tube_pod/proc/follow_tube(var/reverse_launch) if(moving) return @@ -97,7 +102,7 @@ if(current_tube == null) dir = next_dir - Move(get_step(loc, dir)) // Allow collisions when leaving the tubes. + Move(get_step(loc, dir), dir) // Allow collisions when leaving the tubes. break last_delay = current_tube.enter_delay(src, next_dir) @@ -111,22 +116,6 @@ break density = 1 - - // If the pod is no longer in a tube, move in a line until stopped or slowed to a halt. - // /turf/inertial_drift appears to only work on mobs, and re-implementing some of the - // logic allows a gradual slowdown and eventual stop when passing over non-space turfs. - if(!current_tube && last_delay <= 10) - do - sleep(last_delay) - - if(!istype(loc, /turf/space)) - last_delay++ - - if(last_delay > 10) - break - - while(isturf(loc) && Move(get_step(loc, dir))) - moving = 0 diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 8e38ac30808..acdb0fab9c4 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -37,18 +37,6 @@ if (istype(A,/mob/living/carbon)) var/mob/living/carbon/M = A if(M.lying) return - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(istype(H.shoes, /obj/item/clothing/shoes/clown_shoes)) - var/obj/item/clothing/shoes/clown_shoes/O = H.shoes - if(H.m_intent == "run") - if(O.footstep >= 2) - O.footstep = 0 - playsound(src, "clownstep", 50, 1) // this will get annoying very fast. - else - O.footstep++ - else - playsound(src, "clownstep", 20, 1) switch (src.wet) if(1) //wet floor diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 13893942dfd..b8ecd518b05 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -52,8 +52,6 @@ if ((!(A) || src != A.loc)) return - inertial_drift(A) - if(transition) if(destination_x) @@ -71,8 +69,8 @@ L.pulling.loc = T //now we're on the new z_level, proceed the space drifting - if ((A && A.loc)) - A.loc.Entered(A) + sleep(0)//Let a diagonal move finish, if necessary + A.newtonian_move(A.inertia_dir) /turf/space/proc/Sandbox_Spacemove(atom/movable/A) var/cur_x @@ -211,4 +209,4 @@ proc/setup_map_transitions() //listamania S.Assign_Destination() /turf/space/singularity_act() - return \ No newline at end of file + return diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 4fb55be2ffe..20f53440ed1 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -85,12 +85,7 @@ var/mob/O = M if(!O.lastarea) O.lastarea = get_area(O.loc) - var/has_gravity = O.mob_has_gravity(src) - O.update_gravity(has_gravity) - if(!has_gravity) - inertial_drift(O) - else if(!istype(src, /turf/space)) - O.inertia_dir = 0 + O.update_gravity(O.mob_has_gravity()) var/loopsanity = 100 for(var/atom/A in range(1)) @@ -128,25 +123,6 @@ /turf/proc/return_siding_icon_state() //used for grass floors, which have siding. return 0 -/turf/proc/inertial_drift(atom/movable/A as mob|obj) - if(!(A.last_move)) - return - if (A.pulledby) - return - if((istype(A, /mob/) && src.x > 2 && src.x < (world.maxx - 1) && src.y > 2 && src.y < (world.maxy-1))) - var/mob/M = A - if(M.Process_Spacemove(1)) - M.inertia_dir = 0 - return - spawn(5) - if((M && !(M.anchored) && (M.loc == src))) - if(M.inertia_dir & M.last_move) - step(M, M.inertia_dir) - return - M.inertia_dir = M.last_move - step(M, M.inertia_dir) - return - /turf/proc/levelupdate() for(var/obj/O in src) if(O.level == 1) diff --git a/code/game/verbs/atom_verbs.dm b/code/game/verbs/atom_verbs.dm index 2ff6efcf260..2726c11875f 100644 --- a/code/game/verbs/atom_verbs.dm +++ b/code/game/verbs/atom_verbs.dm @@ -6,28 +6,3 @@ if(Adjacent(usr)) usr.start_pulling(src) return - -/atom/verb/point() - set name = "Point To" - set category = "Object" - set src in oview() - var/atom/this = src//detach proc from src - src = null - - if(!usr || !isturf(usr.loc)) - return - if(usr.stat || usr.restrained()) - return - if(usr.status_flags & FAKEDEATH) - return - - var/tile = get_turf(this) - if (!tile) - return - - var/obj/P = new /obj/effect/decal/point(tile) - spawn (20) - if(P) - P.loc = null - - usr.visible_message("[usr] points to [this]") diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index 32a874d0f51..7fc699f736a 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -222,6 +222,10 @@ var/list/admin_ranks = list() //list of all admin_rank datums if("remove") if(alert("Are you sure you want to remove [adm_ckey]?","Message","Yes","Cancel") == "Yes") if(!D) return + if(!check_if_greater_rights_than_holder(D)) + message_admins("[key_name_admin(usr)] attempted to remove [adm_ckey] from the admins list without sufficient rights.") + log_admin("[key_name(usr)] attempted to remove [adm_ckey] from the admins list without sufficient rights.") + return admin_datums -= adm_ckey D.disassociate() @@ -244,6 +248,12 @@ var/list/admin_ranks = list() //list of all admin_rank datums new_rank = ckeyEx(input("Please input a new rank", "New custom rank", null, null) as null|text) if(!new_rank) return + if(D) + if(!check_if_greater_rights_than_holder(D)) + message_admins("[key_name_admin(usr)] attempted to change the rank of [adm_ckey] to [new_rank] without sufficient rights.") + log_admin("[key_name(usr)] attempted to change the rank of [adm_ckey] to [new_rank] without sufficient rights.") + return + R = rank_names[new_rank] if(!R) //rank with that name doesn't exist yet - make it if(D) R = new(new_rank, D.rank.rights, D.rank.adds, D.rank.subs) //duplicate our previous admin_rank but with a new name @@ -269,6 +279,11 @@ var/list/admin_ranks = list() //list of all admin_rank datums var/keyword = input("Input permission keyword (one at a time):\ne.g. +BAN or -FUN or +/client/proc/someverb", "Permission toggle", null, null) as null|text if(!keyword) return + if(!check_if_greater_rights_than_holder(D)) + message_admins("[key_name_admin(usr)] attempted to give [adm_ckey] the keyword [keyword] without sufficient rights.") + log_admin("[key_name(usr)] attempted to give [adm_ckey] the keyword [keyword] without sufficient rights.") + return + D.disassociate() if(!findtext(D.rank.name, "([adm_ckey])")) //not a modified subrank, need to duplicate the admin_rank datum to prevent modifying others too diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index eb1445669f5..8b289da6f70 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -40,6 +40,16 @@ var/list/admin_datums = list() owner.holder = null owner = null +/datum/admins/proc/check_if_greater_rights_than_holder(datum/admins/other) + if(!other) + return 1 //they have no rights + if(rank.rights == 65535) + return 1 //we have all the rights + if(rank.rights != other.rank.rights) + if( (rank.rights & other.rank.rights) == other.rank.rights ) + return 1 //we have all the rights they have and more + return 0 + /* checks if usr is an admin with at least ONE of the flags in rights_required. (Note, they don't need all the flags) if rights_required == 0, then it simply checks if they are an admin. @@ -68,13 +78,9 @@ you will have to do something like if(client.rights & R_ADMIN) yourself. if(usr.client.holder) if(!other || !other.holder) return 1 - if(usr.client.holder.rank.rights != other.holder.rank.rights) //Check values smaller than 65536 - if( (usr.client.holder.rank.rights & other.holder.rank.rights) == other.holder.rank.rights ) - return 1 //we have all the rights they have and more - usr << "Error: Cannot proceed. They have greater or equal rights to us." + return usr.client.holder.check_if_greater_rights_than_holder(other.holder) return 0 - /client/proc/deadmin() admin_datums -= ckey if(holder) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index d40e4a1a1d3..767627aa68a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -784,6 +784,7 @@ var/mob/M = locate(href_list["boot2"]) if (ismob(M)) if(!check_if_greater_rights_than(M.client)) + usr << "Error: They have more rights than you do." return M << "You have been kicked from the server." log_admin("[key_name(usr)] booted [key_name(M)].") diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index e8fa448fce2..bd384c22952 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -259,6 +259,9 @@ var/next_external_rsc = 0 'icons/pda_icons/pda_boom.png', 'icons/pda_icons/pda_bucket.png', 'icons/pda_icons/pda_chatroom.png', + 'icons/pda_icons/pda_medbot.png', + 'icons/pda_icons/pda_floorbot.png', + 'icons/pda_icons/pda_cleanbot.png', 'icons/pda_icons/pda_crate.png', 'icons/pda_icons/pda_cuffs.png', 'icons/pda_icons/pda_eject.png', @@ -302,4 +305,4 @@ var/next_external_rsc = 0 'icons/stamp_icons/large_stamp-cap.png', 'icons/stamp_icons/large_stamp-qm.png', 'icons/stamp_icons/large_stamp-law.png' - ) \ No newline at end of file + ) diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 5911f0178d8..054c7d2acab 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -147,10 +147,4 @@ name = "Optical Thermal Eyepatch" desc = "An eyepatch with built-in thermal optics" icon_state = "eyepatch" - item_state = "eyepatch" - -/obj/item/clothing/glasses/thermal/jensen - name = "Optical Thermal Implants" - desc = "A set of implantable lenses designed to augment your vision" - icon_state = "thermalimplants" - item_state = "syringe_kit" \ No newline at end of file + item_state = "eyepatch" \ No newline at end of file diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index 505c336b6aa..25e6b20f94a 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -68,13 +68,5 @@ emagged = 1 desc = desc + " The display flickers slightly." -/obj/item/clothing/glasses/hud/security/jensenshades - name = "Augmented shades" - desc = "Polarized bioneural eyewear, designed to augment your vision." - icon_state = "jensenshades" - item_state = "jensenshades" - vision_flags = SEE_MOBS - invis_view = 2 - /obj/item/clothing/glasses/hud/security/process_hud(var/mob/M) process_data_hud(M,DATA_HUD_SECURITY,DATA_HUD_ADVANCED) diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 360e6e52e63..88db2bd9160 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -21,6 +21,26 @@ armor = list(melee = 82, bullet = 15, laser = 5,energy = 5, bomb = 5, bio = 2, rad = 0) flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE strip_delay = 80 + action_button_name = "Toggle Helmet Visor" + visor_flags = HEADCOVERSEYES | HEADCOVERSMOUTH + visor_flags_inv = HIDEMASK|HIDEEYES|HIDEFACE + +/obj/item/clothing/head/helmet/riot/attack_self() + if(usr.canmove && !usr.stat && !usr.restrained()) + if(up) + up = !up + flags |= (visor_flags) + flags_inv |= (visor_flags_inv) + icon_state = initial(icon_state) + usr << "You pull the [src] down." + usr.update_inv_head(0) + else + up = !up + flags &= ~(visor_flags) + flags_inv &= ~(visor_flags_inv) + icon_state = "[initial(icon_state)]up" + usr << "You push the [src] up." + usr.update_inv_head(0) /obj/item/clothing/head/helmet/swat name = "\improper SWAT helmet" diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index 84f1d7ca791..132d31c2cc0 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -56,14 +56,6 @@ flags = BLOCKHAIR flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE -/obj/item/clothing/head/cueball - name = "cueball helmet" - desc = "A large, featureless white orb mean to be worn on your head. How do you even see out of this thing?" - icon_state = "cueball" - flags = HEADCOVERSEYES|BLOCKHAIR - item_state="cueball" - flags_inv = 0 - /obj/item/clothing/head/that name = "sturdy top-hat" desc = "It's an amish looking armored top hat." diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index 8c16e3d746d..496fd90507f 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -1,3 +1,5 @@ +/obj/item/clothing/shoes/proc/step_action() //this was made to rewrite clown shoes squeaking + /obj/item/clothing/shoes/syndigaloshes desc = "A pair of brown shoes. They seem to have extra grip." name = "brown shoes" @@ -75,6 +77,13 @@ item_color = "clown" var/footstep = 1 //used for squeeks whilst walking +/obj/item/clothing/shoes/clown_shoes/step_action() + if(footstep > 1) + playsound(src, "clownstep", 50, 1) + footstep = 0 + else + footstep++ + /obj/item/clothing/shoes/jackboots name = "jackboots" desc = "Nanotrasen-issue Security combat boots for combat scenarios or combat situations. All combat, all the time." diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm index 9f569758bae..658c78b3698 100644 --- a/code/modules/clothing/under/jobs/security.dm +++ b/code/modules/clothing/under/jobs/security.dm @@ -2,7 +2,6 @@ * Contains: * Security * Detective - * Head of Security + Jensen cosplay gear * Navy uniforms */ diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 5e76a853eac..c46f5def722 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -14,14 +14,6 @@ item_state = "w_suit" can_adjust = 0 -/obj/item/clothing/under/scratch - name = "white suit" - desc = "A white suit, suitable for an excellent host" - icon_state = "scratch" - item_state = "scratch" - item_color = "scratch" - can_adjust = 0 - /obj/item/clothing/under/sl_suit desc = "It's a very amish looking suit." name = "amish suit" diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 72cea9209af..0b65480c830 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -22,4 +22,6 @@ if(prob(95)) new /mob/living/simple_animal/hostile/carp(C.loc) else - new /mob/living/simple_animal/hostile/carp/megacarp(C.loc) \ No newline at end of file + new /mob/living/simple_animal/hostile/carp/megacarp(C.loc) + + diff --git a/code/modules/events/holiday/halloween.dm b/code/modules/events/holiday/halloween.dm index ad6a82e04df..bcd9a0ef3bb 100644 --- a/code/modules/events/holiday/halloween.dm +++ b/code/modules/events/holiday/halloween.dm @@ -7,11 +7,35 @@ earliest_start = 0 /datum/round_event/spooky/start() + ..() for(var/mob/living/carbon/human/H in mob_list) if(H.dna) - hardset_dna(H, null, null, null, null, /datum/species/skeleton) + if(prob(50)) + hardset_dna(H, null, null, null, null, /datum/species/skeleton) + else + hardset_dna(H, null, null, null, null, /datum/species/zombie) + for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list) Ian.place_on_head(new /obj/item/weapon/bedsheet(Ian)) + spawn_meteors(5, meteorsSPOOKY) + + var/datum/round_event_control/carp_migration/eyeballs/SpookyMigration = locate() in events.control + SpookyMigration.runEvent() + /datum/round_event/spooky/announce() priority_announce(pick("RATTLE ME BONES!","THE RIDE NEVER ENDS!", "A SKELETON POPS OUT!", "SPOOKY SCARY SKELETONS!", "CREWMEMBERS BEWARE, YOU'RE IN FOR A SCARE!") , "THE CALL IS COMING FROM INSIDE THE HOUSE") + +//Eyeball migration +/datum/round_event_control/carp_migration/eyeballs + name = "Eyeball Migration" + typepath = /datum/round_event/carp_migration/eyeballs + holidayID = "Halloween" + weight = 0 + earliest_start = 0 + +/datum/round_event/carp_migration/eyeballs/start() + for(var/obj/effect/landmark/C in landmarks_list) + if(C.name == "carpspawn") + new /mob/living/simple_animal/hostile/carp/eyeball(C.loc) + diff --git a/code/modules/food&drinks/food/snacks/meat.dm b/code/modules/food&drinks/food/snacks/meat.dm index 91b2c27b243..9397cd6b40f 100644 --- a/code/modules/food&drinks/food/snacks/meat.dm +++ b/code/modules/food&drinks/food/snacks/meat.dm @@ -61,6 +61,11 @@ icon_state = "skeletonmeat" desc = "There's a point where this needs to stop and clearly we have passed it" +/obj/item/weapon/reagent_containers/food/snacks/meat/human/mutant/zombie + name = "-meat (rotten)" + icon_state = "lizardmeat" //Close enough. + desc = "Halfway to becoming fertilizer for your garden." + /obj/item/weapon/reagent_containers/food/snacks/meat/monkey //same as plain meat diff --git a/code/modules/holiday/halloween.dm b/code/modules/holiday/halloween.dm new file mode 100644 index 00000000000..4e2de9e5c6e --- /dev/null +++ b/code/modules/holiday/halloween.dm @@ -0,0 +1,337 @@ +//spooky halloween stuff. only tick on halloween!!! +/datum/round_event/spooky/start() //This has to be here because else you get errors with spooky storage not being a defined type. + ..() + for(var/mob/living/carbon/human/H) + for(var/obj/item/weapon/storage/backpack/b in H.contents) + new /obj/item/weapon/storage/spooky(b) + +//uses super seekrit double proc definition stuffs. remember to call ..()! +/*/mob/dead/observer/say(var/message) //this doesn't actually work vOv + ..() + for(var/mob/M in hearers(src, 1)) + if(!M.stat) + if(M.job == "Chaplain") + if (prob (49)) + M.show_message("You hear muffled speech... but nothing is there...", 2) + if(prob(20)) + playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) + else + M.show_message("You hear muffled speech... you can almost make out some words...", 2) +// M.show_message("[stutter(message)]", 2) + if(prob(30)) + playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) + else + if(prob(50)) + return + else if(prob (95)) + M.show_message("You hear muffled speech... but nothing is there...", 2) + if(prob(20)) + playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) + else + M.show_message("You hear muffled speech... you can almost make out some words...", 2) +// M.show_message("[stutter(message)]", 2) + playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1)*/ + + +/////////////////////////////////////// +///////////HALLOWEEN CONTENT/////////// +/////////////////////////////////////// + +//spooky foods +/obj/item/weapon/reagent_containers/food/snacks/sugarcookie/spookyskull + name = "skull cookie" + desc = "Spooky! It's got delicious calcium flavouring!" + icon = 'icons/obj/halloween_items.dmi' + icon_state = "skeletoncookie" + +/obj/item/weapon/reagent_containers/food/snacks/sugarcookie/spookycoffin + name = "coffin cookie" + desc = "Spooky! It's got delicious coffee flavouring!" + icon = 'icons/obj/halloween_items.dmi' + icon_state = "coffincookie" + +//spooky recipes + +/datum/recipe/sugarcookie/spookyskull + reagents = list("flour" = 5, "sugar" = 5, "milk" = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sugarcookie/spookyskull + +/datum/recipe/sugarcookie/spookycoffin + reagents = list("flour" = 5, "sugar" = 5, "coffee" = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sugarcookie/spookycoffin + +//spooky items + +/obj/item/weapon/storage/spooky + name = "trick-o-treat bag" + desc = "A Pumpkin shaped bag that holds all sorts of goodies!" + icon = 'icons/obj/halloween_items.dmi' + icon_state = "treatbag" + +/obj/item/weapon/storage/spooky/New() + ..() + for(var/distrobuteinbag=0 to 6) + var/type = pick(/obj/item/weapon/reagent_containers/food/snacks/sugarcookie/spookyskull, + /obj/item/weapon/reagent_containers/food/snacks/sugarcookie/spookycoffin, + /obj/item/weapon/reagent_containers/food/snacks/candy_corn, + /obj/item/weapon/reagent_containers/food/snacks/candy, + /obj/item/weapon/reagent_containers/food/snacks/chocolatebar) + new type(src) + +////////////////////////////// +//Spookoween trapped closets// +////////////////////////////// + +#define SPOOKY_SKELETON 1 +#define ANGRY_FAITHLESS 2 +#define SCARY_BATS 3 +#define INSANE_CLOWN 4 +#define HOWLING_GHOST 5 + +//Spookoween variables +/obj/structure/closet + var/trapped = 0 + var/mob/trapped_mob + +/obj/structure/closet/initialize() + ..() + if(prob(30)) + set_spooky_trap() + +/obj/structure/closet/dump_contents() + ..() + trigger_spooky_trap() + +/obj/structure/closet/proc/set_spooky_trap() + if(prob(0.1)) + trapped = INSANE_CLOWN + return + if(prob(1)) + trapped = ANGRY_FAITHLESS + return + if(prob(15)) + trapped = SCARY_BATS + return + if(prob(20)) + trapped = HOWLING_GHOST + return + else + var/mob/living/carbon/human/H = new (loc) + H.makeSkeleton() + H.health = 1e5 + insert(H) + trapped_mob = H + trapped = SPOOKY_SKELETON + return + +/obj/structure/closet/proc/trigger_spooky_trap() + if(!trapped) + return + + if(trapped == SPOOKY_SKELETON) + src.visible_message("BOO!"); + playsound(src.loc, pick('sound/effects/xylophone1.ogg','sound/effects/xylophone2.ogg','sound/effects/xylophone3.ogg','sound/spookoween/girlscream.ogg'), 300, 1) + trapped = 0 + spawn(60) + if(trapped_mob.loc != loc) + var/datum/effect/effect/system/harmless_smoke_spread/smoke = new + smoke.set_up(1,0, trapped_mob.loc, 0) + smoke.start() + trapped_mob.loc = loc + src.close() + trapped = SPOOKY_SKELETON + return + + if(trapped == ANGRY_FAITHLESS) + src.visible_message("The closet bursts open!"); + src.visible_message("THIS BEING RADIATES PURE EVIL! YOU BETTER RUN !!!"); + playsound(src.loc, 'sound/hallucinations/wail.ogg', 300, 1) + var/mob/living/simple_animal/hostile/faithless/F = new (loc) + F.health =1e5 + F.stance = HOSTILE_STANCE_ATTACK + F.GiveTarget(usr) + trapped = 0 + qdel(src) + spawn(120) + var/datum/effect/effect/system/harmless_smoke_spread/smoke = new + smoke.set_up(1,0, F.loc, 0) + smoke.start() + qdel(F) + return + + if(trapped == SCARY_BATS) + src.visible_message("Protect your hairs !!!"); + playsound(src.loc, 'sound/spookoween/bats.ogg', 300, 1) + var/number = rand(1,4) + for(var/i=0,i < number,i++) + new /mob/living/simple_animal/hostile/retaliate/bat (loc) + trapped = 0 + return + + + if(trapped == INSANE_CLOWN) + src.visible_message("..."); + playsound(src.loc, 'sound/spookoween/scary_clown_appear.ogg', 300, 1) + var/mob/living/simple_animal/hostile/retaliate/clown/insane/IC = new (loc) + IC.GiveTarget(usr) + trapped = 0 + return + + if(trapped == HOWLING_GHOST) + src.visible_message("Woo Woo"); + playsound(src.loc, 'sound/spookoween/ghosty_wind.ogg', 300, 1) + new /mob/living/simple_animal/shade/howling_ghost (loc) + trapped = 0 + return + +//don't spawn in crates +/obj/structure/closet/crate/trigger_spooky_trap() + return 0 + +/obj/structure/closet/crate/set_spooky_trap() + return 0 + + +//////////////////// +//Spookoween Ghost// +//////////////////// + +/mob/living/simple_animal/shade/howling_ghost + name ="Ghost" + real_name = "Ghost" + icon = 'icons/mob/mob.dmi' + maxHealth = 1e6 + health = 1e6 + speak_emote = list("howls") + emote_hear = list("wails","screeches") + density = 0 + anchored = 1 + incorporeal_move = 1 + layer = 4 + var/timer = 0 + +/mob/living/simple_animal/shade/howling_ghost/New() + ..() + icon_state = pick("ghost","ghostian","ghostian2","ghostking","ghost1","ghost2") + icon_living = icon_state + status_flags |= GODMODE + timer = rand(1,15) + +/mob/living/simple_animal/shade/howling_ghost/Life() + ..() + timer-- + if(timer == 0) + roam() + spooky_ghosty() + timer = rand(1,15) + +/mob/living/simple_animal/shade/howling_ghost/proc/EtherealMove(direction) + loc = get_step(src, direction) + dir = direction + +/mob/living/simple_animal/shade/howling_ghost/proc/roam() + if(prob(80)) + var/direction = pick(NORTH,SOUTH,EAST,WEST,NORTHEAST,NORTHWEST,SOUTHEAST,SOUTHWEST) + EtherealMove(direction) + +/mob/living/simple_animal/shade/howling_ghost/proc/spooky_ghosty() + if(prob(20)) //haunt + playsound(src.loc, pick('sound/spookoween/ghosty_wind.ogg','sound/spookoween/ghost_whisper.ogg','sound/spookoween/chain_rattling.ogg'), 300, 1) + if(prob(10)) //flickers + var/obj/machinery/light/L = locate(/obj/machinery/light) in view(5, src) + if(L) + L.flicker() + if(prob(5)) //poltergeist + var/obj/item/I = locate(/obj/item) in view(3, src) + if(I) + var/direction = pick(NORTH,SOUTH,EAST,WEST,NORTHEAST,NORTHWEST,SOUTHEAST,SOUTHWEST) + step(I,direction) + return + +/mob/living/simple_animal/shade/howling_ghost/adjustBruteLoss() + return + +/mob/living/simple_animal/shade/howling_ghost/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + return 1 + + +/////////////////////////// +//Spookoween Insane Clown// +/////////////////////////// + +/mob/living/simple_animal/hostile/retaliate/clown/insane + name = "Insane Clown" + desc = "May the HonkMother have mercy..." + icon_state = "scary_clown" + icon_living = "scary_clown" + icon_dead = "scary_clown" + icon_gib = "scary_clown" + speak = list("...", ". . .") + maxHealth = 1e6 + health = 1e6 + emote_see = list("silently stares") + heat_damage_per_tick = 0 + cold_damage_per_tick = 0 + unsuitable_atmos_damage = 0 + + var/timer + +/mob/living/simple_animal/hostile/retaliate/clown/insane/New() + ..() + timer = rand(5,15) + status_flags = (status_flags | GODMODE) + return + +/mob/living/simple_animal/hostile/retaliate/clown/insane/Retaliate() + return + +/mob/living/simple_animal/hostile/retaliate/clown/insane/ex_act() + return + +/mob/living/simple_animal/hostile/retaliate/clown/insane/Life() + timer-- + if(target) + stalk() + return + +/mob/living/simple_animal/hostile/retaliate/clown/insane/proc/stalk() + var/mob/living/M = target + if(M.stat == DEAD) + playsound(M.loc, 'sound/spookoween/insane_low_laugh.ogg', 300, 1) + qdel(src) + if(timer == 0) + timer = rand(5,15) + playsound(M.loc, pick('sound/spookoween/scary_horn.ogg','sound/spookoween/scary_horn2.ogg', 'sound/spookoween/scary_horn3.ogg'), 300, 1) + spawn(12) + loc = M.loc + return + +/mob/living/simple_animal/hostile/retaliate/clown/insane/MoveToTarget() + return + +/mob/living/simple_animal/hostile/retaliate/clown/insane/AttackTarget() + return + +/mob/living/simple_animal/hostile/retaliate/clown/insane/adjustBruteLoss() + if(prob(5)) + playsound(src.loc, 'sound/spookoween/insane_low_laugh.ogg', 300, 1) + return + +/mob/living/simple_animal/hostile/retaliate/clown/insane/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O,/obj/item/weapon/nullrod)) + if(prob(5)) + visible_message("[src] finally found the peace it deserves. HONK for the HonkMother !"); + playsound(src.loc, 'sound/spookoween/insane_low_laugh.ogg', 300, 1) + qdel(src) + return + else + visible_message("It seems to be resisting the effect!!!"); + return + ..() + diff --git a/code/modules/mob/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm index 37831db6f0a..c173f406e2f 100644 --- a/code/modules/mob/dead/observer/say.dm +++ b/code/modules/mob/dead/observer/say.dm @@ -18,29 +18,3 @@ /mob/dead/observer/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq) src << message - -/* - for (var/mob/M in hearers(null, null)) - if (!M.stat) - if(M.job == "Chaplain") - if (prob (49)) - M.show_message("You hear muffled speech... but nothing is there...", 2) - if(prob(20)) - playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) - else - M.show_message("You hear muffled speech... you can almost make out some words...", 2) -// M.show_message("[stutter(message)]", 2) - if(prob(30)) - playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) - else - if (prob(50)) - return - else if (prob (95)) - M.show_message("You hear muffled speech... but nothing is there...", 2) - if(prob(20)) - playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) - else - M.show_message("You hear muffled speech... you can almost make out some words...", 2) -// M.show_message("[stutter(message)]", 2) - playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) -*/ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index d2845a672ed..9e5285b6cf1 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -158,9 +158,6 @@ /mob/living/carbon/alien/SpeciesCanConsume() return 1 // Aliens can eat, and they can be fed food/drink -/mob/living/carbon/alien/Process_Spaceslipping() - return 0 // Don't slip in space. - /mob/living/carbon/alien/Stat() statpanel("Status") diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm index dcbcba1ded8..68c63a16410 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm @@ -136,7 +136,7 @@ var/atom/step = get_step(src, get_dir(src,target)) if(!step) break - src.Move(step) + src.Move(step, get_dir(src, step)) hit_check() error += (error < 0) ? tdist_x : -tdist_y; dist_travelled++ diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 55076006232..52ae23cc879 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -309,20 +309,7 @@ item.layer = initial(item.layer) src.visible_message("[src] has thrown [item].") - if(!src.lastarea) - src.lastarea = get_area(src.loc) - if(!has_gravity(src)) - src.inertia_dir = get_dir(target, src) - step(src, inertia_dir) - - -/* - if(istype(src.loc, /turf/space) || (src.flags & NOGRAV)) //they're in space, move em one space in the opposite direction - src.inertia_dir = get_dir(target, src) - step(src, inertia_dir) -*/ - - + newtonian_move(get_dir(target, src)) item.throw_at(target, item.throw_range, item.throw_speed) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 2d9e34d5519..84d3f094d59 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -43,7 +43,7 @@ return ..() /mob/living/carbon/human/Bump(atom/movable/AM as mob|obj, yes) - if ((!( yes ) || now_pushing)) + if ((!( yes ) || now_pushing || buckled)) return now_pushing = 1 if (ismob(AM)) @@ -111,7 +111,7 @@ if(pulling == AM) stop_pulling() var/t = get_dir(src, AM) - AM.Move(get_step(AM, t)) + AM.Move(get_step(AM, t), t) now_pushing = 0 /mob/living/carbon/human/Stat() @@ -716,4 +716,4 @@ gain = rand(-300, 300) investigate_log(" has consumed [key_name(src)].","singulo") //Oh that's where the clown ended up! gib() - return(gain) \ No newline at end of file + return(gain) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 438fb8c650b..b5ad5610e7e 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -5,40 +5,20 @@ . += ..() . += config.human_delay -/mob/living/carbon/human/Process_Spacemove(var/check_drift = 0) - //Can we act - if(!canmove) return 0 +/mob/living/carbon/human/Process_Spacemove(var/movement_dir = 0) + + if(..()) + return 1 //Do we have a working jetpack - if(istype(back, /obj/item/weapon/tank/jetpack)) + if(istype(back, /obj/item/weapon/tank/jetpack) && isturf(loc)) //Second check is so you can't use a jetpack in a mech var/obj/item/weapon/tank/jetpack/J = back - if(((!check_drift) || (check_drift && J.stabilization_on)) && (!lying) && (J.allow_thrust(0.01, src))) - inertia_dir = 0 + if((movement_dir || J.stabilization_on) && J.allow_thrust(0.01, src)) return 1 - //If no working jetpack or magboots then use the other checks - if(..()) return 1 + return 0 -/mob/living/carbon/human/Process_Spaceslipping(var/prob_slip = 5) - //If knocked out we might just hit it and stop. This makes it possible to get dead bodies and such. - if(stat) - prob_slip = 0 // Changing this to zero to make it line up with the comment, and also, make more sense. - - //Do we have magboots or such on if so no slip - if(istype(shoes, /obj/item/clothing/shoes/magboots) && (shoes.flags & NOSLIP)) - prob_slip = 0 - - //Check hands and mod slip - if(!l_hand) prob_slip -= 2 - else if(l_hand.w_class <= 2) prob_slip -= 1 - if (!r_hand) prob_slip -= 2 - else if(r_hand.w_class <= 2) prob_slip -= 1 - - prob_slip = round(prob_slip) - return(prob_slip) - - /mob/living/carbon/human/slip(var/s_amount, var/w_amount, var/obj/O, var/lube) if(isobj(shoes) && (shoes.flags&NOSLIP) && !(lube&GALOSHES_DONT_HELP)) return 0 @@ -52,3 +32,11 @@ /mob/living/carbon/human/mob_negates_gravity() return shoes && shoes.negates_gravity() + +/mob/living/carbon/human/Move(NewLoc, direct) + ..() + if(shoes) + if(loc == NewLoc) + var/obj/item/clothing/shoes/S = shoes + S.step_action() + diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index f6eaebd924c..546384be6c1 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -617,13 +617,24 @@ /datum/species/proc/movement_delay(var/mob/living/carbon/human/H) var/mspeed = 0 + if(H.status_flags & GOTTAGOFAST) + mspeed -= 1 if(!has_gravity(H)) - return -1 //It's hard to be slowed down in space by... anything - else if(H.status_flags & GOTTAGOFAST) - return -1 + mspeed += 2 //Carefully propelling yourself along the walls is actually quite slow + + if(istype(H.back, /obj/item/weapon/tank/jetpack)) + var/obj/item/weapon/tank/jetpack/J = H.back + if(J.allow_thrust(0.01, H)) + mspeed -= 3 + + if(H.l_hand) //Having your hands full makes movement harder when you're weightless. You try climbing around while holding a gun! + mspeed += 0.5 + if(H.r_hand) + mspeed += 0.5 + if(H.r_hand && H.l_hand) + mspeed += 0.5 - mspeed = 0 var/health_deficiency = (100 - H.health + H.staminaloss) if(health_deficiency >= 40) mspeed += (health_deficiency / 25) diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm index e3e42effb46..99cb7f8eece 100644 --- a/code/modules/mob/living/carbon/human/species_types.dm +++ b/code/modules/mob/living/carbon/human/species_types.dm @@ -214,10 +214,7 @@ return 1 /datum/species/fly/handle_speech(message) - if(copytext(message, 1, 2) != "*") - message = replacetext(message, "z", stutter("zz")) - - return message + return replacetext(message, "z", stutter("zz")) /* SKELETONS @@ -229,3 +226,30 @@ id = "skeleton" sexes = 0 meat = /obj/item/weapon/reagent_containers/food/snacks/meat/human/mutant/skeleton +/* + ZOMBIES +*/ + +/datum/species/zombie + // 1spooky + name = "Brain-Munching Zombie" + id = "zombie" + say_mod = "moans" + sexes = 0 + meat = /obj/item/weapon/reagent_containers/food/snacks/meat/human/mutant/zombie + +/datum/species/zombie/handle_speech(message) + var/list/message_list = text2list(message, " ") + var/maxchanges = max(round(message_list.len / 1.5), 2) + + for(var/i = rand(maxchanges / 2, maxchanges), i > 0, i--) + var/insertpos = rand(1, message_list.len - 1) + var/inserttext = message_list[insertpos] + + if(!(copytext(inserttext, length(inserttext) - 2) == "...")) + message_list[insertpos] = inserttext + "..." + + if(prob(20) && message_list.len > 3) + message_list.Insert(insertpos, "[pick("BRAINS", "Brains", "Braaaiinnnsss", "BRAAAIIINNSSS")]...") + + return list2text(message_list, " ") diff --git a/code/modules/mob/living/carbon/slime/slime.dm b/code/modules/mob/living/carbon/slime/slime.dm index 3d1a66a3702..3b1095043bc 100644 --- a/code/modules/mob/living/carbon/slime/slime.dm +++ b/code/modules/mob/living/carbon/slime/slime.dm @@ -151,7 +151,7 @@ step(AM, t) now_pushing = null -/mob/living/carbon/slime/Process_Spacemove() +/mob/living/carbon/slime/Process_Spacemove(var/movement_dir = 0) return 2 /mob/living/carbon/slime/Stat() diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 38586236e9a..ed75ad5e894 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -158,19 +158,16 @@ if ("point") if (!src.restrained()) - var/mob/M = null + var/atom/M = null if (param) - for (var/atom/A as mob|obj|turf|area in view(1, src)) + for (var/atom/A as mob|obj|turf in view()) if (param == A.name) M = A break if (!M) message = "[src] points." else - M.point() - if (M) - message = "[src] points to [M]." - else + pointed(M) m_type = 1 if ("scream") diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index f38ccd6007b..b29b0885b40 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -315,9 +315,9 @@ return -/mob/living/Move(a, b, flag) - if (buckled) - return +/mob/living/Move(atom/newloc, direct) + if (buckled && buckled.loc != newloc && !buckled.anchored) + return buckled.Move(newloc, direct) if (restrained()) stop_pulling() @@ -328,7 +328,7 @@ for(var/mob/living/M in range(src, 1)) if ((M.pulling == src && M.stat == 0 && !( M.restrained() ))) t7 = null - if ((t7 && (pulling && ((get_dist(src, pulling) <= 1 || pulling.loc == loc) && (client && client.moving))))) + if (t7 && pulling && (get_dist(src, pulling) <= 1 || pulling.loc == loc)) var/turf/T = loc . = ..() @@ -395,12 +395,12 @@ if(check_dna_integrity(M)) //blood DNA var/mob/living/carbon/DNA_helper = pulling H.blood_DNA[DNA_helper.dna.unique_enzymes] = DNA_helper.dna.blood_type - pulling.Move(T) + pulling.Move(T, get_dir(pulling, T)) if(M) M.start_pulling(t) else if (pulling) - pulling.Move(T) + pulling.Move(T, get_dir(pulling, T)) else stop_pulling() . = ..() diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 78489511a0c..e390d9e58c5 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -31,6 +31,7 @@ var/list/ai_list = list() var/obj/item/device/pda/ai/aiPDA = null var/obj/item/device/multitool/aiMulti = null var/obj/item/device/camera/siliconcam/aicamera = null + var/obj/machinery/bot/Bot //MALFUNCTION var/datum/module_picker/malf_picker @@ -54,6 +55,8 @@ var/list/ai_list = list() var/last_paper_seen = null var/can_shunt = 1 var/last_announcement = "" // For AI VOX, if enabled + var/turf/waypoint //Holds the turf of the currently selected waypoint. + var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking. /mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0) var/list/possibleNames = ai_names @@ -94,7 +97,7 @@ var/list/ai_list = list() if (istype(loc, /turf)) verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \ /mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \ - /mob/living/silicon/ai/proc/toggle_camera_light) + /mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall) if(!safety)//Only used by AIize() to successfully spawn an AI. if (!B)//If there is no player/brain inside. @@ -355,6 +358,24 @@ var/list/ai_list = list() A.ai_actual_track(target) return + if (href_list["callbot"]) //Command a bot to move to a selected location. + Bot = locate(href_list["callbot"]) in machines + if(!Bot || Bot.remote_disabled || src.control_disabled) + return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off. + waypoint_mode = 1 + src << "Set your waypoint by clicking on a valid location free of obstructions." + return + + if (href_list["interface"]) //Remotely connect to a bot! + Bot = locate(href_list["interface"]) in machines + if(!Bot || Bot.remote_disabled || src.control_disabled) + return + Bot.attack_ai(src) + + if (href_list["botrefresh"]) //Refreshes the bot control panel. + botcall() + return + 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 @@ -449,6 +470,61 @@ var/list/ai_list = list() return 1 +/mob/living/silicon/ai/proc/botcall() + set category = "AI Commands" + set name = "Access Robot Control" + set desc = "Wirelessly control various automatic robots." + if(stat == 2) + src << "Critical error. System offline." + return + + if(control_disabled) + src << "Wireless communication is disabled." + return + var/turf/ai_current_turf = get_turf(src) + var/ai_Zlevel = ai_current_turf.z + var/d + var/area/bot_area + d += "Query network status
    " + d += "" + + for (Bot in machines) + if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected! + bot_area = get_area(Bot) + d += "" + //If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all. + d += "" + d += "" + d += "" + d += "" + d += "" + d = format_text(d) + + var/datum/browser/popup = new(src, "botcall", "Remote Robot Control", 700, 400) + popup.set_content(d) + popup.open() + +/mob/living/silicon/ai/proc/set_waypoint(var/atom/A) + var/turf/turf_check = get_turf(A) + //The target must be in view of a camera or near the core. + if(turf_check in range(get_turf(src))) + call_bot(turf_check) + else if(cameranet && cameranet.checkTurfVis(turf_check)) + call_bot(turf_check) + else + src << "Selected location is not visible." + +/mob/living/silicon/ai/proc/call_bot(var/turf/waypoint) + + if(!Bot) + return + + if(Bot.calling_ai && Bot.calling_ai != src) //Prevents an override if another AI is controlling this bot. + src << "Interface error. Unit is already in use." + return + + Bot.call_bot(src, waypoint) + /mob/living/silicon/ai/triggerAlarm(var/class, area/A, var/O, var/alarmsource) if (stat == 2) return 1 diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm index 158d11795fb..fe89288765e 100644 --- a/code/modules/mob/living/silicon/robot/robot_movement.dm +++ b/code/modules/mob/living/silicon/robot/robot_movement.dm @@ -1,4 +1,4 @@ -/mob/living/silicon/robot/Process_Spacemove() +/mob/living/silicon/robot/Process_Spacemove(var/movement_dir = 0) if(module) for(var/obj/item/weapon/tank/jetpack/J in module.modules) if(J && istype(J, /obj/item/weapon/tank/jetpack)) diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index c010d9daf55..4ff94d16b97 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -238,5 +238,5 @@ playstyle_string = "You are a Harvester. You are not strong, but your powers of domination will assist you in your role: \ Bring those who still cling to this world of illusion back to the Geometer so they may know Truth." -/mob/living/simple_animal/construct/harvester/Process_Spacemove(var/check_drift = 0) +/mob/living/simple_animal/construct/harvester/Process_Spacemove(var/movement_dir = 0) return 1 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm index 5cc28028e21..0ac3781a406 100644 --- a/code/modules/mob/living/simple_animal/friendly/crab.dm +++ b/code/modules/mob/living/simple_animal/friendly/crab.dm @@ -28,8 +28,10 @@ if(isturf(src.loc) && !resting && !buckled) //This is so it only moves if it's not inside a closet, gentics machine, etc. turns_since_move++ if(turns_since_move >= turns_per_move) - Move(get_step(src,pick(4,8))) - turns_since_move = 0 + var/east_vs_west = pick(4,8) + if(Process_Spacemove(east_vs_west)) + Move(get_step(src,east_vs_west), east_vs_west) + turns_since_move = 0 regenerate_icons() //COFFEE! SQUEEEEEEEEE! diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index 5883e9ca38c..ebb220c9a72 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -57,7 +57,7 @@ var/step = get_step(src, direction) if(step) if(locate(/obj/effect/spacevine) in step) - Move(step) + Move(step, get_dir(src, step)) /mob/living/simple_animal/hostile/retaliate/goat/Retaliate() ..() diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm index 7953f92cdae..748e216feed 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -54,7 +54,7 @@ else icon_state = "bearfloor" -/mob/living/simple_animal/hostile/bear/Process_Spacemove(var/check_drift = 0) +/mob/living/simple_animal/hostile/bear/Process_Spacemove(var/movement_dir = 0) return 1 //No drifting in space for space bears! /mob/living/simple_animal/hostile/bear/FindTarget() diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm index 24390b58870..a543b85b750 100644 --- a/code/modules/mob/living/simple_animal/hostile/carp.dm +++ b/code/modules/mob/living/simple_animal/hostile/carp.dm @@ -38,7 +38,7 @@ F faction = list("carp") -/mob/living/simple_animal/hostile/carp/Process_Spacemove(var/check_drift = 0) +/mob/living/simple_animal/hostile/carp/Process_Spacemove(var/movement_dir = 0) return 1 //No drifting in space for space carp! //original comments do not steal /mob/living/simple_animal/hostile/carp/FindTarget() diff --git a/code/modules/mob/living/simple_animal/hostile/eyeballs.dm b/code/modules/mob/living/simple_animal/hostile/eyeballs.dm new file mode 100644 index 00000000000..46f2e679e22 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/eyeballs.dm @@ -0,0 +1,34 @@ + + +/mob/living/simple_animal/hostile/carp/eyeball + name = "eyeball" + desc = "An odd looking creature, it won't stop staring..." + icon_state = "eyeball" + icon_living = "eyeball" + icon_dead = "" + icon_gib = "" + meat_type = null + meat_amount = 0 + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "hits" + maxHealth = 45 + health = 45 + + harm_intent_damage = 15 + melee_damage_lower = 20 + melee_damage_upper = 25 + attacktext = "blinks at" + attack_sound = 'sound/weapons/pierce.ogg' + + faction = list("spooky") + + +/mob/living/simple_animal/hostile/carp/eyeball/FindTarget() + . = ..() + if(.) + emote("me", 1, "glares at [.]") + +/mob/living/simple_animal/hostile/carp/eyeball/Die() + qdel(src) + return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/faithless.dm b/code/modules/mob/living/simple_animal/hostile/faithless.dm index 5753a93cb96..b818475bb03 100644 --- a/code/modules/mob/living/simple_animal/hostile/faithless.dm +++ b/code/modules/mob/living/simple_animal/hostile/faithless.dm @@ -31,7 +31,7 @@ faction = list("faithless") -/mob/living/simple_animal/hostile/faithless/Process_Spacemove(var/check_drift = 0) +/mob/living/simple_animal/hostile/faithless/Process_Spacemove(var/movement_dir = 0) return 1 /mob/living/simple_animal/hostile/faithless/FindTarget() diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm index 09deb6c7ba7..de4d1fd2b3b 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -99,7 +99,7 @@ corpse = /obj/effect/landmark/mobcorpse/syndicatecommando speed = 1 -/mob/living/simple_animal/hostile/syndicate/melee/space/Process_Spacemove(var/check_drift = 0) +/mob/living/simple_animal/hostile/syndicate/melee/space/Process_Spacemove(var/movement_dir = 0) return /mob/living/simple_animal/hostile/syndicate/ranged @@ -131,7 +131,7 @@ corpse = /obj/effect/landmark/mobcorpse/syndicatecommando speed = 1 -/mob/living/simple_animal/hostile/syndicate/ranged/space/Process_Spacemove(var/check_drift = 0) +/mob/living/simple_animal/hostile/syndicate/ranged/space/Process_Spacemove(var/movement_dir = 0) return diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 0273aee0275..1b720f37540 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -115,8 +115,10 @@ turns_since_move++ if(turns_since_move >= turns_per_move) if(!(stop_automated_movement_when_pulled && pulledby)) //Soma animals don't move when pulled - Move(get_step(src,pick(cardinal))) - turns_since_move = 0 + var/anydir = pick(cardinal) + if(Process_Spacemove(anydir)) + Move(get_step(src, anydir), anydir) + turns_since_move = 0 //Speaking if(!client && speak_chance) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index a8a5cb65d9b..9e989a38ae7 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -298,6 +298,34 @@ var/list/slot_equipment_priority = list( \ face_atom(A) A.examine(src) +//same as above +/mob/verb/pointed(atom/A as mob|obj|turf in view()) + set name = "Point To" + set category = "Object" + + if(!src || !isturf(src.loc)) + return + if(src.stat || src.restrained()) + return + if(src.status_flags & FAKEDEATH) + return + if(!(A in view(src.loc))) + return + if(istype(A, /obj/effect/decal/point)) + return + + var/tile = get_turf(A) + if (!tile) + return + + var/obj/P = new /obj/effect/decal/point(tile) + spawn (20) + if(P) + P.loc = null + + usr.visible_message("[src] points to [A]") + + /mob/verb/mode() set name = "Activate Held Object" set category = "Object" @@ -703,7 +731,6 @@ var/list/slot_equipment_priority = list( \ canmove = 1 if(buckled) lying = 90 * bed - anchored = buckled else if((ko || resting) && !lying) fall(ko) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index cd9d0a0f0e0..f13d82a7c8e 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -106,8 +106,6 @@ var/coughedtime = null - var/inertia_dir = 0 - var/music_lastplayed = "null" var/job = null//Living diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 5dc9ef9bb79..e0f206cc726 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -86,42 +86,6 @@ return -/atom/movable/Move(NewLoc, direct) - if (direct & (direct - 1)) - if (direct & 1) - if (direct & 4) - if (step(src, NORTH)) - step(src, EAST) - else - if (step(src, EAST)) - step(src, NORTH) - else - if (direct & 8) - if (step(src, NORTH)) - step(src, WEST) - else - if (step(src, WEST)) - step(src, NORTH) - else - if (direct & 2) - if (direct & 4) - if (step(src, SOUTH)) - step(src, EAST) - else - if (step(src, EAST)) - step(src, SOUTH) - else - if (direct & 8) - if (step(src, SOUTH)) - step(src, WEST) - else - if (step(src, WEST)) - step(src, SOUTH) - else - . = ..() - return - - /client/proc/Move_object(direct) if(mob && mob.control_object) if(mob.control_object.density) @@ -167,15 +131,14 @@ if(!mob.lastarea) mob.lastarea = get_area(mob.loc) - if(!has_gravity(mob)) - if(!mob.Process_Spacemove(0)) - return 0 - if(isobj(mob.loc) || ismob(mob.loc)) //Inside an object, tell it we moved var/atom/O = mob.loc return O.relaymove(mob, direct) + if(!mob.Process_Spacemove(direct)) + return 0 + if(isturf(mob.loc)) if(mob.restrained()) //Why being pulled while cuffed prevents you from moving @@ -244,6 +207,8 @@ . = ..() moving = 0 + if(mob && .) + mob.throwing = 0 return . @@ -342,51 +307,46 @@ ///Called by /client/Move() ///For moving in space ///Return 1 for movement 0 for none -/mob/proc/Process_Spacemove(var/check_drift = 0) - //First check to see if we can do things - if(!canmove) - return 0 +/mob/Process_Spacemove(var/movement_dir = 0) - if(!isturf(loc)) //if they're in a disposal unit, for example + if(..()) return 1 - var/dense_object = 0 - for(var/turf/turf in oview(1,src)) - if(istype(turf,/turf/space)) + var/atom/movable/dense_object_backup + for(var/atom/A in orange(1, get_turf(src))) + if(isarea(A)) continue - if(!turf.density && !mob_negates_gravity()) - continue + else if(isturf(A)) + var/turf/turf = A + if(istype(turf,/turf/space)) + continue - dense_object++ - break + if(!turf.density && !mob_negates_gravity()) + continue - if(!dense_object && (locate(/obj/structure/lattice) in oview(1, src))) - dense_object++ + return 1 - //Lastly attempt to locate any dense objects we could push off of - //TODO: If we implement objects drifing in space this needs to really push them - //Due to a few issues only anchored and dense objects will now work. - if(!dense_object) - for(var/obj/O in oview(1, src)) - if((O) && (O.density) && (O.anchored)) - dense_object++ - break + else + var/atom/movable/AM = A + if(AM == buckled) //Kind of unnecessary but let's just be sure + continue + if(AM.density) + if(AM.anchored) + if(istype(AM, /obj/item/projectile)) //"You grab the bullet and push off of it!" No + continue + return 1 + if(pulling == AM) + continue + dense_object_backup = AM - //Nothing to push off of so end here - if(!dense_object) - return 0 + if(movement_dir && dense_object_backup) + if(dense_object_backup.newtonian_move(turn(movement_dir, 180))) //You're pushing off something movable, so it moves + src << "You push off of [dense_object_backup] to propel yourself." - //Check to see if we slipped - if(prob(Process_Spaceslipping(5))) - src << "You slipped!" - src.inertia_dir = src.last_move - step(src, src.inertia_dir) - return 0 - //If not then we can reset inertia and move - inertia_dir = 0 - return 1 + return 1 + return 0 /mob/proc/mob_has_gravity(turf/T) return has_gravity(src, T) @@ -394,15 +354,6 @@ /mob/proc/mob_negates_gravity() return 0 -/mob/proc/Process_Spaceslipping(var/prob_slip = 5) - //Setup slipage - //If knocked out we might just hit it and stop. This makes it possible to get dead bodies and such. - if(stat) - prob_slip = 0 // Changing this to zero to make it line up with the comment. - - prob_slip = round(prob_slip) - return(prob_slip) - /mob/proc/Move_Pulled(var/atom/A) if (!canmove || restrained() || !pulling) return @@ -410,6 +361,10 @@ return if (!pulling.Adjacent(src)) return + if (A == loc && pulling.density) + return + if (!Process_Spacemove(get_dir(pulling.loc, A))) + return if (ismob(pulling)) var/mob/M = pulling var/atom/movable/t = M.pulling diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 369c7aea7d3..9108b61c8ea 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -259,10 +259,7 @@ movement_dir = get_dir(src,target) //moves to a singulo beacon, if there is one if(current_size >= 9)//The superlarge one does not care about things in its way - spawn(0) - step(src, movement_dir) - spawn(1) - step(src, movement_dir) + step(src, movement_dir) return 1 else if(check_turfs_in(movement_dir)) last_failed_movement = 0//Reset this because we moved @@ -407,4 +404,4 @@ var/dist = max((current_size - 2),1) explosion(src.loc,(dist),(dist*2),(dist*4)) qdel(src) - return(gain) \ No newline at end of file + return(gain) diff --git a/code/modules/projectiles/firing.dm b/code/modules/projectiles/firing.dm index 652aaf954f6..e99ce0b32eb 100644 --- a/code/modules/projectiles/firing.dm +++ b/code/modules/projectiles/firing.dm @@ -11,6 +11,7 @@ if(i > 1) newshot() user.changeNext_move(CLICK_CD_RANGE) + user.newtonian_move(get_dir(target, user)) update_icon() return 1 diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 54338aa0f80..69f63100241 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -137,6 +137,9 @@ else return 1 +/obj/item/projectile/Process_Spacemove(var/movement_dir = 0) + return 1 //Bullets don't drift in space + /obj/item/projectile/process() if(kill_count < 1) diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 87b82950be1..ddfb006ba68 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -58,6 +58,7 @@ playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6) user.changeNext_move(CLICK_CD_RANGE) + user.newtonian_move(get_dir(A, user)) if(reagents.has_reagent("sacid")) message_admins("[key_name_admin(user)] fired sulphuric acid from \a [src].") diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index 23f5e34ec0a..3f8c1819d04 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -6,6 +6,7 @@ density = 1 mouse_drag_pointer = MOUSE_ACTIVE_POINTER var/obj/wrapped = null + var/giftwrapped = 0 var/sortTag = 0 @@ -41,12 +42,19 @@ user.visible_message("[user] labels [src] as [str].") name = "[name] ([str])" - else if(istype(W, /obj/item/stack/wrapping_paper)) - user.visible_message("[user] wraps the package in festive paper!") - if(istype(wrapped, /obj/structure/closet/crate)) - icon_state = "giftcrate" + else if(istype(W, /obj/item/stack/wrapping_paper) && !giftwrapped) + var/obj/item/stack/wrapping_paper/WP = W + if(WP.use(3)) + user.visible_message("[user] wraps the package in festive paper!") + giftwrapped = 1 + if(istype(wrapped, /obj/structure/closet/crate)) + icon_state = "giftcrate" + else + icon_state = "giftcloset" + if(WP.amount <= 0 && !WP.loc) //if we used our last wrapping paper, drop a cardboard tube + new /obj/item/weapon/c_tube( get_turf(user) ) else - icon_state = "giftcloset" + user << "You need more paper." /obj/item/smallDelivery @@ -55,11 +63,12 @@ icon = 'icons/obj/storage.dmi' icon_state = "deliverycrateSmall" var/obj/item/wrapped = null + var/giftwrapped = 0 var/sortTag = 0 /obj/item/smallDelivery/attack_self(mob/user as mob) - if(wrapped) //sometimes items can disappear. For example, bombs. --rastaf0 + if(wrapped && wrapped.loc) //sometimes items can disappear. For example, bombs. --rastaf0 wrapped.loc = user.loc if(ishuman(user)) user.put_in_hands(wrapped) @@ -87,9 +96,17 @@ user.visible_message("[user] labels [src] as [str].") name = "[name] ([str])" - else if(istype(W, /obj/item/stack/wrapping_paper)) - icon_state = "giftcrate[wrapped.w_class]" - user.visible_message("[user] wraps the package in festive paper!") + else if(istype(W, /obj/item/stack/wrapping_paper) && !giftwrapped) + var/obj/item/stack/wrapping_paper/WP = W + if(WP.use(1)) + icon_state = "giftcrate[wrapped.w_class]" + giftwrapped = 1 + user.visible_message("[user] wraps the package in festive paper!") + if(WP.amount <= 0 && !WP.loc) //if we used our last wrapping paper, drop a cardboard tube + new /obj/item/weapon/c_tube( get_turf(user) ) + else + user << "You need more paper." + /obj/item/stack/packageWrap @@ -97,8 +114,8 @@ icon = 'icons/obj/items.dmi' icon_state = "deliveryPaper" flags = NOBLUDGEON - w_class = 3.0 amount = 25 + max_amount = 25 /obj/item/stack/packageWrap/afterattack(var/obj/target as obj, mob/user as mob, proximity) @@ -113,11 +130,11 @@ if(target in user) return - user.attack_log += text("\[[time_stamp()]\] Has used [name] on \ref[target]") + if(istype(target, /obj/item) && !(istype(target, /obj/item/weapon/storage) && !istype(target,/obj/item/weapon/storage/box))) var/obj/item/O = target - if(amount > 1) + if(use(1)) var/obj/item/smallDelivery/P = new /obj/item/smallDelivery(get_turf(O.loc)) //Aaannd wrap it up! if(!istype(O.loc, /turf)) if(user.client) @@ -131,33 +148,41 @@ P.add_fingerprint(usr) O.add_fingerprint(usr) add_fingerprint(usr) - amount -= 1 + else + return else if(istype(target, /obj/structure/closet/crate)) var/obj/structure/closet/crate/O = target - if(amount > 3 && !O.opened) + if(O.opened) + return + if(use(3)) var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc)) P.icon_state = "deliverycrate" P.wrapped = O O.loc = P - amount -= 3 - else if(amount < 3) + else user << "You need more paper." + return else if(istype (target, /obj/structure/closet)) var/obj/structure/closet/O = target - if(amount > 3 && !O.opened) + if(O.opened) + return + if(use(3)) var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc)) P.wrapped = O O.welded = 1 O.loc = P - amount -= 3 - else if(amount < 3) + else user << "You need more paper." + return else user << "The object you are trying to wrap is unsuitable for the sorting machinery." - if(amount <= 0) - new /obj/item/weapon/c_tube( loc ) - qdel(src) return + + user.visible_message("[user] wraps [target].") + user.attack_log += text("\[[time_stamp()]\] Has used [name] on [target]") + + if(amount <= 0 && !src.loc) //if we used our last wrapping paper, drop a cardboard tube + new /obj/item/weapon/c_tube( get_turf(user) ) return diff --git a/config/admins.txt b/config/admins.txt index 31a3f30183c..34d7fe5b413 100644 --- a/config/admins.txt +++ b/config/admins.txt @@ -65,4 +65,5 @@ paprka = Game Master cookingboy3 = Game Master limeliz = Game Master steelpoint = Game Master -phil235 = Game Master \ No newline at end of file +phil235 = Game Master +xxnoob = Game Master \ No newline at end of file diff --git a/html/changelog.html b/html/changelog.html index b3528ac9971..bb75a0bf2cb 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,37 @@ --> +
    +

    27 October 2014

    +

    Jordie0608 updated:

    +
      +
    • Adds a new riot shotgun that spawns in the armory with a 6 round beanbag magazine.
    • +
    +

    Paprika updated:

    +
      +
    • Allowed constructs to assist in activating most runes. This includes conversion runes, but does NOT include sacrifice runes.
    • +
    +

    Patchouli Knowledge updated:

    +
      +
    • In light of the recent achievements of the Robotics department, new and upgraded exosuit schematics were delivered to SS13 exosuit fabricators as a reward from CentComm.
    • +
    • The countless hours of research, experimentation, and reverse-engineering of wrecks from the mining asteroid have paid off - the Research team has rediscovered the process of building Phazon exosuits. The parts and circuits have been made available in the exofabs and circuit printers.
    • +
    • The APLU Ripley exosuit has been refitted with asteroid mining purposes in mind. Its armour plating will provide extra protection against the brute attacks of asteroid alien lifeforms, and protect from gibtonite explosions. The leg servos were upgraded to provide faster movement.
    • +
    • There are rumours of some creative shaft miners discovering a way of augmenting APLU Ripley armour with trophy hides from goliath-type asteroid lifeforms...
    • +
    • Durand construction routines now require a phasic scanner module and a super capacitor to match Nanotrasen industry standards.
    • +
    • The exosuit fire extinguisher now boasts a larger watertank, and carries a whole 1000u of water from the old 200u tank.
    • +
    • The exosuit plasma converter's efficiency has been vastly improved upon, and its fuel consumption has been cut to nearly half of old values.
    • +
    • The exosuit sleeper interiors have been refitted to allow the occupants more freedom of movement, and the occupants may now eject at will.
    • +
    • The armour plating on all exosuits was fitted with reactive deflection systems specifically designed to stop the rapid slashes from xenomorph threats.
    • +
    • The Firefighter Ripley chassis were moved from the Exosuit Equipment section to the APLU Ripley section of exofab menus.
    • +
    • Fixed some minor errors in the exosuit construction message syntax.
    • +
    +

    phil235 updated:

    +
      +
    • Closets and its children can no longer contain a near infinite amount of mobs. Large mobs (juggernaut, alien emperess, etc) don't fit, small mobs (mouse, parrot, etc) still fit in the same amounts, human-sized mob (humanoid, slime, etc) fit but maximum two per body bag and three for all the other closets. Adding bluespace body bag to R&D, it can hold even large mobs and in large amounts.
    • +
    • girders and displaced girders now have a chance to let projectiles pass through them.
    • +
    +
    +

    19 October 2014

    Donkie updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index bce08847b4b..e5ed90c6360 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -1992,3 +1992,45 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. to encourage janitors to warn crewmembers about wet floors. optimumtact: - rscadd: Medical supplies crate now comes with a boxy full of bodybags +2014-10-27: + Jordie0608: + - rscadd: Adds a new riot shotgun that spawns in the armory with a 6 round beanbag + magazine. + Paprika: + - experiment: Allowed constructs to assist in activating most runes. This includes + conversion runes, but does NOT include sacrifice runes. + Patchouli Knowledge: + - rscadd: In light of the recent achievements of the Robotics department, new and + upgraded exosuit schematics were delivered to SS13 exosuit fabricators as a + reward from CentComm. + - rscadd: The countless hours of research, experimentation, and reverse-engineering + of wrecks from the mining asteroid have paid off - the Research team has rediscovered + the process of building Phazon exosuits. The parts and circuits have been made + available in the exofabs and circuit printers. + - rscadd: The APLU Ripley exosuit has been refitted with asteroid mining purposes + in mind. Its armour plating will provide extra protection against the brute + attacks of asteroid alien lifeforms, and protect from gibtonite explosions. + The leg servos were upgraded to provide faster movement. + - rscadd: There are rumours of some creative shaft miners discovering a way of augmenting + APLU Ripley armour with trophy hides from goliath-type asteroid lifeforms... + - tweak: Durand construction routines now require a phasic scanner module and a + super capacitor to match Nanotrasen industry standards. + - tweak: The exosuit fire extinguisher now boasts a larger watertank, and carries + a whole 1000u of water from the old 200u tank. + - tweak: The exosuit plasma converter's efficiency has been vastly improved upon, + and its fuel consumption has been cut to nearly half of old values. + - bugfix: The exosuit sleeper interiors have been refitted to allow the occupants + more freedom of movement, and the occupants may now eject at will. + - bugfix: The armour plating on all exosuits was fitted with reactive deflection + systems specifically designed to stop the rapid slashes from xenomorph threats. + - bugfix: The Firefighter Ripley chassis were moved from the Exosuit Equipment section + to the APLU Ripley section of exofab menus. + - spellcheck: Fixed some minor errors in the exosuit construction message syntax. + phil235: + - rscadd: Closets and its children can no longer contain a near infinite amount + of mobs. Large mobs (juggernaut, alien emperess, etc) don't fit, small mobs + (mouse, parrot, etc) still fit in the same amounts, human-sized mob (humanoid, + slime, etc) fit but maximum two per body bag and three for all the other closets. + Adding bluespace body bag to R&D, it can hold even large mobs and in large amounts. + - experiment: girders and displaced girders now have a chance to let projectiles + pass through them. diff --git a/html/changelogs/Jordie0608-PR-5231.yml b/html/changelogs/Jordie0608-PR-5231.yml deleted file mode 100644 index 037185af189..00000000000 --- a/html/changelogs/Jordie0608-PR-5231.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: Jordie0608 - -delete-after: True - -changes: - - rscadd: Adds a new riot shotgun that spawns in the armory with a 6 round beanbag magazine. \ No newline at end of file diff --git a/html/changelogs/MrPerson.yml b/html/changelogs/MrPerson.yml index 6378584f30e..4f610d483e2 100644 --- a/html/changelogs/MrPerson.yml +++ b/html/changelogs/MrPerson.yml @@ -1,2 +1,8 @@ author: MrPerson -changes: [] +changes: + - rscadd: "Everything now drifts in space, not just mobs." + - rscadd: "Mechs are just as maneuverable in space as you are." + - tweak: "Being weightless now slows movement down by a lot rather than speeding it up. Having your hands full will make movement even slower." + - rscdel: "Removed spaceslipping (You slipped! x1000)" + - bugfix: "Jetpacking after being thrown out a mass driver will cancel out your momentum." + - bugfix: "Shooting a gun causes you to drift the other direction like spraying a fire extinguisher." \ No newline at end of file diff --git a/html/changelogs/Paprka-PR-5179.yml b/html/changelogs/Paprka-PR-5179.yml deleted file mode 100644 index 09edf6384ea..00000000000 --- a/html/changelogs/Paprka-PR-5179.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Paprika -delete-after: True -changes: - - experiment: "Allowed constructs to assist in activating most runes. This includes conversion runes, but does NOT include sacrifice runes." \ No newline at end of file diff --git a/html/changelogs/Patchi-mechs-phazons.yml b/html/changelogs/Patchi-mechs-phazons.yml deleted file mode 100644 index 7990ef7ea6d..00000000000 --- a/html/changelogs/Patchi-mechs-phazons.yml +++ /dev/null @@ -1,14 +0,0 @@ -author: Patchouli Knowledge -delete-after: true -changes: - - rscadd: "In light of the recent achievements of the Robotics department, new and upgraded exosuit schematics were delivered to SS13 exosuit fabricators as a reward from CentComm. - - rscadd: "The countless hours of research, experimentation, and reverse-engineering of wrecks from the mining asteroid have paid off - the Research team has rediscovered the process of building Phazon exosuits. The parts and circuits have been made available in the exofabs and circuit printers." - - rscadd: "The APLU Ripley exosuit has been refitted with asteroid mining purposes in mind. Its armour plating will provide extra protection against the brute attacks of asteroid alien lifeforms, and protect from gibtonite explosions. The leg servos were upgraded to provide faster movement." - - rscadd: "There are rumours of some creative shaft miners discovering a way of augmenting APLU Ripley armour with trophy hides from goliath-type asteroid lifeforms..." - - tweak: "Durand construction routines now require a phasic scanner module and a super capacitor to match Nanotrasen industry standards." - - tweak: "The exosuit fire extinguisher now boasts a larger watertank, and carries a whole 1000u of water from the old 200u tank." - - tweak: "The exosuit plasma converter's efficiency has been vastly improved upon, and its fuel consumption has been cut to nearly half of old values." - - bugfix: "The exosuit sleeper interiors have been refitted to allow the occupants more freedom of movement, and the occupants may now eject at will. - - bugfix: "The armour plating on all exosuits was fitted with reactive deflection systems specifically designed to stop the rapid slashes from xenomorph threats." - - bugfix: "The Firefighter Ripley chassis were moved from the Exosuit Equipment section to the APLU Ripley section of exofab menus." - - spellcheck: "Fixed some minor errors in the exosuit construction message syntax." \ No newline at end of file diff --git a/html/changelogs/phil235-PR-5216.yml b/html/changelogs/phil235-PR-5216.yml deleted file mode 100644 index acb18141530..00000000000 --- a/html/changelogs/phil235-PR-5216.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: phil235 -delete-after: True -changes: - - rscadd: "Closets and its children can no longer contain a near infinite amount of mobs. Large mobs (juggernaut, alien emperess, etc) don't fit, small mobs (mouse, parrot, etc) still fit in the same amounts, human-sized mob (humanoid, slime, etc) fit but maximum two per body bag and three for all the other closets. Adding bluespace body bag to R&D, it can hold even large mobs and in large amounts." \ No newline at end of file diff --git a/html/changelogs/phil235-PR-5249.yml b/html/changelogs/phil235-PR-5249.yml deleted file mode 100644 index 1a93df0ddf6..00000000000 --- a/html/changelogs/phil235-PR-5249.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: phil235 -delete-after: True -changes: - - experiment: "girders and displaced girders now have a chance to let projectiles pass through them." \ No newline at end of file diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi index 6466f049aed..0547d648086 100644 Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 64d5b519ad0..41b93e38b63 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi index 8b586b4fab9..ff3073b2ddd 100644 Binary files a/icons/mob/human.dmi and b/icons/mob/human.dmi differ diff --git a/icons/obj/aibots.dmi b/icons/obj/aibots.dmi index 7b559aad634..7039ec43103 100644 Binary files a/icons/obj/aibots.dmi and b/icons/obj/aibots.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 11520ec0f35..602df9fc9d0 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/halloween_items.dmi b/icons/obj/halloween_items.dmi new file mode 100644 index 00000000000..c08ea711488 Binary files /dev/null and b/icons/obj/halloween_items.dmi differ diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi index 7c4e43a241c..c03fa5e244e 100644 Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ diff --git a/icons/obj/library.dmi b/icons/obj/library.dmi index ed57a390a27..042bda052f6 100644 Binary files a/icons/obj/library.dmi and b/icons/obj/library.dmi differ diff --git a/icons/obj/meteor_spooky.dmi b/icons/obj/meteor_spooky.dmi new file mode 100644 index 00000000000..287d5b47bd0 Binary files /dev/null and b/icons/obj/meteor_spooky.dmi differ diff --git a/icons/pda_icons/pda_cleanbot.png b/icons/pda_icons/pda_cleanbot.png new file mode 100644 index 00000000000..cecbcf40773 Binary files /dev/null and b/icons/pda_icons/pda_cleanbot.png differ diff --git a/icons/pda_icons/pda_floorbot.png b/icons/pda_icons/pda_floorbot.png new file mode 100644 index 00000000000..999e45aed25 Binary files /dev/null and b/icons/pda_icons/pda_floorbot.png differ diff --git a/icons/pda_icons/pda_medbot.png b/icons/pda_icons/pda_medbot.png new file mode 100644 index 00000000000..24ae212be2e Binary files /dev/null and b/icons/pda_icons/pda_medbot.png differ diff --git a/sound/spookoween/bats.ogg b/sound/spookoween/bats.ogg new file mode 100644 index 00000000000..fb428debcb3 Binary files /dev/null and b/sound/spookoween/bats.ogg differ diff --git a/sound/spookoween/chain_rattling.ogg b/sound/spookoween/chain_rattling.ogg new file mode 100644 index 00000000000..9ff9913b2b2 Binary files /dev/null and b/sound/spookoween/chain_rattling.ogg differ diff --git a/sound/spookoween/ghost_whisper.ogg b/sound/spookoween/ghost_whisper.ogg new file mode 100644 index 00000000000..660b04c786d Binary files /dev/null and b/sound/spookoween/ghost_whisper.ogg differ diff --git a/sound/spookoween/ghosty_wind.ogg b/sound/spookoween/ghosty_wind.ogg new file mode 100644 index 00000000000..b1c8c2f3a8c Binary files /dev/null and b/sound/spookoween/ghosty_wind.ogg differ diff --git a/sound/spookoween/girlscream.ogg b/sound/spookoween/girlscream.ogg new file mode 100644 index 00000000000..8ded518f47f Binary files /dev/null and b/sound/spookoween/girlscream.ogg differ diff --git a/sound/spookoween/insane_low_laugh.ogg b/sound/spookoween/insane_low_laugh.ogg new file mode 100644 index 00000000000..6f1ba277783 Binary files /dev/null and b/sound/spookoween/insane_low_laugh.ogg differ diff --git a/sound/spookoween/scary_clown_appear.ogg b/sound/spookoween/scary_clown_appear.ogg new file mode 100644 index 00000000000..05ab18f70b0 Binary files /dev/null and b/sound/spookoween/scary_clown_appear.ogg differ diff --git a/sound/spookoween/scary_horn.ogg b/sound/spookoween/scary_horn.ogg new file mode 100644 index 00000000000..a0b05821bb2 Binary files /dev/null and b/sound/spookoween/scary_horn.ogg differ diff --git a/sound/spookoween/scary_horn2.ogg b/sound/spookoween/scary_horn2.ogg new file mode 100644 index 00000000000..fb2805bd2cd Binary files /dev/null and b/sound/spookoween/scary_horn2.ogg differ diff --git a/sound/spookoween/scary_horn3.ogg b/sound/spookoween/scary_horn3.ogg new file mode 100644 index 00000000000..0aaefe1583a Binary files /dev/null and b/sound/spookoween/scary_horn3.ogg differ diff --git a/tgstation.dme b/tgstation.dme index fbfeef2b539..32a302e49de 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1113,6 +1113,7 @@ #include "code\modules\mob\living\simple_animal\hostile\bear.dm" #include "code\modules\mob\living\simple_animal\hostile\carp.dm" #include "code\modules\mob\living\simple_animal\hostile\creature.dm" +#include "code\modules\mob\living\simple_animal\hostile\eyeballs.dm" #include "code\modules\mob\living\simple_animal\hostile\faithless.dm" #include "code\modules\mob\living\simple_animal\hostile\giant_spider.dm" #include "code\modules\mob\living\simple_animal\hostile\hivebot.dm"

    Name

    Status

    Location

    Control

    [Bot.hacked ? "(!) [Bot.name]" : Bot.name][Bot.on ? "[Bot.mode ? "[ Bot.mode_name[Bot.mode] ]": "Idle"]" : "Inactive"][bot_area.name]InterfaceCall