diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm index 8c31d589343aa4..5c9336c5c5ca4b 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm @@ -812,7 +812,7 @@ /turf/open/floor/engine/vacuum, /area/ruin/planetengi) "yF" = ( -/mob/living/simple_animal/hostile/construct/proteon, +/mob/living/basic/construct/proteon, /turf/open/floor/iron, /area/ruin/planetengi) "Ai" = ( @@ -823,7 +823,7 @@ /turf/open/floor/iron/icemoon, /area/ruin/planetengi) "Iy" = ( -/mob/living/simple_animal/hostile/construct/proteon, +/mob/living/basic/construct/proteon, /obj/effect/turf_decal/tile/yellow, /turf/open/floor/iron/icemoon, /area/ruin/planetengi) diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_gas.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_gas.dmm new file mode 100644 index 00000000000000..a70a0decb47453 --- /dev/null +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_gas.dmm @@ -0,0 +1,1348 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aN" = ( +/obj/machinery/door/airlock/material/glass, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/general, +/obj/machinery/duct, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"aR" = ( +/obj/effect/spawner/structure/window, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"bn" = ( +/obj/structure/closet/crate/trashcart/filled, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"bJ" = ( +/obj/machinery/light/cold/directional/north, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"cv" = ( +/obj/effect/spawner/random/trash/food_packaging, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"cE" = ( +/obj/effect/spawner/random/trash/cigbutt, +/obj/machinery/duct, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"cF" = ( +/obj/structure/rack, +/obj/item/food/cornchips/blue{ + pixel_x = -5; + pixel_y = -5 + }, +/obj/item/food/cornchips/blue{ + pixel_x = -5; + pixel_y = 5 + }, +/obj/item/food/cornchips/blue{ + pixel_x = -5; + pixel_y = 3 + }, +/obj/item/food/cornchips/blue{ + pixel_x = -5; + pixel_y = 1 + }, +/obj/item/food/cornchips/blue{ + pixel_x = -5; + pixel_y = -1 + }, +/obj/item/food/cornchips/blue{ + pixel_x = -5; + pixel_y = -3 + }, +/obj/item/food/cornchips/green{ + pixel_x = 8; + pixel_y = -5 + }, +/obj/item/food/cornchips/green{ + pixel_x = 8; + pixel_y = 5 + }, +/obj/item/food/cornchips/green{ + pixel_x = 8; + pixel_y = 3 + }, +/obj/item/food/cornchips/green{ + pixel_x = 8; + pixel_y = 1 + }, +/obj/item/food/cornchips/green{ + pixel_x = 8; + pixel_y = -1 + }, +/obj/item/food/cornchips/green{ + pixel_x = 8; + pixel_y = -3 + }, +/obj/item/food/cornchips/red{ + pixel_y = -5 + }, +/obj/item/food/cornchips/red{ + pixel_y = 5 + }, +/obj/item/food/cornchips/red{ + pixel_y = 3 + }, +/obj/item/food/cornchips/red{ + pixel_y = 1 + }, +/obj/item/food/cornchips/red{ + pixel_y = -1 + }, +/obj/item/food/cornchips/red{ + pixel_y = -3 + }, +/obj/item/food/cornchips/purple{ + pixel_y = -4 + }, +/obj/item/food/cornchips/purple{ + pixel_y = 4 + }, +/obj/item/food/cornchips/purple, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"cI" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/sink/directional/west, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"dd" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/cable, +/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/on, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"ed" = ( +/obj/effect/spawner/random/structure/crate_empty, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"es" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/general/hidden, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"eF" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/duct, +/obj/structure/sign/poster/fluff/lizards_gas_power/directional/west, +/obj/item/vending_refill/cigarette, +/obj/item/vending_refill/cola, +/obj/item/vending_refill/snack, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"eM" = ( +/obj/structure/fans/tiny/invisible, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"eZ" = ( +/obj/structure/rack, +/obj/item/food/cornuto, +/obj/item/food/cornuto{ + pixel_y = 3; + pixel_x = -6 + }, +/obj/item/food/cornuto{ + pixel_y = -2; + pixel_x = 6 + }, +/obj/item/food/cornuto{ + pixel_y = 2; + pixel_x = 6 + }, +/obj/item/food/cornuto{ + pixel_y = 2; + pixel_x = -6 + }, +/obj/machinery/duct, +/obj/structure/window/spawner/directional/east, +/obj/machinery/door/window/left/directional/north, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, +/area/ruin/powered/lizard_gas) +"gm" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/table/reinforced, +/obj/structure/sign/poster/official/midtown_slice/directional/east, +/obj/item/food/taco{ + pixel_x = 5 + }, +/obj/item/food/hotdog{ + pixel_y = 4; + pixel_x = -7 + }, +/obj/structure/window/spawner/directional/north, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"gv" = ( +/turf/template_noop, +/area/template_noop) +"gW" = ( +/obj/structure/sink/directional/east, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"ih" = ( +/obj/structure/sign/poster/fluff/lizards_gas_payment/directional/east, +/mob/living/basic/lizard/space, +/obj/machinery/light/cold/directional/east, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"iS" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/general, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"jD" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/duct, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"jQ" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"kc" = ( +/obj/machinery/door/airlock/multi_tile/public/glass{ + dir = 4 + }, +/obj/structure/cable, +/obj/structure/fans/tiny/invisible, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"ku" = ( +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"kI" = ( +/obj/effect/spawner/random/trash/grille_or_waste, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"kS" = ( +/obj/machinery/duct, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"kT" = ( +/obj/structure/table, +/obj/item/reagent_containers/spray/cleaner{ + pixel_x = 4; + pixel_y = 2 + }, +/obj/item/reagent_containers/spray/cleaner{ + pixel_x = -4; + pixel_y = 2 + }, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"lK" = ( +/obj/structure/cable, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"ma" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/cable, +/obj/effect/spawner/random/trash/food_packaging, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"mE" = ( +/obj/structure/bonfire/prelit, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"oo" = ( +/turf/closed/wall, +/area/ruin/powered/lizard_gas) +"oy" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/table/reinforced, +/obj/effect/spawner/random/entertainment/cigarette_pack, +/obj/effect/spawner/random/entertainment/cigarette_pack, +/obj/effect/spawner/random/entertainment/cigarette_pack, +/obj/effect/spawner/random/entertainment/cigarette_pack, +/obj/effect/spawner/random/entertainment/cigarette_pack, +/obj/effect/spawner/random/entertainment/cigarette_pack, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"pL" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/general/hidden, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"pO" = ( +/obj/effect/spawner/random/trash/hobo_squat, +/turf/open/misc/asteroid/snow/icemoon, +/area/ruin/powered/lizard_gas) +"qM" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/machinery/duct, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"rh" = ( +/obj/effect/turf_decal/loading_area{ + dir = 8 + }, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"sm" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/general, +/obj/machinery/duct, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"sn" = ( +/obj/structure/rack, +/obj/machinery/duct, +/obj/item/storage/cans/sixsoda{ + pixel_y = -1 + }, +/obj/item/storage/cans/sixsoda, +/obj/machinery/door/window/left/directional/north, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, +/area/ruin/powered/lizard_gas) +"sQ" = ( +/obj/effect/spawner/random/structure/grille, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"sU" = ( +/obj/structure/barricade/wooden/snowed, +/obj/structure/barricade/wooden/crude/snow, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"tx" = ( +/obj/effect/turf_decal/delivery, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"tW" = ( +/obj/machinery/atmospherics/components/tank/air, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"ul" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/light/cold/directional/east, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"ur" = ( +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/unexplored) +"uv" = ( +/obj/structure/shipping_container/donk_co, +/turf/open/misc/asteroid/snow/icemoon, +/area/ruin/powered/lizard_gas) +"vA" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/sign/poster/official/jim_nortons/directional/south, +/obj/machinery/light/cold/directional/south, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"wK" = ( +/obj/machinery/space_heater, +/obj/structure/cable, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"wN" = ( +/obj/effect/spawner/random/structure/crate_empty, +/turf/open/misc/asteroid/snow/icemoon, +/area/ruin/powered/lizard_gas) +"wU" = ( +/obj/structure/table/reinforced, +/obj/item/food/croissant{ + pixel_x = -4; + pixel_y = 4 + }, +/obj/item/food/breadslice/banana{ + pixel_x = 4; + pixel_y = 3 + }, +/obj/item/food/butterbiscuit, +/obj/structure/window/spawner/directional/north, +/obj/structure/window/spawner/directional/west, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"xw" = ( +/obj/machinery/door/airlock/external/ruin, +/obj/effect/mapping_helpers/airlock/locked, +/obj/structure/fans/tiny/invisible, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"xK" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"xN" = ( +/obj/machinery/atmospherics/components/unary/thermomachine/heater/on, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"yG" = ( +/obj/structure/rack, +/obj/item/reagent_containers/condiment/vegetable_oil, +/obj/item/reagent_containers/condiment/vegetable_oil{ + pixel_x = 4 + }, +/obj/item/reagent_containers/condiment/vegetable_oil{ + pixel_x = -4 + }, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"yH" = ( +/obj/structure/reagent_dispensers/plumbed/fuel, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"zh" = ( +/obj/structure/table, +/obj/item/reagent_containers/cup/bucket{ + pixel_y = 2 + }, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"zm" = ( +/obj/machinery/light/cold/directional/east, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"zJ" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"zL" = ( +/obj/effect/spawner/random/vending/colavend, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"Ao" = ( +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"AM" = ( +/obj/structure/mineral_door/wood, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"Bc" = ( +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"CW" = ( +/obj/machinery/duct, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"El" = ( +/obj/structure/table, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"Ez" = ( +/obj/structure/billboard/roadsign/twothousand, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/unexplored) +"Fp" = ( +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"FP" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/decal/cleanable/dirt, +/obj/structure/rack, +/obj/machinery/light/cold/directional/north, +/obj/item/storage/fancy/donut_box{ + pixel_y = -2 + }, +/obj/item/storage/fancy/donut_box{ + pixel_y = 6 + }, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"GO" = ( +/obj/structure/water_source/puddle, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/unexplored) +"HE" = ( +/turf/open/misc/asteroid/snow/icemoon, +/area/ruin/powered/lizard_gas) +"HI" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/on{ + dir = 8 + }, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"IF" = ( +/obj/machinery/light/cold/directional/east, +/obj/machinery/vending/cigarette, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"Ji" = ( +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/unexplored) +"Jv" = ( +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"KG" = ( +/obj/effect/spawner/random/structure/grille, +/turf/open/misc/asteroid/snow/icemoon, +/area/ruin/powered/lizard_gas) +"Lh" = ( +/obj/structure/barricade/wooden/snowed, +/obj/structure/barricade/wooden/crude/snow, +/turf/open/misc/asteroid/snow/icemoon, +/area/ruin/powered/lizard_gas) +"LG" = ( +/obj/structure/billboard/lizards_gas, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/unexplored) +"LP" = ( +/obj/structure/mop_bucket, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/unexplored) +"Md" = ( +/obj/effect/spawner/random/structure/crate_abandoned, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"Mz" = ( +/obj/machinery/light/cold/directional/south, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"MA" = ( +/obj/structure/rack, +/obj/item/storage/box/matches{ + pixel_x = 3; + pixel_y = 4 + }, +/obj/item/storage/box/matches{ + pixel_x = -3; + pixel_y = 4 + }, +/obj/effect/spawner/random/entertainment/lighter, +/obj/effect/spawner/random/entertainment/lighter, +/obj/structure/cable, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"Py" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/table, +/obj/machinery/coffeemaker, +/obj/machinery/atmospherics/pipe/smart/manifold4w/general, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"QI" = ( +/obj/structure/table/reinforced, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"QK" = ( +/obj/structure/cable, +/obj/structure/rack, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/item/storage/cans/sixbeer{ + pixel_y = 8 + }, +/obj/item/storage/cans/sixbeer{ + pixel_y = -1 + }, +/obj/machinery/door/window/left/directional/south, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, +/area/ruin/powered/lizard_gas) +"QQ" = ( +/obj/structure/sign/poster/official/fruit_bowl/directional/north, +/obj/structure/rack, +/obj/item/grenade/firecracker{ + pixel_x = 5; + pixel_y = 7 + }, +/obj/item/grenade/firecracker{ + pixel_x = 5; + pixel_y = -7 + }, +/obj/item/grenade/firecracker{ + pixel_x = 5 + }, +/obj/item/grenade/firecracker{ + pixel_x = -6; + pixel_y = 7 + }, +/obj/item/grenade/firecracker{ + pixel_y = -7; + pixel_x = -6 + }, +/obj/item/grenade/firecracker{ + pixel_x = -6 + }, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"Rc" = ( +/obj/structure/shipping_container/nanotrasen, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"Rs" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/general, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"RC" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/power/apc/auto_name/directional/south, +/obj/machinery/power/terminal, +/obj/effect/mapping_helpers/apc/full_charge, +/obj/effect/mapping_helpers/apc/cell_10k, +/obj/effect/mapping_helpers/apc/unlocked, +/obj/machinery/power/port_gen/pacman/pre_loaded, +/obj/structure/cable, +/obj/machinery/duct, +/turf/open/floor/plating, +/area/ruin/powered/lizard_gas) +"RD" = ( +/obj/structure/cable, +/turf/closed/wall, +/area/ruin/powered/lizard_gas) +"RE" = ( +/obj/machinery/light/cold/directional/east, +/obj/effect/spawner/random/vending/snackvend, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) +"RW" = ( +/obj/effect/spawner/random/structure/crate_loot, +/turf/open/misc/asteroid/snow/icemoon, +/area/ruin/powered/lizard_gas) +"SZ" = ( +/obj/structure/table, +/obj/item/mop, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"Tz" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/rack, +/obj/item/food/candy{ + pixel_x = 11 + }, +/obj/item/food/candy{ + pixel_x = -9 + }, +/obj/item/food/candy{ + pixel_x = -2 + }, +/obj/item/food/candy{ + pixel_x = 4 + }, +/obj/machinery/light/cold/directional/west, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"TA" = ( +/obj/structure/table/reinforced, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/general/hidden, +/obj/structure/closet/mini_fridge, +/obj/effect/spawner/random/food_or_drink/booze, +/obj/effect/spawner/random/food_or_drink/booze, +/obj/effect/spawner/random/food_or_drink/booze, +/obj/effect/spawner/random/food_or_drink/booze, +/obj/effect/spawner/random/food_or_drink/booze, +/obj/effect/spawner/random/food_or_drink/booze, +/obj/effect/spawner/random/food_or_drink/booze, +/obj/effect/spawner/random/food_or_drink/booze, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"Ww" = ( +/obj/machinery/duct, +/turf/open/floor/plating/snowed/icemoon, +/area/ruin/powered/lizard_gas) +"WG" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/cable, +/obj/structure/rack, +/obj/item/reagent_containers/condiment/yoghurt{ + pixel_x = 10 + }, +/obj/item/reagent_containers/condiment/yoghurt{ + pixel_x = -8 + }, +/obj/item/reagent_containers/condiment/yoghurt{ + pixel_x = 1 + }, +/obj/effect/decal/cleanable/cobweb, +/obj/item/food/cheese/wheel, +/obj/item/food/cheese/wheel, +/obj/structure/window/spawner/directional/west, +/obj/machinery/door/window/left/directional/south, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, +/area/ruin/powered/lizard_gas) +"WN" = ( +/obj/machinery/airalarm/directional/east, +/obj/effect/mapping_helpers/airalarm/unlocked, +/turf/open/floor/iron, +/area/ruin/powered/lizard_gas) +"YC" = ( +/obj/effect/spawner/random/structure/crate_loot, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/ruin/powered/lizard_gas) + +(1,1,1) = {" +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +LG +Ji +Ji +gv +gv +"} +(2,1,1) = {" +gv +gv +gv +gv +gv +gv +gv +gv +gv +gv +LP +Ji +Ji +Ji +Ji +gv +gv +gv +gv +gv +ur +Ji +Ji +gv +gv +"} +(3,1,1) = {" +gv +gv +gv +gv +gv +gv +gv +Ji +Ji +Ji +GO +tx +tx +El +Ji +Ji +gv +gv +gv +gv +ur +Ji +ur +gv +gv +"} +(4,1,1) = {" +gv +gv +gv +gv +gv +gv +Ji +Ji +gv +gv +zh +tx +tx +El +Bc +Ji +gv +gv +gv +gv +Ez +ur +Ji +gv +gv +"} +(5,1,1) = {" +gv +gv +gv +gv +gv +Ji +Ji +gv +gv +gv +SZ +tx +tx +kT +Bc +Ji +gv +gv +gv +gv +ur +Ji +Ji +gv +gv +"} +(6,1,1) = {" +gv +gv +gv +gv +gv +Ji +gv +gv +Jv +Jv +HE +rh +rh +Jv +Jv +HE +HE +gv +gv +gv +ur +Ji +ur +gv +gv +"} +(7,1,1) = {" +gv +gv +gv +gv +gv +Ji +Ji +gv +HE +Bc +Bc +jD +Ww +jD +Ww +cE +Jv +Ji +Ji +Ji +Ji +Ji +Ji +gv +gv +"} +(8,1,1) = {" +gv +gv +gv +gv +gv +Ji +Ji +gv +Jv +Bc +Bc +cI +Bc +cI +Bc +Ww +Jv +Ji +ur +Ji +ur +Ji +Ji +gv +gv +"} +(9,1,1) = {" +gv +gv +gv +gv +gv +Ji +Ji +gv +Jv +Bc +Mz +oo +Bc +oo +bJ +Ww +Jv +gv +gv +Ji +Ji +ur +gv +gv +gv +"} +(10,1,1) = {" +gv +gv +gv +gv +gv +Ji +Ji +gv +Jv +Fp +Bc +gW +Bc +gW +Bc +Ww +HE +gv +gv +gv +gv +gv +gv +gv +gv +"} +(11,1,1) = {" +gv +gv +gv +gv +gv +Ji +Ji +gv +HE +Bc +Bc +jD +Ww +jD +Ww +Ww +Jv +gv +gv +gv +gv +gv +gv +gv +gv +"} +(12,1,1) = {" +gv +gv +gv +gv +Ji +Ji +gv +gv +zm +Jv +HE +Jv +IF +HE +CW +zL +RE +gv +gv +gv +gv +gv +gv +gv +gv +"} +(13,1,1) = {" +gv +gv +gv +gv +Ji +gv +gv +gv +oo +aR +aR +aR +oo +eM +kc +oo +oo +gv +gv +gv +gv +gv +gv +gv +gv +"} +(14,1,1) = {" +gv +gv +gv +gv +Ji +gv +gv +gv +oo +FP +yG +cF +Tz +Ao +ma +sn +oo +gv +gv +gv +gv +gv +gv +gv +gv +"} +(15,1,1) = {" +gv +gv +gv +gv +Ji +gv +gv +gv +oo +QQ +lK +dd +es +es +es +eZ +oo +gv +gv +gv +gv +gv +gv +gv +gv +"} +(16,1,1) = {" +gv +gv +gv +gv +Ji +gv +gv +gv +oo +MA +lK +cv +zJ +jQ +es +vA +oo +gv +gv +gv +gv +gv +gv +gv +gv +"} +(17,1,1) = {" +gv +gv +gv +sQ +sQ +sQ +KG +sQ +oo +WG +Ao +wU +oy +QI +TA +AM +oo +gv +gv +gv +gv +gv +gv +gv +gv +"} +(18,1,1) = {" +gv +gv +gv +sQ +Jv +Rc +Jv +Jv +oo +QK +ul +gm +ih +WN +pL +kS +oo +gv +gv +gv +gv +gv +gv +gv +gv +"} +(19,1,1) = {" +gv +gv +gv +sQ +Jv +HE +Jv +Jv +oo +oo +oo +oo +oo +oo +aN +oo +oo +gv +gv +gv +gv +gv +gv +gv +gv +"} +(20,1,1) = {" +gv +gv +gv +sU +Jv +Jv +sU +YC +ed +Jv +oo +tW +Py +xN +sm +eF +oo +gv +gv +gv +gv +gv +gv +gv +gv +"} +(21,1,1) = {" +gv +gv +gv +Lh +bn +Jv +Jv +wN +Jv +ed +oo +xK +iS +Rs +Rs +RC +RD +gv +gv +gv +gv +gv +gv +gv +gv +"} +(22,1,1) = {" +gv +gv +gv +sU +Jv +uv +sU +Jv +Jv +Jv +xw +ku +HI +wK +yH +qM +oo +gv +gv +gv +gv +gv +gv +gv +gv +"} +(23,1,1) = {" +gv +gv +gv +sQ +Jv +Jv +Jv +Jv +ed +Jv +oo +aR +aR +oo +oo +oo +oo +gv +gv +gv +gv +gv +gv +gv +gv +"} +(24,1,1) = {" +gv +gv +gv +sQ +Jv +Jv +ed +wN +RW +mE +pO +HE +Jv +Jv +Jv +HE +kI +gv +gv +gv +gv +gv +gv +gv +gv +"} +(25,1,1) = {" +gv +gv +gv +KG +Jv +Jv +YC +Md +Jv +Jv +Jv +Jv +Jv +HE +Jv +Jv +kI +gv +gv +gv +gv +gv +gv +gv +gv +"} diff --git a/_maps/RandomRuins/LavaRuins/skyrat/lavaland_surface_syndicate_base1_skyrat.dmm b/_maps/RandomRuins/LavaRuins/skyrat/lavaland_surface_syndicate_base1_skyrat.dmm index fedd3cb5207686..55da68d118d944 100644 --- a/_maps/RandomRuins/LavaRuins/skyrat/lavaland_surface_syndicate_base1_skyrat.dmm +++ b/_maps/RandomRuins/LavaRuins/skyrat/lavaland_surface_syndicate_base1_skyrat.dmm @@ -443,12 +443,6 @@ }, /turf/open/floor/iron/dark, /area/ruin/syndicate_lava_base/medbay) -"eh" = ( -/obj/structure/window/reinforced/survival_pod/spawner/directional/south, -/obj/structure/window/reinforced/survival_pod/spawner/directional/west, -/obj/structure/window/reinforced/survival_pod/spawner/directional/south, -/turf/open/floor/engine, -/area/ruin/syndicate_lava_base/testlab) "ej" = ( /obj/effect/turf_decal/tile/bar{ dir = 4 @@ -1397,10 +1391,6 @@ pixel_x = -5; pixel_y = 5 }, -/obj/item/clothing/mask/breath/anesthetic{ - pixel_x = 8; - pixel_y = 5 - }, /turf/open/floor/iron/dark, /area/ruin/syndicate_lava_base/medbay) "ow" = ( @@ -5951,7 +5941,7 @@ Zd Ku Fx ji -eh +ch Jt Ow OW diff --git a/_maps/RandomRuins/SpaceRuins/anomaly_research.dmm b/_maps/RandomRuins/SpaceRuins/anomaly_research.dmm index e3015469bcea4a..831e0247541938 100644 --- a/_maps/RandomRuins/SpaceRuins/anomaly_research.dmm +++ b/_maps/RandomRuins/SpaceRuins/anomaly_research.dmm @@ -66,7 +66,6 @@ /area/misc/anomaly_research) "dj" = ( /obj/structure/window/spawner/directional/north, -/obj/structure/window/spawner/directional/north, /obj/structure/window/spawner/directional/east, /obj/structure/flora/bush/flowers_br/style_random, /turf/open/floor/grass, @@ -1516,7 +1515,6 @@ /area/misc/anomaly_research) "Ox" = ( /obj/structure/window/spawner/directional/north, -/obj/structure/window/spawner/directional/north, /obj/structure/flora/bush/flowers_br/style_random, /obj/machinery/light/broken/directional/south, /turf/open/floor/grass, diff --git a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm index 3534643bea98a3..66e681981c7061 100644 --- a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm +++ b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm @@ -26,7 +26,7 @@ /area/template_noop) "ah" = ( /obj/structure/lattice/catwalk, -/mob/living/simple_animal/hostile/pirate/ranged/space{ +/mob/living/basic/trooper/pirate/ranged/space{ environment_smash = 0 }, /turf/template_noop, @@ -587,7 +587,7 @@ dir = 4 }, /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/pirate/ranged/space{ +/mob/living/basic/trooper/pirate/ranged/space{ environment_smash = 0 }, /turf/open/floor/iron/airless, @@ -736,7 +736,7 @@ /area/ruin/space/has_grav) "Fr" = ( /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/pirate/ranged/space{ +/mob/living/basic/trooper/pirate/ranged/space{ environment_smash = 0 }, /turf/open/floor/plating/airless, @@ -941,7 +941,7 @@ "Nm" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on, /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/pirate/ranged/space{ +/mob/living/basic/trooper/pirate/ranged/space{ environment_smash = 0 }, /turf/open/floor/iron/airless, diff --git a/_maps/RandomRuins/SpaceRuins/clericden.dmm b/_maps/RandomRuins/SpaceRuins/clericden.dmm index ed9b63c7947a2a..c6e6bebddb0be8 100644 --- a/_maps/RandomRuins/SpaceRuins/clericden.dmm +++ b/_maps/RandomRuins/SpaceRuins/clericden.dmm @@ -131,7 +131,7 @@ /area/ruin/space) "E" = ( /obj/effect/decal/cleanable/blood/tracks, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /turf/open/floor/carpet/airless, /area/ruin/space) "F" = ( @@ -171,7 +171,7 @@ /turf/open/floor/plating/airless, /area/ruin/space) "N" = ( -/mob/living/simple_animal/hostile/construct/proteon, +/mob/living/basic/construct/proteon, /turf/open/misc/asteroid/airless, /area/ruin/space) "O" = ( diff --git a/_maps/RandomRuins/SpaceRuins/derelict_construction.dmm b/_maps/RandomRuins/SpaceRuins/derelict_construction.dmm index 6eeb3dd3ef3943..a8c3607258ddce 100644 --- a/_maps/RandomRuins/SpaceRuins/derelict_construction.dmm +++ b/_maps/RandomRuins/SpaceRuins/derelict_construction.dmm @@ -31,7 +31,7 @@ /area/ruin/space/has_grav/derelictconstruction) "fa" = ( /obj/structure/lattice, -/mob/living/simple_animal/hostile/pirate/ranged/space, +/mob/living/basic/trooper/pirate/ranged/space, /turf/template_noop, /area/space/nearstation) "gi" = ( @@ -416,7 +416,7 @@ /turf/open/floor/plating, /area/ruin/space/has_grav/derelictconstruction) "Za" = ( -/mob/living/simple_animal/hostile/pirate/melee/space, +/mob/living/basic/trooper/pirate/melee/space, /obj/structure/lattice/catwalk, /turf/template_noop, /area/ruin/space/has_grav/derelictconstruction) diff --git a/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm b/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm new file mode 100644 index 00000000000000..e3a80fb657a6c5 --- /dev/null +++ b/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm @@ -0,0 +1,1494 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aF" = ( +/obj/item/trash/can/food/envirochow{ + pixel_x = 2 + }, +/obj/item/trash/can/food/envirochow{ + pixel_x = -8; + pixel_y = -6 + }, +/obj/item/trash/can/food/envirochow{ + pixel_y = -12 + }, +/obj/effect/decal/cleanable/insectguts, +/mob/living/basic/cockroach, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"aP" = ( +/obj/item/kitchen/fork{ + pixel_x = -10; + pixel_y = 0 + }, +/obj/effect/decal/cleanable/ants, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"bj" = ( +/obj/structure/closet/crate/trashcart/filled, +/obj/item/food/badrecipe/moldy/bacteria, +/obj/item/food/deadmouse, +/obj/item/sticker/syndicate/larva, +/mob/living/basic/mouse/rat, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"bs" = ( +/obj/structure/kitchenspike_frame, +/obj/item/paper/crumpled, +/obj/item/restraints/handcuffs/cable/zipties/used, +/obj/effect/decal/cleanable/blood/gibs/old, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"bx" = ( +/obj/effect/decal/cleanable/garbage, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"bF" = ( +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"ew" = ( +/obj/item/trash/can/food/peaches/maint, +/obj/item/food/breadslice/moldy/bacteria, +/obj/effect/decal/cleanable/food/egg_smudge, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"fb" = ( +/obj/item/trash/boritos/green, +/obj/effect/decal/cleanable/plastic, +/obj/item/storage/bag/trash, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"fk" = ( +/obj/item/kirbyplants/fern, +/obj/item/food/deadmouse, +/obj/effect/spawner/random/entertainment/money_small, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"fx" = ( +/obj/item/food/badrecipe/moldy/bacteria{ + pixel_y = -10 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"fI" = ( +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"fP" = ( +/obj/item/match, +/obj/item/trash/popcorn, +/obj/item/trash/spacers_sidekick, +/obj/item/food/pizzaslice/moldy/bacteria, +/obj/effect/decal/cleanable/plastic, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"fR" = ( +/obj/effect/spawner/random/structure/crate_empty, +/obj/item/kitchen/spoon/soup_ladle{ + pixel_x = -5; + pixel_y = 7 + }, +/obj/item/food/badrecipe/moldy{ + pixel_x = 3; + pixel_y = 0 + }, +/obj/item/food/badrecipe/moldy{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/food/badrecipe/moldy{ + pixel_y = 3 + }, +/obj/item/food/badrecipe/moldy, +/obj/item/food/grown/mushroom/odious_puffball{ + pixel_y = 3 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"fV" = ( +/obj/item/food/butter{ + pixel_x = 10; + pixel_y = 4 + }, +/obj/item/food/butter{ + pixel_x = 2; + pixel_y = 4 + }, +/obj/structure/closet/crate/freezer, +/obj/item/food/butter{ + pixel_x = -6; + pixel_y = 4 + }, +/obj/item/reagent_containers/condiment/flour{ + pixel_x = -6; + pixel_y = -6 + }, +/obj/item/reagent_containers/condiment/flour{ + pixel_x = 6; + pixel_y = -6 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"gb" = ( +/obj/structure/closet/crate/trashcart, +/obj/item/plate_shard, +/obj/item/popsicle_stick, +/obj/item/popsicle_stick, +/obj/item/food/egg/rotten, +/obj/effect/decal/cleanable/plastic, +/obj/item/storage/bag/tray/cafeteria, +/obj/item/storage/bag/tray/cafeteria, +/obj/item/storage/bag/tray/cafeteria, +/obj/item/knife/butcher{ + desc = "A huge thing used for chopping and chopping up meat. Years of service has scarred its metal and worn groves into the handle, but its blade is well-maintained and sharp."; + name = "antique cleaver" + }, +/mob/living/basic/cockroach, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"gI" = ( +/obj/item/storage/box/mousetraps, +/obj/structure/table/reinforced, +/obj/item/melee/flyswatter, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"hq" = ( +/obj/structure/chair/comfy/shuttle, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"hH" = ( +/obj/item/clothing/mask/surgical, +/obj/effect/spawner/random/trash/botanical_waste, +/obj/structure/closet/crate/trashcart/filled, +/obj/item/seeds/onion/red{ + pixel_x = 6; + pixel_y = 4 + }, +/obj/item/seeds/onion{ + pixel_x = 2; + pixel_y = 2 + }, +/obj/item/food/grown/mushroom/odious_puffball{ + pixel_x = -8; + pixel_y = 2 + }, +/obj/effect/spawner/random/food_or_drink/seed, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"hN" = ( +/obj/item/shard, +/obj/item/food/pizzaslice/moldy/bacteria, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"iu" = ( +/obj/structure/plasticflaps/opaque, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"iH" = ( +/obj/structure/closet/crate/freezer, +/obj/item/food/hard_taco_shell/empty{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/food/hard_taco_shell/empty{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/food/hard_taco_shell/empty{ + pixel_x = 2; + pixel_y = 2 + }, +/obj/item/food/hard_taco_shell/empty{ + pixel_x = 1; + pixel_y = 1 + }, +/obj/item/storage/box/donkpockets{ + pixel_x = -5; + pixel_y = -5 + }, +/obj/effect/spawner/random/food_or_drink/donkpockets_single, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"jo" = ( +/obj/item/trash/can, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"js" = ( +/obj/item/food/egg/rotten{ + pixel_x = -6; + pixel_y = -8 + }, +/obj/item/food/egg/rotten{ + pixel_x = -10; + pixel_y = -8 + }, +/obj/item/food/egg/rotten{ + pixel_x = -14; + pixel_y = -8 + }, +/obj/item/food/meat/slab/rawcrab{ + pixel_x = 2; + pixel_y = -8 + }, +/obj/item/food/meat/slab/rawcrab{ + pixel_x = 2; + pixel_y = -8 + }, +/obj/item/food/meat/slab/rawcrab{ + pixel_x = 3; + pixel_y = -6 + }, +/obj/item/food/meat/slab/rawcrab{ + pixel_x = 2; + pixel_y = -2 + }, +/obj/item/food/meat/slab/rawcrab{ + pixel_x = 2 + }, +/obj/item/storage/fancy/pickles_jar{ + pixel_x = -8; + pixel_y = 6 + }, +/obj/structure/closet/secure_closet/freezer/empty, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"ki" = ( +/obj/effect/spawner/random/trash/food_packaging, +/obj/item/shard, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"ku" = ( +/obj/structure/fermenting_barrel, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"kJ" = ( +/obj/structure/table/reinforced, +/obj/item/storage/box/gloves{ + pixel_x = 10; + pixel_y = 8 + }, +/obj/item/storage/box/masks{ + pixel_x = -6; + pixel_y = 8 + }, +/obj/machinery/recharger{ + pixel_y = -10 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"kS" = ( +/obj/machinery/light/warm, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"kV" = ( +/obj/machinery/computer/terminal{ + content = list("Property of Spinward-Upsilon Sanitation Department. Authorised employees only."); + desc = "A garbage truck's dusty old control console."; + name = "dashboard"; + upperinfo = "Controls locked." + }, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"nN" = ( +/obj/item/trash/candy, +/obj/item/reagent_containers/cup/glass/colocup, +/obj/item/reagent_containers/cup/glass/colocup, +/obj/item/reagent_containers/cup/glass/colocup, +/obj/item/reagent_containers/cup/glass/colocup, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"nQ" = ( +/obj/item/trash/shrimp_chips, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"nS" = ( +/obj/effect/spawner/random/structure/crate_empty, +/obj/item/vending_refill/dinnerware, +/obj/item/vending_refill/snack, +/obj/item/circuitboard/machine/coffeemaker, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"og" = ( +/obj/structure/lattice, +/obj/structure/grille, +/obj/effect/spawner/random/entertainment/plushie, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"oq" = ( +/obj/item/food/cheese/wheel, +/obj/item/food/cheese/wheel, +/obj/item/food/cheese/wheel, +/obj/item/food/cheese/wheel, +/obj/item/food/cheese/wheel, +/obj/item/food/cheese/firm_cheese, +/obj/item/food/cheese/firm_cheese, +/obj/item/food/cheese/firm_cheese, +/obj/item/food/cheese/firm_cheese, +/obj/item/food/cheese/firm_cheese, +/obj/item/thermometer, +/obj/structure/closet/secure_closet/freezer/empty, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"oL" = ( +/obj/structure/table/reinforced, +/obj/item/analyzer{ + pixel_y = 6 + }, +/obj/item/geiger_counter{ + pixel_x = -8; + pixel_y = -2 + }, +/obj/item/flashlight{ + pixel_x = 4 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"pp" = ( +/obj/effect/spawner/random/trash/garbage, +/obj/item/broken_bottle, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"ps" = ( +/obj/item/trash/can/food/larvae, +/obj/item/food/bait/worm, +/obj/effect/decal/cleanable/garbage, +/obj/effect/decal/cleanable/ants, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"pF" = ( +/obj/item/food/badrecipe/moldy/bacteria, +/obj/item/food/deadmouse/moldy, +/obj/structure/broken_flooring/pile, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"pP" = ( +/obj/structure/lattice/catwalk, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"qd" = ( +/obj/item/food/breadslice/moldy/bacteria{ + pixel_y = -10 + }, +/obj/structure/reagent_dispensers/servingdish{ + anchored = 0 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"qm" = ( +/obj/effect/decal/cleanable/food/egg_smudge, +/obj/item/food/pizzaslice/moldy, +/mob/living/basic/mouse/brown, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"qM" = ( +/turf/open/space/basic, +/area/space) +"re" = ( +/obj/item/trash/shrimp_chips, +/obj/item/trash/sosjerky, +/mob/living/basic/mouse/rat, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"rx" = ( +/obj/item/surprise_egg, +/obj/structure/closet/crate/trashcart, +/obj/item/trash/raisins, +/obj/effect/decal/cleanable/food/egg_smudge, +/obj/item/book/manual/chef_recipes, +/obj/item/trash/semki/healthy, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"rL" = ( +/obj/item/food/badrecipe, +/obj/item/pen/charcoal{ + desc = "It's just a wooden stick with some compressed ash on the end. At least it can write."; + name = "charcoal stick" + }, +/obj/effect/decal/cleanable/oil/streak, +/obj/structure/closet/crate/trashcart, +/obj/item/food/grown/ash_flora/shavings, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"tr" = ( +/obj/structure/broken_flooring/singular, +/obj/effect/spawner/random/trash/food_packaging, +/obj/effect/spawner/random/trash/food_packaging, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"ty" = ( +/obj/item/trash/can/food/peaches, +/obj/item/trash/boritos/red, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"tU" = ( +/obj/machinery/door/poddoor/shutters/preopen, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"uJ" = ( +/obj/item/trash/cnds, +/obj/item/food/breadslice/moldy/bacteria, +/obj/effect/decal/cleanable/wrapping, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"vA" = ( +/obj/machinery/power/terminal, +/obj/structure/tank_dispenser/oxygen, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"vI" = ( +/obj/item/poster/random_contraband, +/obj/item/tank/internals/emergency_oxygen/empty, +/obj/effect/decal/cleanable/garbage{ + pixel_x = -8; + pixel_y = -8 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"wb" = ( +/obj/effect/spawner/random/trash/bacteria, +/obj/item/trash/can, +/obj/item/trash/can{ + pixel_x = 8; + pixel_y = 1 + }, +/obj/item/trash/can{ + pixel_x = 5; + pixel_y = -2 + }, +/obj/item/food/badrecipe/moldy/bacteria{ + pixel_x = 12; + pixel_y = -8 + }, +/obj/effect/decal/cleanable/fuel_pool{ + desc = "A sticky patch of dried cola. It smells very sweet."; + name = "puddle of cola" + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"wv" = ( +/obj/structure/closet/cardboard, +/obj/item/toy/plush/snakeplushie, +/obj/item/clothing/glasses/eyepatch, +/obj/item/clothing/mask/cigarette/cigar/havana, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"wR" = ( +/obj/structure/reagent_dispensers/water_cooler, +/obj/item/food/badrecipe/moldy/bacteria{ + pixel_x = 2; + pixel_y = -8 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"xf" = ( +/obj/item/trash/tray, +/obj/item/trash/waffles, +/obj/item/trash/waffles, +/obj/item/trash/waffles, +/obj/item/food/grown/mushroom/plumphelmet, +/obj/structure/closet/crate/trashcart, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"xg" = ( +/obj/structure/closet/crate/cardboard, +/obj/item/knife/kitchen, +/obj/item/storage/box/mousetraps, +/obj/structure/broken_flooring/pile, +/obj/item/food/grown/parsnip, +/obj/item/food/grown/parsnip, +/obj/item/food/cheese/wedge, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"xk" = ( +/obj/structure/table/reinforced, +/obj/item/gps/spaceruin{ + pixel_x = 6; + pixel_y = 2 + }, +/obj/item/storage/backpack/industrial{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/item/clothing/suit/hazardvest{ + pixel_x = -8; + pixel_y = -6 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"xZ" = ( +/obj/item/restraints/handcuffs/cable/zipties/used, +/obj/effect/spawner/random/decoration/flower, +/obj/item/reagent_containers/cup/glass/bottle/wine/unlabeled, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"ye" = ( +/obj/item/trash/semki/healthy, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"yh" = ( +/obj/effect/spawner/random/trash, +/mob/living/basic/mouse, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"yi" = ( +/obj/structure/sign/warning, +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"yv" = ( +/obj/item/trash/can{ + pixel_x = -8; + pixel_y = -2 + }, +/obj/item/trash/can{ + pixel_y = -8 + }, +/obj/effect/decal/cleanable/fuel_pool{ + desc = "A sticky patch of dried cola. It smells very sweet."; + name = "puddle of cola" + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"yC" = ( +/obj/item/trash/popcorn/caramel{ + pixel_y = -6 + }, +/mob/living/basic/cockroach, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"zK" = ( +/obj/item/trash/chips{ + pixel_x = -8 + }, +/obj/item/broken_bottle{ + pixel_x = 8; + pixel_y = 2 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Aj" = ( +/obj/effect/decal/cleanable/ants, +/mob/living/basic/mouse/white, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"An" = ( +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"AM" = ( +/obj/item/trash/can{ + pixel_x = -8; + pixel_y = -2; + pixel_z = 0 + }, +/obj/item/reagent_containers/cup/soda_cans/random{ + pixel_x = -8; + pixel_y = 6 + }, +/obj/structure/closet/crate/cardboard, +/obj/item/vending_refill/cola, +/obj/item/vending_refill/boozeomat, +/obj/item/trash/can{ + pixel_x = 8; + pixel_y = 0 + }, +/obj/item/trash/can{ + pixel_x = 2; + pixel_y = -4 + }, +/obj/item/reagent_containers/cup/soda_cans/random{ + pixel_x = -2; + pixel_y = -2 + }, +/obj/item/reagent_containers/cup/soda_cans/random{ + pixel_x = 8; + pixel_y = -2 + }, +/obj/effect/decal/cleanable/fuel_pool{ + desc = "A sticky patch of dried cola. It smells very sweet."; + name = "puddle of cola" + }, +/obj/effect/spawner/random/food_or_drink/refreshing_beverage, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"AR" = ( +/obj/structure/lattice, +/obj/structure/grille, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"BS" = ( +/obj/item/storage/bag/trash/filled{ + pixel_x = -8 + }, +/obj/effect/decal/cleanable/garbage{ + pixel_x = 2; + pixel_y = 5 + }, +/obj/effect/decal/cleanable/food/egg_smudge{ + pixel_x = -2; + pixel_y = -8 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Cc" = ( +/obj/item/trash/tray, +/obj/item/food/breadslice/moldy/bacteria{ + pixel_x = -8; + pixel_y = -8 + }, +/obj/item/food/tofu/prison{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/item/food/tofu/prison{ + pixel_x = -8; + pixel_y = -2 + }, +/obj/effect/decal/cleanable/ants, +/obj/structure/closet/crate/preopen, +/obj/item/food/meat/slab/human/mutant/zombie{ + pixel_x = 8; + pixel_y = 4 + }, +/obj/item/mail/junkmail, +/obj/item/trash/raisins, +/obj/item/trash/candy{ + pixel_x = 10; + pixel_y = -6 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Ci" = ( +/obj/item/kitchen/fork/plastic{ + pixel_x = -8 + }, +/obj/item/kitchen/spoon/plastic{ + pixel_x = -2; + pixel_y = -2 + }, +/obj/item/paper/crumpled{ + pixel_x = 7; + pixel_y = -4 + }, +/obj/effect/decal/cleanable/glass, +/obj/effect/spawner/random/food_or_drink/condiment, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Ct" = ( +/obj/machinery/door/airlock/shuttle, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"CF" = ( +/obj/machinery/reagentgrinder{ + anchored = 0 + }, +/obj/item/food/badrecipe{ + pixel_x = -4; + pixel_y = -6 + }, +/obj/effect/decal/cleanable/fuel_pool{ + desc = "A sticky patch of dried cola. It smells very sweet."; + name = "puddle of cola" + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Do" = ( +/obj/item/food/badrecipe/moldy/bacteria, +/obj/item/food/bait/worm, +/obj/effect/decal/cleanable/food/tomato_smudge, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Ec" = ( +/obj/effect/spawner/random/trash/bucket, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Fp" = ( +/obj/item/food/badrecipe/moldy/bacteria, +/obj/item/storage/bag/trash/filled, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Fs" = ( +/obj/structure/closet/cardboard, +/obj/item/restraints/handcuffs/cable/zipties/used, +/obj/item/food/cornchips/blue, +/obj/item/food/cornchips/blue, +/obj/item/food/cornchips/green, +/obj/item/food/cornchips/green, +/obj/item/food/cornchips/purple, +/obj/item/food/cornchips/purple, +/obj/item/food/cornchips/red, +/obj/item/food/cornchips/red, +/obj/item/food/cornchips/random, +/obj/item/food/cornchips/random, +/obj/item/food/cornchips/blue{ + desc = "Limited edition flavour. Only for sale within the space commonwealth."; + name = "\improper Space Salt and Vinegar Boritos corn chips"; + tastes = list("salt" = 1, "vinegar" = 3) + }, +/obj/item/food/cornchips/blue{ + desc = "Limited edition flavour. Only for sale within the space commonwealth."; + name = "\improper Space Salt and Vinegar Boritos corn chips"; + tastes = list("salt" = 1, "vinegar" = 3) + }, +/obj/item/food/cornchips/random, +/obj/item/food/cornchips/random, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Fz" = ( +/obj/structure/table/reinforced, +/obj/machinery/cell_charger, +/obj/item/stock_parts/cell/lead, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"FL" = ( +/obj/structure/closet/cardboard, +/obj/item/pen/blue, +/obj/item/ph_paper, +/obj/item/petri_dish, +/obj/item/healthanalyzer/simple/disease, +/obj/item/biopsy_tool, +/obj/effect/spawner/random/medical/surgery_tool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Gh" = ( +/obj/item/trash/semki/healthy, +/mob/living/basic/mouse, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"GB" = ( +/obj/item/trash/can, +/obj/item/storage/bag/trash, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"GP" = ( +/obj/effect/decal/cleanable/garbage, +/obj/item/crowbar/hammer{ + desc = "It's a heavy iron hammer with a plastic grip. A triangle has been chiselled into the handle."; + name = "heirloom hammer" + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"GU" = ( +/obj/item/reagent_containers/cup/glass/waterbottle/empty, +/obj/effect/decal/cleanable/wrapping, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Hh" = ( +/obj/structure/closet/crate/trashcart/filled, +/obj/item/reagent_containers/cup/glass/bottle/juice/orangejuice{ + desc = "Best before '32"; + pixel_x = -6 + }, +/obj/effect/decal/cleanable/insectguts, +/obj/item/food/grown/mushroom/odious_puffball{ + pixel_x = 8; + pixel_y = 4 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Hu" = ( +/obj/effect/spawner/random/structure/crate_empty, +/obj/item/knife/plastic{ + pixel_x = 12 + }, +/obj/item/food/badrecipe/moldy/bacteria{ + pixel_x = -6 + }, +/obj/item/food/meat/slab/pig, +/obj/item/food/deadmouse, +/obj/item/food/salami{ + pixel_x = 1; + pixel_y = 2 + }, +/obj/item/food/salami{ + pixel_x = 1; + pixel_y = 3 + }, +/obj/item/food/salami{ + pixel_x = 1; + pixel_y = 6 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"HC" = ( +/obj/effect/spawner/random/structure/crate_empty, +/obj/item/kitchen/fork/plastic{ + pixel_x = -8 + }, +/obj/item/kitchen/fork/plastic{ + pixel_x = 8; + pixel_y = 0 + }, +/obj/item/kitchen/fork/plastic, +/obj/item/storage/box/papersack/meat, +/obj/effect/spawner/random/food_or_drink/condiment, +/obj/item/popsicle_stick, +/obj/item/popsicle_stick{ + pixel_x = -4; + pixel_y = 1 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Ie" = ( +/obj/machinery/airalarm{ + pixel_y = 25 + }, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"II" = ( +/obj/structure/closet/crate/trashcart/filled, +/obj/item/food/cracker, +/obj/item/food/canned/beans{ + desc = "Probably still good."; + name = "rust-covered tin of beans" + }, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"IR" = ( +/obj/structure/table/reinforced, +/obj/item/gas_filter, +/obj/item/gas_filter, +/obj/item/clothing/mask/gas, +/obj/item/clothing/head/utility/hardhat/orange{ + pixel_y = 8 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"JH" = ( +/obj/item/petri_dish/random, +/obj/item/petri_dish/random, +/obj/item/petri_dish, +/obj/item/petri_dish, +/obj/item/petri_dish, +/obj/item/organ/internal/tongue/rat, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/glass, +/obj/item/organ/internal/stomach/rat, +/obj/item/fish/ratfish, +/obj/structure/closet/crate/freezer, +/obj/effect/spawner/random/medical/surgery_tool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"KD" = ( +/obj/structure/closet/crate/critter, +/obj/item/dog_bone{ + pixel_y = -6 + }, +/mob/living/basic/cockroach, +/mob/living/basic/cockroach, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"KT" = ( +/obj/structure/broken_flooring/singular, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Le" = ( +/obj/effect/spawner/random/trash/bacteria, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Mq" = ( +/obj/structure/closet/crate/cardboard, +/obj/item/stack/tile/bamboo/tatami{ + amount = 40 + }, +/obj/item/stack/sticky_tape{ + pixel_y = -2 + }, +/obj/effect/decal/cleanable/plastic, +/obj/effect/decal/cleanable/oil/streak, +/obj/effect/decal/cleanable/glass, +/obj/effect/spawner/random/engineering/material_cheap, +/obj/item/crowbar/hammer{ + desc = "It's a heavy claw hammer. The handle is covered in fangmarks of varying sizes."; + name = "old hammer" + }, +/obj/item/food/deadmouse, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"MA" = ( +/obj/item/food/badrecipe/moldy/bacteria, +/obj/item/food/deadmouse, +/obj/item/grown/bananapeel, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Nm" = ( +/obj/item/trash/energybar, +/obj/item/trash/energybar, +/obj/item/trash/energybar, +/obj/item/trash/energybar, +/obj/item/food/candy/bronx, +/obj/item/food/candy/bronx, +/obj/effect/spawner/random/structure/crate_empty, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Od" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/shuttle, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Oh" = ( +/obj/effect/spawner/random/trash/bacteria, +/mob/living/basic/mouse/brown, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Ok" = ( +/obj/item/plate/large, +/obj/item/plate/large, +/obj/item/storage/box/drinkingglasses{ + pixel_x = 10; + pixel_y = 2 + }, +/obj/structure/closet/crate/preopen, +/obj/item/reagent_containers/cup/glass/coffee_cup{ + pixel_x = 4; + pixel_y = -3 + }, +/mob/living/basic/mouse/brown, +/mob/living/basic/mouse/brown, +/mob/living/basic/mouse/brown, +/mob/living/basic/mouse, +/mob/living/basic/mouse, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Or" = ( +/obj/item/food/sustenance_bar/cheese{ + pixel_x = -6; + pixel_y = -8 + }, +/obj/structure/closet/crate/large, +/obj/item/food/sustenance_bar/cheese{ + pixel_x = -6; + pixel_y = -4 + }, +/obj/item/food/sustenance_bar/neapolitan{ + maptext_x = 0; + maptext_y = 0; + pixel_x = -6 + }, +/obj/item/food/sustenance_bar/neapolitan{ + pixel_x = -6; + pixel_y = 4 + }, +/obj/item/food/sustenance_bar/mint{ + pixel_x = -6; + pixel_y = 8 + }, +/obj/item/food/sustenance_bar/mint{ + pixel_x = -6; + pixel_y = 12 + }, +/obj/item/food/sustenance_bar{ + pixel_x = 6; + pixel_y = -10 + }, +/obj/item/food/sustenance_bar{ + pixel_x = 6; + pixel_y = -6 + }, +/obj/item/food/sustenance_bar{ + pixel_x = 6; + pixel_y = -2 + }, +/obj/item/food/sustenance_bar{ + pixel_x = 6; + pixel_y = 2 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Ox" = ( +/obj/effect/spawner/random/structure/crate_empty, +/obj/item/trash/candy{ + pixel_x = 6; + pixel_y = 6 + }, +/obj/item/trash/can/food/desert_snails{ + pixel_x = -4; + pixel_y = 2 + }, +/obj/item/trash/can/food/envirochow{ + pixel_x = -8; + pixel_y = -2 + }, +/obj/effect/decal/cleanable/food/flour, +/obj/item/thermometer/pen{ + pixel_x = 8 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"OD" = ( +/turf/closed/wall/mineral/titanium, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"OZ" = ( +/obj/effect/spawner/random/structure/crate_empty, +/obj/item/plate/small{ + pixel_x = -6 + }, +/obj/item/food/meat/slab/human/mutant/zombie{ + pixel_x = 4; + pixel_y = 6 + }, +/obj/item/food/meat/slab/human/mutant/zombie{ + pixel_x = 5 + }, +/obj/item/food/meat/slab/human/mutant/zombie{ + pixel_x = 2; + pixel_y = -5 + }, +/obj/item/food/meat/slab/human{ + pixel_x = 1; + pixel_y = 3 + }, +/obj/effect/decal/cleanable/ants, +/obj/effect/decal/cleanable/food/tomato_smudge, +/obj/item/organ/internal/heart/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"PU" = ( +/obj/item/clothing/head/cone{ + pixel_x = 8; + pixel_y = 8 + }, +/obj/machinery/light/warm, +/obj/machinery/power/apc{ + cell_type = /obj/item/stock_parts/cell/lead; + locked = 0; + pixel_y = -25; + start_charge = 0 + }, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Qi" = ( +/obj/item/book/bible, +/obj/structure/closet/crate/cardboard, +/obj/item/mail/junkmail{ + pixel_x = -10; + pixel_y = 2 + }, +/obj/item/mail/junkmail{ + pixel_x = 6; + pixel_y = 1 + }, +/obj/item/mail/junkmail, +/obj/effect/decal/cleanable/insectguts, +/mob/living/basic/mouse/rat, +/mob/living/basic/mouse/rat, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"QH" = ( +/obj/structure/closet/crate/trashcart/filled, +/obj/effect/decal/cleanable/insectguts, +/obj/item/pinata, +/obj/item/food/cornchips/green, +/obj/effect/spawner/random/food_or_drink/condiment, +/mob/living/basic/mouse, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"QL" = ( +/obj/item/broken_bottle, +/obj/item/grown/bananapeel, +/obj/effect/spawner/random/trash/garbage, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Rq" = ( +/obj/machinery/door/airlock/external/glass, +/obj/structure/fans/tiny, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Sa" = ( +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Sb" = ( +/obj/item/food/deadmouse/moldy, +/obj/item/reagent_containers/spray/pestspray{ + pixel_x = 6; + pixel_y = 8 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"TB" = ( +/obj/structure/window/reinforced/shuttle, +/obj/structure/grille, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"TG" = ( +/obj/item/mop, +/obj/item/food/deadmouse/moldy, +/obj/item/pushbroom, +/obj/effect/decal/cleanable/insectguts, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"TX" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"UX" = ( +/obj/structure/lattice/catwalk, +/obj/item/crowbar/large/emergency, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Vb" = ( +/obj/structure/closet/crate/cardboard/mothic, +/obj/item/trash/can/food/pine_nuts, +/obj/item/broken_bottle, +/obj/item/broken_bottle, +/obj/effect/decal/cleanable/wrapping, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"VB" = ( +/obj/machinery/power/smes, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"VL" = ( +/obj/machinery/power/shuttle_engine/propulsion, +/turf/open/space/basic, +/area/space) +"Xi" = ( +/obj/item/food/badrecipe/moldy/bacteria, +/obj/effect/decal/cleanable/food/egg_smudge, +/mob/living/basic/mouse, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"XF" = ( +/obj/item/shard, +/obj/item/trash/boritos, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"XY" = ( +/obj/structure/lattice, +/obj/structure/grille/broken, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Yu" = ( +/obj/structure/table/reinforced, +/obj/item/storage/bag/trash{ + pixel_x = -12; + pixel_y = 0 + }, +/obj/item/storage/bag/trash, +/obj/item/storage/bag/trash{ + pixel_x = -6; + pixel_y = 0 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Yx" = ( +/obj/structure/reagent_dispensers/cooking_oil{ + anchored = 0 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Yz" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"YB" = ( +/obj/item/trash/peanuts{ + pixel_x = -4; + pixel_y = -8 + }, +/obj/structure/closet/crate/freezer, +/obj/item/trash/pistachios{ + pixel_x = 8; + pixel_y = -4 + }, +/obj/item/trash/pistachios, +/obj/item/c_tube, +/obj/item/food/uncooked_rice{ + pixel_y = -4 + }, +/obj/item/trash/peanuts{ + pixel_x = -2; + pixel_y = 6 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) +"Zb" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/grown/bananapeel, +/obj/item/food/deadmouse, +/mob/living/basic/mouse/rat, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/foodwaste) + +(1,1,1) = {" +qM +qM +pP +pP +pP +OD +VL +qM +qM +qM +qM +qM +qM +qM +qM +qM +qM +qM +qM +qM +"} +(2,1,1) = {" +qM +OD +TB +TB +OD +OD +Sa +Sa +Sa +Sa +Sa +Sa +Sa +Sa +Sa +Sa +Sa +Sa +Sa +Sa +"} +(3,1,1) = {" +XY +Od +kJ +Fz +gI +OD +Sa +Hu +rL +HC +YB +iH +wv +KD +wR +nS +fV +Vb +bs +yi +"} +(4,1,1) = {" +og +TB +kV +hq +kS +OD +Sa +xf +ku +OZ +Fp +Ok +MA +aF +vI +xg +ps +ye +GP +Sa +"} +(5,1,1) = {" +AR +TB +xk +IR +bF +OD +Sa +Ci +qm +qd +zK +aP +GU +KT +An +TX +ki +Fp +xZ +Sa +"} +(6,1,1) = {" +XY +TB +Od +OD +Ie +Ct +tU +TX +yh +bx +Yz +Do +Le +fx +wb +gb +hH +QH +bj +Sa +"} +(7,1,1) = {" +XY +Od +Yu +oL +bF +Ct +tU +fb +pF +Gh +hN +QL +TX +Mq +AM +CF +rx +II +Hh +Sa +"} +(8,1,1) = {" +og +Od +fI +fI +bF +OD +Sa +js +BS +Oh +oq +XF +jo +Aj +yv +GB +pp +re +Yx +Sa +"} +(9,1,1) = {" +XY +Od +fI +bF +PU +OD +Sa +Qi +yC +nN +Fs +fk +TG +nQ +ku +ty +ew +tr +Zb +Sa +"} +(10,1,1) = {" +AR +Od +fI +vA +VB +OD +Sa +Cc +Ox +fR +fP +Or +Ec +Sb +Xi +uJ +FL +Nm +JH +yi +"} +(11,1,1) = {" +qM +OD +Rq +Od +OD +OD +Sa +Sa +Sa +Sa +Sa +Sa +Sa +iu +iu +iu +Sa +Sa +Sa +Sa +"} +(12,1,1) = {" +qM +qM +pP +pP +UX +OD +VL +qM +qM +qM +qM +qM +qM +qM +qM +qM +qM +qM +qM +qM +"} diff --git a/_maps/RandomRuins/SpaceRuins/garbagetruck2.dmm b/_maps/RandomRuins/SpaceRuins/garbagetruck2.dmm new file mode 100644 index 00000000000000..a2ed3ff8dbae96 --- /dev/null +++ b/_maps/RandomRuins/SpaceRuins/garbagetruck2.dmm @@ -0,0 +1,955 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"bb" = ( +/obj/item/organ/external/wings/moth, +/obj/structure/closet/crate/trashcart, +/obj/item/bodypart/arm/left/skeleton, +/obj/item/bodypart/arm/right/skeleton, +/obj/item/evidencebag, +/obj/item/organ/internal/heart/cybernetic/tier2, +/obj/structure/broken_flooring/pile, +/obj/item/stack/sheet/animalhide/human/five, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"bv" = ( +/obj/structure/showcase/horrific_experiment, +/obj/effect/decal/cleanable/blood/gibs/old, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"eO" = ( +/obj/effect/spawner/random/contraband/narcotics, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"gh" = ( +/turf/open/space/basic, +/area/space) +"gr" = ( +/obj/machinery/door/poddoor/shutters/preopen, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"gy" = ( +/obj/machinery/door/airlock/external/glass, +/obj/structure/fans/tiny, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"hf" = ( +/obj/item/circuitboard/machine/medical_kiosk, +/obj/structure/frame/machine, +/obj/effect/spawner/random/engineering/tool, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"hp" = ( +/obj/structure/table/reinforced, +/obj/item/gps/spaceruin{ + pixel_x = 6; + pixel_y = 2 + }, +/obj/item/storage/backpack/industrial{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/item/clothing/suit/hazardvest{ + pixel_x = -8; + pixel_y = -6 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"hu" = ( +/obj/structure/filingcabinet/chestdrawer, +/obj/item/stack/spacecash/c20, +/obj/item/pen/fountain, +/obj/structure/broken_flooring/singular, +/obj/item/swab, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"hv" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/reagent_containers/pill/maintenance{ + pixel_x = 3; + pixel_y = 7 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"io" = ( +/obj/structure/closet/body_bag, +/obj/structure/table/optable, +/obj/effect/mob_spawn/corpse/human{ + brute_damage = 35; + mob_type = /mob/living/carbon/human/species/fly; + oxy_damage = 65 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"iw" = ( +/obj/structure/lattice, +/obj/structure/grille, +/obj/effect/spawner/random/entertainment/plushie, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"iU" = ( +/obj/effect/spawner/random/trash/garbage, +/obj/effect/spawner/random/medical/medkit, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"kf" = ( +/obj/machinery/power/smes, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"kl" = ( +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"kp" = ( +/obj/structure/safe, +/obj/item/stamp/syndicate, +/obj/item/traitor_bug, +/obj/item/eyesnatcher, +/obj/item/stack/spacecash/c1000, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"kx" = ( +/obj/structure/lattice, +/obj/structure/grille, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"lT" = ( +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"mB" = ( +/obj/effect/spawner/random/engineering/tank, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"mZ" = ( +/obj/machinery/airalarm{ + pixel_y = 25 + }, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"nW" = ( +/obj/item/storage/box/disks{ + pixel_x = -7; + pixel_y = -3 + }, +/obj/structure/broken_flooring/singular, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"pu" = ( +/obj/structure/plasticflaps/opaque, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"py" = ( +/obj/structure/closet/body_bag, +/obj/structure/table/optable, +/obj/item/surgical_drapes, +/obj/effect/mob_spawn/corpse/human{ + brute_damage = 50; + burn_damage = 50 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"pD" = ( +/obj/machinery/iv_drip/saline, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"pR" = ( +/obj/machinery/iv_drip, +/obj/item/storage/box/syringes{ + pixel_x = 6; + pixel_y = -2 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"qh" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/rack_parts, +/obj/item/storage/pill_bottle/mannitol, +/obj/item/retractor/advanced, +/obj/effect/decal/cleanable/oil/slippery, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"qC" = ( +/turf/closed/wall/mineral/titanium, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"qX" = ( +/obj/effect/decal/cleanable/plastic, +/obj/structure/broken_flooring/corner, +/obj/item/trash/syndi_cakes, +/obj/item/trash/syndi_cakes, +/obj/item/trash/syndi_cakes, +/obj/item/poster/random_contraband, +/obj/item/organ/internal/tongue/zombie, +/obj/structure/closet/crate/trashcart, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"rB" = ( +/obj/structure/closet/crate/freezer, +/obj/item/stack/medical/bone_gel, +/obj/item/stack/medical/ointment, +/obj/item/thermometer, +/obj/effect/decal/cleanable/blood/splatter, +/obj/item/clothing/suit/apron/surgical, +/obj/item/clothing/neck/stethoscope, +/obj/item/clothing/neck/stethoscope, +/obj/item/biopsy_tool, +/obj/effect/spawner/random/contraband/narcotics, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"sa" = ( +/obj/structure/frame/computer, +/obj/item/circuitboard/computer/operating, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"sU" = ( +/obj/structure/lattice/catwalk, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"tI" = ( +/obj/structure/tank_holder/anesthetic, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"uo" = ( +/obj/machinery/computer/terminal{ + content = list("Property of Spinward-Upsilon Sanitation Department. Authorised employees only."); + desc = "A garbage truck's dusty old control console."; + name = "dashboard"; + upperinfo = "Controls locked." + }, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"uG" = ( +/obj/structure/chair/plastic, +/obj/item/reagent_containers/syringe/lethal/choral, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"uR" = ( +/obj/machinery/iv_drip, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/plastic, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"vf" = ( +/obj/structure/table/reinforced, +/obj/machinery/cell_charger, +/obj/item/stock_parts/cell/lead, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"vM" = ( +/obj/structure/closet/cardboard, +/obj/item/toy/plush/snakeplushie, +/obj/item/bodypart/arm/left/robot/surplus, +/obj/item/clothing/glasses/eyepatch, +/obj/item/toy/nuke, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"wh" = ( +/mob/living/basic/trooper/syndicate/ranged, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"wk" = ( +/obj/structure/frame/computer, +/obj/effect/decal/cleanable/glass, +/obj/effect/decal/cleanable/cobweb, +/obj/item/circuitboard/computer/operating, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"xj" = ( +/obj/structure/window/reinforced/shuttle, +/obj/structure/grille, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"xw" = ( +/obj/item/restraints/handcuffs/cable/zipties/used, +/obj/structure/closet/crate/trashcart/filled, +/obj/item/reagent_containers/condiment/soysauce, +/obj/item/reagent_containers/pill/mannitol, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"xH" = ( +/obj/item/food/badrecipe/moldy, +/obj/item/food/badrecipe/moldy, +/obj/structure/closet/mini_fridge/grimy, +/obj/effect/decal/cleanable/oil, +/obj/item/reagent_containers/cup/bottle/morphine, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"zb" = ( +/obj/item/wheelchair, +/obj/item/cane/white, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"zj" = ( +/obj/structure/table/rolling{ + desc = "An Interdyne Pharmaceutics brand 'Crash Cart Classic' rolling table for surgical tools. It can and will move."; + name = "rolling surgical tray" + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"zn" = ( +/obj/structure/closet/cardboard, +/obj/item/stack/medical/suture, +/obj/item/stack/medical/gauze, +/obj/item/stack/sticky_tape/surgical, +/obj/structure/broken_flooring/corner, +/obj/item/organ/internal/cyberimp/arm/surgery, +/obj/item/organ/internal/cyberimp/eyes/hud/medical, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"zu" = ( +/obj/structure/toilet{ + anchored = 0 + }, +/obj/effect/spawner/random/contraband/permabrig_weapon, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"zZ" = ( +/obj/item/pillow, +/obj/structure/closet/crate/trashcart/laundry, +/obj/item/bodybag, +/obj/item/bodybag, +/obj/item/clothing/under/rank/medical/scrubs/blue, +/obj/item/clothing/under/rank/medical/scrubs/blue, +/obj/item/clothing/under/rank/medical/scrubs/coroner, +/obj/item/clothing/under/rank/medical/scrubs/green, +/obj/item/clothing/under/rank/medical/scrubs/green, +/obj/item/clothing/suit/toggle/labcoat, +/obj/item/clothing/suit/toggle/labcoat, +/obj/item/clothing/suit/toggle/labcoat, +/obj/item/clothing/suit/toggle/labcoat, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Al" = ( +/obj/structure/frame/computer, +/obj/effect/decal/cleanable/glass, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Am" = ( +/obj/structure/mannequin/plastic, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"AB" = ( +/obj/structure/shipping_container/interdyne{ + armor_type = /datum/armor/immune + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"AG" = ( +/obj/structure/chair/comfy/shuttle, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"AU" = ( +/obj/item/paper/crumpled, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/broken_flooring/side, +/obj/item/suppressor, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"BE" = ( +/obj/structure/table/reinforced, +/obj/item/storage/bag/trash{ + pixel_x = -12; + pixel_y = 0 + }, +/obj/item/storage/bag/trash, +/obj/item/storage/bag/trash{ + pixel_x = -6; + pixel_y = 0 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Cv" = ( +/obj/item/storage/box/mousetraps, +/obj/structure/table/reinforced, +/obj/item/melee/flyswatter, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"CJ" = ( +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"CM" = ( +/obj/item/toy/braintoy, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/fuel_pool, +/obj/structure/closet/crate/trashcart, +/obj/item/shard, +/obj/item/stack/cable_coil, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"CU" = ( +/obj/structure/mannequin/skeleton, +/obj/structure/broken_flooring/plating, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Dj" = ( +/obj/item/food/deadmouse/moldy, +/obj/item/statuebust/hippocratic, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Dv" = ( +/obj/item/popsicle_stick{ + pixel_x = -4; + pixel_y = 9 + }, +/obj/item/rack_parts, +/obj/item/shard, +/obj/item/wrench/medical, +/obj/effect/decal/cleanable/plastic, +/obj/effect/spawner/random/contraband/permabrig_gear, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"EJ" = ( +/obj/item/stack/sticky_tape/surgical, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Go" = ( +/obj/effect/decal/cleanable/dirt, +/obj/item/reagent_containers/pill/cyanide{ + pixel_y = 8 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Gp" = ( +/obj/item/organ/internal/eyes/robotic/basic, +/obj/item/kitchen/spoon, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Hx" = ( +/obj/effect/decal/cleanable/plastic, +/obj/structure/closet/crate/freezer, +/obj/item/skillchip/entrails_reader, +/obj/item/mod/module/health_analyzer, +/obj/item/shovel, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"HE" = ( +/obj/structure/bed/maint, +/obj/structure/bedsheetbin, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"IM" = ( +/obj/effect/decal/cleanable/robot_debris, +/obj/structure/closet/crate/freezer, +/obj/item/organ/internal/liver/roach, +/obj/item/organ/internal/stomach, +/obj/item/organ/internal/tongue/robot, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"IS" = ( +/obj/structure/broken_flooring/singular, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"JW" = ( +/obj/item/plate, +/obj/effect/decal/cleanable/plastic, +/obj/structure/closet/crate/trashcart, +/obj/item/food/deadmouse, +/obj/effect/spawner/random/medical/medkit, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Kk" = ( +/obj/item/wheelchair, +/obj/item/screwdriver, +/obj/effect/spawner/random/maintenance/three, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Ky" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Lh" = ( +/obj/item/food/deadmouse/moldy, +/obj/item/pushbroom, +/obj/item/storage/bag/trash/filled, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Ll" = ( +/obj/item/trash/boritos/red, +/obj/item/storage/box/gloves, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"LA" = ( +/obj/item/mail/junkmail, +/obj/effect/decal/cleanable/plastic, +/obj/item/clothing/mask/surgical, +/obj/item/extinguisher/empty, +/obj/item/sticker/assistant, +/obj/item/reagent_containers/cup/coffeepot, +/obj/item/coffee_cartridge/decaf, +/obj/structure/closet/crate/trashcart, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"LG" = ( +/obj/structure/lattice/catwalk, +/obj/item/crowbar/large/emergency, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"LI" = ( +/obj/structure/table/reinforced, +/obj/item/gas_filter, +/obj/item/gas_filter, +/obj/item/clothing/mask/gas, +/obj/item/clothing/head/utility/hardhat/orange{ + pixel_y = 8 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"LR" = ( +/obj/machinery/power/terminal, +/obj/structure/tank_dispenser/oxygen, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"MC" = ( +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"NJ" = ( +/obj/structure/table/reinforced, +/obj/item/storage/box/gloves{ + pixel_x = 10; + pixel_y = 8 + }, +/obj/item/storage/box/masks{ + pixel_x = -6; + pixel_y = 8 + }, +/obj/machinery/recharger{ + pixel_y = -10 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Od" = ( +/obj/item/clothing/head/cone{ + pixel_x = 8; + pixel_y = 8 + }, +/obj/machinery/light/warm, +/obj/machinery/power/apc{ + cell_type = /obj/item/stock_parts/cell/lead; + locked = 0; + pixel_y = -25; + start_charge = 0 + }, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Ok" = ( +/obj/item/reagent_containers/pill/cyanide, +/obj/effect/spawner/random/medical/minor_healing, +/obj/effect/spawner/random/medical/surgery_tool, +/obj/item/reagent_containers/blood/o_minus, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"OA" = ( +/obj/machinery/door/airlock/shuttle, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Pd" = ( +/obj/structure/lattice, +/obj/structure/grille/broken, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Pe" = ( +/obj/effect/decal/cleanable/robot_debris/up, +/obj/structure/frame/computer, +/obj/item/stack/sheet/glass{ + amount = 2 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"PM" = ( +/obj/structure/closet/mini_fridge/grimy, +/obj/item/storage/organbox, +/obj/effect/decal/cleanable/blood/gibs/old, +/obj/item/storage/pill_bottle/epinephrine, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Qq" = ( +/obj/structure/microscope, +/obj/structure/broken_flooring/singular, +/obj/effect/spawner/random/trash/food_packaging, +/obj/item/instrument/bilehorn, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"QK" = ( +/obj/effect/decal/cleanable/robot_debris/down, +/obj/item/circular_saw, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Rn" = ( +/obj/structure/closet/crate/cardboard, +/obj/item/book/manual/wiki/surgery, +/obj/item/book/manual/wiki/surgery, +/obj/item/book/manual/wiki/medicine{ + name = "Medical Space Compendium, Volume 637" + }, +/obj/item/book/manual/wiki/medicine{ + name = "Medical Space Compendium, Volume 637" + }, +/obj/item/book/manual/wiki/medicine{ + name = "Medical Space Compendium, Volume 637" + }, +/obj/item/book/manual/wiki/medicine{ + name = "Medical Space Compendium, Volume 637" + }, +/obj/item/stamp/denied, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"RT" = ( +/obj/structure/frame/machine, +/obj/item/shard, +/obj/effect/decal/cleanable/glass, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Tp" = ( +/obj/structure/barricade/wooden, +/obj/structure/barricade/wooden/crude, +/obj/structure/curtain/cloth, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"TM" = ( +/obj/structure/closet/body_bag, +/obj/structure/table/optable, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mob_spawn/corpse/human{ + brute_damage = 200; + mob_type = /mob/living/carbon/human/species/lizard + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Ua" = ( +/obj/structure/table/reinforced, +/obj/item/analyzer{ + pixel_y = 6 + }, +/obj/item/geiger_counter{ + pixel_x = -8; + pixel_y = -2 + }, +/obj/item/flashlight{ + pixel_x = 4 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Um" = ( +/obj/effect/decal/cleanable/garbage, +/obj/item/lipstick, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"UJ" = ( +/obj/item/storage/box/masks, +/obj/item/storage/box/masks, +/obj/item/storage/box/masks, +/obj/item/clothing/mask/surgical, +/obj/item/reagent_containers/spray/cleaner{ + pixel_x = 7; + pixel_y = 5 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"VL" = ( +/obj/machinery/power/shuttle_engine/propulsion, +/turf/open/space/basic, +/area/space) +"WX" = ( +/obj/machinery/light/warm, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"XC" = ( +/obj/structure/sign/warning, +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"XD" = ( +/obj/structure/sinkframe, +/obj/structure/broken_flooring/pile, +/obj/effect/decal/cleanable/blood/gibs/old, +/obj/item/reagent_containers/cup/rag{ + pixel_x = 6; + pixel_y = -3 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"XR" = ( +/obj/structure/broken_flooring/pile, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Yj" = ( +/obj/structure/reflector/single/mapping{ + rotation_angle = 360 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) +"Zi" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/shuttle, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/medicalwaste) + +(1,1,1) = {" +gh +gh +sU +sU +sU +qC +VL +gh +gh +gh +gh +gh +gh +gh +gh +gh +gh +gh +gh +gh +"} +(2,1,1) = {" +gh +qC +xj +xj +qC +qC +MC +MC +MC +MC +MC +MC +MC +MC +MC +MC +MC +MC +MC +MC +"} +(3,1,1) = {" +Pd +Zi +NJ +vf +Cv +qC +MC +wk +nW +sa +HE +PM +zZ +hu +vM +AB +py +io +TM +XC +"} +(4,1,1) = {" +iw +xj +uo +AG +WX +qC +MC +Dj +XR +Al +QK +CJ +Um +zb +tI +CJ +uG +CJ +Ok +MC +"} +(5,1,1) = {" +kx +xj +hp +LI +kl +qC +MC +Pe +CJ +CJ +CJ +eO +CJ +CJ +Kk +CJ +zj +Go +bv +MC +"} +(6,1,1) = {" +Pd +xj +Zi +qC +mZ +OA +gr +CJ +Ky +iU +Rn +CM +qh +CJ +wh +CJ +CJ +Ky +Yj +MC +"} +(7,1,1) = {" +Pd +Zi +BE +Ua +kl +OA +gr +CJ +CJ +mB +Dv +rB +JW +CJ +EJ +AB +xw +CJ +kp +MC +"} +(8,1,1) = {" +iw +Zi +lT +lT +kl +qC +MC +uR +CJ +CJ +hv +CJ +CJ +CJ +Gp +CJ +pD +CJ +IM +MC +"} +(9,1,1) = {" +Pd +Zi +lT +kl +Od +qC +MC +pR +eO +XD +UJ +RT +Lh +CJ +Hx +CJ +zu +IS +bb +MC +"} +(10,1,1) = {" +kx +Zi +lT +LR +kf +qC +MC +CU +Ll +xH +Qq +hf +LA +CJ +Am +Tp +zn +AU +qX +XC +"} +(11,1,1) = {" +gh +qC +gy +Zi +qC +qC +MC +MC +MC +MC +MC +MC +MC +pu +pu +pu +MC +MC +MC +MC +"} +(12,1,1) = {" +gh +gh +sU +sU +LG +qC +VL +gh +gh +gh +gh +gh +gh +gh +gh +gh +gh +gh +gh +gh +"} diff --git a/_maps/RandomRuins/SpaceRuins/garbagetruck3.dmm b/_maps/RandomRuins/SpaceRuins/garbagetruck3.dmm new file mode 100644 index 00000000000000..45947bb4112637 --- /dev/null +++ b/_maps/RandomRuins/SpaceRuins/garbagetruck3.dmm @@ -0,0 +1,1185 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"ac" = ( +/obj/item/trash/semki/healthy, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"ap" = ( +/obj/machinery/power/terminal, +/obj/structure/tank_dispenser/oxygen, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/squat) +"aG" = ( +/obj/item/storage/toolbox/electrical{ + pixel_x = 9; + pixel_y = 8 + }, +/obj/item/storage/toolbox/mechanical{ + pixel_x = -9; + pixel_y = 8 + }, +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/storage/toolbox/mechanical{ + pixel_x = -9; + pixel_y = 2 + }, +/obj/item/stack/rods/ten, +/obj/structure/closet/crate/preopen, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"aI" = ( +/obj/structure/bed/maint, +/obj/item/knife/shiv, +/obj/item/storage/backpack/satchel/leather/withwallet, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"bb" = ( +/obj/item/food/badrecipe/moldy, +/obj/item/tank/internals/plasma/empty{ + pixel_x = -10; + pixel_y = 4 + }, +/obj/item/tank/internals/plasma/empty{ + pixel_y = 4 + }, +/obj/item/popsicle_stick, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"bP" = ( +/obj/item/cigbutt/cigarbutt, +/obj/effect/decal/cleanable/dirt, +/obj/item/reagent_containers/syringe/contraband/krokodil, +/obj/item/screwdriver, +/obj/effect/decal/cleanable/fuel_pool, +/obj/structure/reagent_dispensers/fueltank/large, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"bR" = ( +/obj/item/bedsheet/rainbow, +/obj/item/cigbutt, +/obj/item/clothing/ears/earmuffs, +/obj/structure/bed/maint, +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/spawner/random/contraband/permabrig_gear, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"dh" = ( +/obj/machinery/light/warm, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/squat) +"do" = ( +/obj/structure/chair/comfy/shuttle, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/squat) +"dC" = ( +/obj/item/storage/box/mousetraps, +/obj/structure/table/reinforced, +/obj/item/melee/flyswatter, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/squat) +"dF" = ( +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/squat) +"dL" = ( +/obj/item/toy/mecha/marauder, +/obj/structure/closet/cardboard, +/obj/item/toy/plush/snakeplushie, +/obj/item/storage/fancy/cigarettes/cigpack_robust, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"fF" = ( +/obj/item/clothing/suit/caution, +/obj/item/trash/syndi_cakes, +/obj/effect/decal/cleanable/plastic, +/obj/item/t_scanner, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"gq" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/shuttle, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/squat) +"gy" = ( +/obj/structure/window/reinforced/shuttle, +/obj/structure/grille, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/squat) +"hk" = ( +/obj/structure/table/reinforced, +/obj/item/storage/bag/trash{ + pixel_x = -12; + pixel_y = 0 + }, +/obj/item/storage/bag/trash, +/obj/item/storage/bag/trash{ + pixel_x = -6; + pixel_y = 0 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/squat) +"hm" = ( +/obj/item/mecha_parts/chassis/ripley, +/obj/item/mecha_parts/part/ripley_right_leg{ + pixel_x = 4; + pixel_y = -8 + }, +/obj/item/mecha_parts/part/ripley_left_leg{ + pixel_x = -4; + pixel_y = -7 + }, +/obj/item/mecha_parts/part/ripley_torso, +/obj/effect/decal/cleanable/fuel_pool, +/obj/structure/closet/crate/large{ + desc = "A hefty wooden crate with the word \"REJECT\" stamped on it. You'll need a crowbar to get it open." + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"ih" = ( +/obj/item/bedsheet/purple, +/obj/item/clothing/mask/cigarette/space_cigarette, +/obj/structure/bed/maint, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"iU" = ( +/obj/structure/chair/stool, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"jl" = ( +/obj/structure/table/reinforced, +/obj/item/gps/spaceruin{ + pixel_x = 6; + pixel_y = 2 + }, +/obj/item/storage/backpack/industrial{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/item/clothing/suit/hazardvest{ + pixel_x = -8; + pixel_y = -6 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/squat) +"jJ" = ( +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"jN" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/stock_parts/scanning_module, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"jZ" = ( +/obj/machinery/door/airlock/external/glass, +/obj/structure/fans/tiny, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/squat) +"kb" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/stock_parts/cell/crap/empty, +/obj/effect/decal/cleanable/plastic, +/obj/effect/spawner/random/maintenance/two, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"kR" = ( +/obj/item/tank/internals/oxygen/yellow, +/obj/structure/closet/crate/preopen, +/obj/effect/decal/cleanable/shreds, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"la" = ( +/obj/structure/lattice, +/obj/structure/grille/broken, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/squat) +"le" = ( +/obj/structure/door_assembly/door_assembly_mhatch, +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/shard, +/obj/item/stack/cable_coil/cut, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"lv" = ( +/obj/item/storage/box/zipties{ + pixel_x = -6; + pixel_y = 3 + }, +/obj/item/storage/box/stockparts/basic{ + pixel_x = 8; + pixel_y = -2 + }, +/obj/item/storage/box/disks{ + pixel_x = -8; + pixel_y = -4 + }, +/obj/structure/closet/crate/large, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"lA" = ( +/obj/item/sticker/toolbox, +/obj/structure/closet/crate/cardboard, +/obj/item/book/manual/wiki/engineering_guide, +/obj/item/book/manual/wiki/engineering_construction, +/obj/item/book/manual/ripley_build_and_repair, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"lE" = ( +/obj/machinery/airalarm{ + pixel_y = 25 + }, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/squat) +"lY" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"mV" = ( +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/garbagetruck/squat) +"nX" = ( +/obj/structure/closet/crate/engineering/electrical, +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/electronics/airlock, +/obj/item/electronics/airlock, +/obj/item/electronics/airlock, +/obj/item/electronics/airlock, +/obj/item/electronics/airlock, +/obj/item/electronics/airlock, +/obj/item/electronics/airlock, +/obj/item/electronics/airlock, +/obj/item/electronics/airlock, +/obj/item/electronics/airlock, +/obj/item/electronics/firelock, +/obj/item/electronics/firelock, +/obj/item/electronics/firelock, +/obj/item/electronics/firelock, +/obj/item/electronics/firelock, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"oD" = ( +/obj/effect/spawner/random/trash/cigbutt, +/obj/item/trash/boritos/purple, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"pd" = ( +/obj/item/stack/rods/ten, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"pk" = ( +/obj/structure/lattice/catwalk, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/squat) +"pC" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/storage/bag/construction, +/obj/item/clothing/shoes/winterboots/ice_boots/eva{ + desc = "A heavy pair of boots with grips applied to the bottom to keep the wearer vertical while walking in freezing conditions. It's clearly been well used."; + name = "ice climbing boots" + }, +/obj/structure/closet/crate/engineering/electrical, +/obj/item/stock_parts/capacitor/adv, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"pM" = ( +/obj/item/lead_pipe, +/obj/structure/door_assembly/door_assembly_mhatch, +/obj/effect/decal/cleanable/glass, +/obj/item/restraints/handcuffs/cable/zipties/used, +/obj/item/shard, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"qF" = ( +/obj/structure/closet/cardboard, +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/pushbroom, +/obj/item/restraints/handcuffs/cable/zipties/used, +/obj/item/toy/brokenradio, +/obj/effect/spawner/random/engineering/tool, +/mob/living/basic/cockroach, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"rq" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/decal/cleanable/dirt, +/obj/structure/bed/dogbed, +/turf/open/floor/plating/dumpsterair, +/area/space) +"sb" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/boxcutter, +/obj/item/boxcutter, +/obj/item/folder/yellow, +/obj/item/geiger_counter, +/obj/item/stack/sticky_tape, +/obj/structure/closet/crate/preopen, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"sf" = ( +/obj/item/burner/fuel{ + pixel_x = -5; + pixel_y = -2 + }, +/obj/effect/decal/cleanable/glass, +/obj/effect/decal/cleanable/ash, +/obj/item/reagent_containers/cup/beaker/plastic{ + pixel_x = -5; + pixel_y = 4 + }, +/obj/structure/table, +/obj/item/reagent_containers/dropper{ + pixel_x = 7; + pixel_y = 0 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"sF" = ( +/obj/structure/table/reinforced, +/obj/item/storage/box/gloves{ + pixel_x = 10; + pixel_y = 8 + }, +/obj/item/storage/box/masks{ + pixel_x = -6; + pixel_y = 8 + }, +/obj/machinery/recharger{ + pixel_y = -10 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/squat) +"tu" = ( +/obj/item/clothing/mask/cigarette/robust, +/obj/structure/closet/emcloset, +/obj/item/clothing/suit/utility/fire/heavy, +/obj/item/clothing/head/utility/hardhat/welding/atmos, +/obj/item/survivalcapsule/bathroom, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"tL" = ( +/obj/structure/reagent_dispensers/fueltank/large, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"ui" = ( +/obj/item/rollingpaper, +/obj/item/book/random{ + pixel_x = 7; + pixel_y = 2 + }, +/obj/item/clothing/gloves/fingerless{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/structure/table, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"un" = ( +/obj/item/food/branrequests, +/obj/item/kitchen/spoon/plastic, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"ut" = ( +/obj/item/clothing/suit/apron/overalls{ + pixel_y = -3 + }, +/obj/effect/decal/cleanable/fuel_pool, +/obj/structure/reagent_dispensers/fueltank/large, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"uW" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/decal/cleanable/fuel_pool, +/obj/structure/bonfire{ + desc = "Begging to be lit." + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"vq" = ( +/obj/item/shard, +/obj/effect/decal/cleanable/fuel_pool, +/obj/structure/closet/crate/trashcart/filled, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"vI" = ( +/obj/item/clothing/head/beanie/red{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/clothing/glasses/regular, +/obj/structure/table, +/obj/item/food/grown/kronkus{ + pixel_x = -5; + pixel_y = 8 + }, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"vJ" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/decal/cleanable/molten_object/large, +/obj/structure/broken_flooring/pile, +/obj/item/food/deadmouse/moldy, +/obj/item/stock_parts/water_recycler, +/obj/item/stock_parts/cell/lead, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"vW" = ( +/obj/effect/spawner/random/engineering/material_cheap, +/obj/structure/girder/displaced, +/obj/item/stock_parts/scanning_module, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"xg" = ( +/obj/structure/chair/office, +/obj/item/reagent_containers/cup/mortar, +/obj/item/pestle, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"yo" = ( +/obj/item/clothing/head/cone{ + pixel_x = 8; + pixel_y = 8 + }, +/obj/machinery/light/warm, +/obj/machinery/power/apc{ + cell_type = /obj/item/stock_parts/cell/lead; + locked = 0; + pixel_y = -25; + start_charge = 0 + }, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/squat) +"yF" = ( +/obj/item/trash/spacers_sidekick, +/obj/item/trash/flare, +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/spawner/random/contraband/narcotics, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"za" = ( +/obj/item/cigbutt/cigarbutt{ + desc = "A manky old cigar butt. A little cobweb is on the end."; + pixel_x = -8; + pixel_y = -2 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"zh" = ( +/obj/item/cigbutt, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"zo" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/structure/girder/displaced, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"zz" = ( +/obj/item/cigbutt/cigarbutt, +/obj/effect/decal/cleanable/oil, +/obj/effect/decal/cleanable/fuel_pool, +/obj/structure/closet/crate/trashcart, +/obj/item/storage/bag/trash, +/obj/item/clothing/shoes/sneakers/black, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"zC" = ( +/obj/structure/lattice, +/obj/structure/grille, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/squat) +"zN" = ( +/obj/structure/table/reinforced, +/obj/item/gas_filter, +/obj/item/gas_filter, +/obj/item/clothing/mask/gas, +/obj/item/clothing/head/utility/hardhat/orange{ + pixel_y = 8 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/squat) +"zY" = ( +/obj/effect/decal/cleanable/dirt, +/obj/item/toy/minimeteor, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"BN" = ( +/obj/item/tank/internals/plasma/full, +/obj/effect/decal/cleanable/fuel_pool, +/obj/structure/reagent_dispensers/fueltank/large, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Cm" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/mod/module/jetpack, +/obj/item/stock_parts/servo, +/obj/item/stock_parts/subspace/filter, +/obj/structure/fluff/oldturret, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Dq" = ( +/obj/item/match, +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/spawner/random/entertainment/cigarette, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"DR" = ( +/obj/item/shard/plasma{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/item/trash/semki{ + pixel_x = 6; + pixel_y = 6 + }, +/obj/item/food/badrecipe/moldy{ + pixel_x = -6; + pixel_y = -4 + }, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Er" = ( +/obj/item/clothing/suit/space, +/obj/item/clothing/head/helmet/space, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Fe" = ( +/obj/structure/fermenting_barrel, +/obj/item/reagent_containers/cup/bottle/welding_fuel{ + pixel_x = 9; + pixel_y = -6 + }, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"FD" = ( +/obj/structure/table/reinforced, +/obj/item/analyzer{ + pixel_y = 6 + }, +/obj/item/geiger_counter{ + pixel_x = -8; + pixel_y = -2 + }, +/obj/item/flashlight{ + pixel_x = 4 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/squat) +"FN" = ( +/obj/item/storage/fancy/cigarettes/cigpack_robust{ + pixel_x = -9; + pixel_y = 4 + }, +/obj/item/storage/fancy/cigarettes/cigpack_robust{ + pixel_x = 1; + pixel_y = 4 + }, +/obj/structure/closet/crate/cardboard, +/obj/item/storage/fancy/cigarettes/cigpack_syndicate{ + pixel_x = -9 + }, +/obj/item/storage/fancy/cigarettes/cigpack_shadyjims{ + pixel_x = 1 + }, +/obj/item/gas_filter/damaged{ + pixel_x = -5; + pixel_y = -4 + }, +/obj/item/clothing/mask/gas{ + pixel_x = 1; + pixel_y = -3 + }, +/obj/item/clothing/mask/gas{ + desc = "This gas mask feels different. It's not quite like the others."; + pixel_x = -1; + pixel_y = -3 + }, +/obj/item/clothing/mask/gas{ + pixel_x = -4; + pixel_y = -3 + }, +/obj/item/clothing/mask/gas{ + pixel_x = -7; + pixel_y = -3 + }, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Gn" = ( +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/squat) +"Hk" = ( +/obj/item/food/pizzaslice/moldy/bacteria, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Hn" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/decal/cleanable/oil/slippery, +/obj/item/pen, +/obj/item/stock_parts/subspace/analyzer, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Hw" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"HD" = ( +/obj/structure/mecha_wreckage/ripley, +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/decal/cleanable/molten_object, +/obj/item/organ/internal/tongue/robot, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"HN" = ( +/obj/structure/table/reinforced, +/obj/machinery/cell_charger, +/obj/item/stock_parts/cell/lead, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/squat) +"HZ" = ( +/turf/closed/wall/mineral/titanium, +/area/ruin/space/has_grav/garbagetruck/squat) +"Jx" = ( +/obj/structure/chem_separator, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"JL" = ( +/obj/machinery/space_heater/improvised_chem_heater, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"JO" = ( +/obj/item/storage/pill_bottle/stimulant{ + pixel_x = 1; + pixel_y = 3 + }, +/obj/item/storage/pill_bottle/maintenance_pill/full{ + pixel_x = -2; + pixel_y = -2 + }, +/obj/structure/closet/crate/preopen, +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/reagent_containers/syringe/contraband/methamphetamine{ + pixel_x = -5; + pixel_y = -7 + }, +/obj/item/reagent_containers/syringe/contraband/krokodil{ + pixel_x = -1; + pixel_y = -2 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"JR" = ( +/obj/effect/decal/cleanable/ash, +/obj/effect/decal/cleanable/oil/streak, +/mob/living/basic/trooper/russian, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"JW" = ( +/obj/machinery/door/poddoor/shutters/preopen, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"JX" = ( +/turf/open/space/basic, +/area/space) +"Ko" = ( +/obj/machinery/computer/terminal{ + content = list("Property of Spinward-Upsilon Sanitation Department. Authorised employees only."); + desc = "A garbage truck's dusty old control console."; + name = "dashboard"; + upperinfo = "Controls locked." + }, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/squat) +"Kq" = ( +/obj/structure/closet/crate, +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/airlock_painter, +/obj/item/pen/screwdriver, +/obj/item/rcd_ammo, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"LV" = ( +/obj/machinery/power/smes, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/squat) +"Ml" = ( +/obj/structure/plasticflaps/opaque, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"MJ" = ( +/obj/structure/lattice/catwalk, +/obj/item/crowbar/large/emergency, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/squat) +"MQ" = ( +/obj/item/stock_parts/cell/crap/empty{ + pixel_x = -4; + pixel_y = 10 + }, +/obj/item/clothing/mask/cigarette/space_cigarette{ + pixel_x = -5; + pixel_y = 7 + }, +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/crowbar/hammer{ + desc = "A large claw hammer. It's been heavily used, as evidenced by the dents and scratches covering its head."; + name = "claw hammer" + }, +/obj/item/storage/fancy/cigarettes/cigpack_cannabis{ + pixel_x = 6; + pixel_y = 2 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Nd" = ( +/obj/item/binoculars, +/obj/item/crowbar/large/old, +/obj/item/tank/jetpack/improvised, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Ol" = ( +/obj/item/plate_shard, +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/decal/cleanable/oil, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Pz" = ( +/obj/structure/sign/warning, +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/garbagetruck/squat) +"PE" = ( +/obj/machinery/door/airlock/shuttle, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/squat) +"PH" = ( +/obj/item/bikehorn/rubberducky, +/obj/structure/closet/mini_fridge/grimy, +/obj/item/reagent_containers/cup/soda_cans/grey_bull, +/obj/item/reagent_containers/cup/soda_cans/monkey_energy, +/obj/item/reagent_containers/cup/soda_cans/monkey_energy, +/obj/item/reagent_containers/cup/soda_cans/pwr_game, +/obj/item/reagent_containers/cup/blastoff_ampoule, +/obj/structure/table, +/obj/item/food/drug/moon_rock, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Rw" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"RD" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"RP" = ( +/obj/structure/table, +/obj/item/food/drug/moon_rock{ + pixel_x = 7; + pixel_y = 4 + }, +/obj/item/lighter/skull{ + light_color = "#F57247"; + pixel_x = 8; + pixel_y = -3 + }, +/obj/item/weldingtool/largetank{ + light_color = "#F57247"; + max_fuel = 50; + pixel_x = -7; + pixel_y = 3 + }, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Ss" = ( +/obj/item/cigbutt/roach, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"To" = ( +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Tv" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/trash/can/food/beans{ + pixel_x = 8; + pixel_y = -4 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"TD" = ( +/obj/item/food/deadmouse, +/obj/item/trash/candy, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Vw" = ( +/obj/item/rollingpaper{ + pixel_x = 8; + pixel_y = -6 + }, +/obj/item/rollingpaper{ + pixel_x = -2; + pixel_y = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/closet/crate/wooden, +/obj/item/clothing/glasses/night{ + pixel_x = -1; + pixel_y = -2 + }, +/obj/item/melee/roastingstick{ + pixel_x = 11 + }, +/obj/item/flamethrower/full/tank{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"VL" = ( +/obj/machinery/power/shuttle_engine/propulsion, +/turf/open/space/basic, +/area/space) +"WK" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/clothing/shoes/workboots{ + pixel_x = 7; + pixel_y = 5 + }, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"WV" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Xt" = ( +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Xv" = ( +/obj/item/food/deadmouse, +/obj/item/clothing/shoes/sneakers/red, +/obj/item/clothing/mask/cigarette/carp, +/obj/item/extinguisher/mini, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"XS" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/structure/firelock_frame, +/obj/structure/broken_flooring/pile, +/obj/item/reagent_containers/syringe/contraband/methamphetamine, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) +"Ye" = ( +/obj/structure/lattice, +/obj/structure/grille, +/obj/effect/spawner/random/entertainment/plushie, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/squat) +"Zu" = ( +/obj/item/food/candy, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/closet/crate/trashcart, +/obj/item/storage/bag/trash/filled, +/obj/item/trash/champagne_cork, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating/dumpsterair, +/area/ruin/space/has_grav/garbagetruck/squat) + +(1,1,1) = {" +JX +JX +pk +pk +pk +HZ +VL +JX +JX +JX +JX +JX +JX +JX +JX +JX +JX +JX +JX +JX +"} +(2,1,1) = {" +JX +HZ +gy +gy +HZ +HZ +mV +mV +mV +mV +mV +mV +mV +mV +mV +mV +mV +mV +mV +mV +"} +(3,1,1) = {" +la +gq +sF +HN +dC +HZ +mV +bR +ih +un +aI +rq +Fe +lv +pM +tu +hm +pC +fF +Pz +"} +(4,1,1) = {" +Ye +gy +Ko +do +dh +HZ +mV +ut +WK +zh +WV +Tv +za +aG +zo +HD +MQ +qF +Cm +mV +"} +(5,1,1) = {" +zC +gy +jl +zN +dF +HZ +mV +zz +Xt +jJ +Xt +Xt +DR +uW +XS +nX +BN +vJ +vW +mV +"} +(6,1,1) = {" +la +gy +gq +HZ +lE +PE +JW +WV +WV +WV +Xt +To +Hw +Hk +vq +zY +Hn +kb +le +mV +"} +(7,1,1) = {" +la +gq +hk +FD +dF +PE +JW +oD +Xt +JO +RD +To +Xt +TD +pd +JR +Kq +sb +dL +mV +"} +(8,1,1) = {" +Ye +gq +Gn +Gn +dF +HZ +mV +vI +Ss +sf +iU +Xt +Xt +ac +Xt +bb +jN +lA +kR +mV +"} +(9,1,1) = {" +la +gq +Gn +dF +yo +HZ +mV +ui +xg +RP +Jx +lY +JL +tL +Xt +Rw +To +Ol +To +mV +"} +(10,1,1) = {" +zC +gq +Gn +ap +LV +HZ +mV +PH +Xt +FN +Vw +bP +Zu +To +Dq +yF +Nd +Er +Xv +Pz +"} +(11,1,1) = {" +JX +HZ +jZ +gq +HZ +HZ +mV +mV +mV +mV +mV +mV +mV +Ml +Ml +Ml +mV +mV +mV +mV +"} +(12,1,1) = {" +JX +JX +pk +pk +MJ +HZ +VL +JX +JX +JX +JX +JX +JX +JX +JX +JX +JX +JX +JX +JX +"} diff --git a/_maps/RandomRuins/SpaceRuins/garbagetruck4.dmm b/_maps/RandomRuins/SpaceRuins/garbagetruck4.dmm new file mode 100644 index 00000000000000..761990a97d5976 --- /dev/null +++ b/_maps/RandomRuins/SpaceRuins/garbagetruck4.dmm @@ -0,0 +1,1147 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aj" = ( +/obj/machinery/power/smes, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/toystore) +"bL" = ( +/obj/structure/table/reinforced, +/obj/item/storage/bag/trash{ + pixel_x = -12; + pixel_y = 0 + }, +/obj/item/storage/bag/trash, +/obj/item/storage/bag/trash{ + pixel_x = -6; + pixel_y = 0 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/toystore) +"bU" = ( +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/toystore) +"cf" = ( +/obj/item/paint_palette, +/obj/item/storage/crayons, +/obj/structure/spider/stickyweb, +/obj/structure/table_frame/wood, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"cg" = ( +/obj/structure/spider/stickyweb, +/obj/item/clothing/under/costume/mummy, +/obj/item/clothing/mask/mummy, +/obj/effect/decal/cleanable/glass, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"cq" = ( +/obj/machinery/light/warm, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/toystore) +"cT" = ( +/obj/item/c_tube, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"dn" = ( +/obj/structure/window/reinforced/shuttle, +/obj/structure/grille, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"dq" = ( +/obj/effect/spawner/random/structure/crate_empty, +/obj/item/trash/candy{ + pixel_x = 7 + }, +/obj/item/lead_pipe{ + pixel_x = -2; + pixel_y = -4 + }, +/obj/item/plate_shard{ + pixel_x = 6; + pixel_y = 0 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"eL" = ( +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/toystore) +"hD" = ( +/obj/structure/mannequin/wood{ + desc = "Oh, so this is a dress-up game now. It makes eye contact." + }, +/obj/item/clothing/shoes/kindle_kicks{ + pixel_y = -10 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"hH" = ( +/obj/structure/spider/solid, +/obj/item/book/manual/wiki/cytology, +/obj/effect/decal/cleanable/plastic, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"hS" = ( +/obj/structure/closet/crate/trashcart/filled, +/obj/item/toy/xmas_cracker, +/obj/item/toy/xmas_cracker, +/obj/item/toy/toy_xeno, +/obj/item/clothing/head/costume/party/festive, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"it" = ( +/obj/item/trash/candle, +/obj/item/food/canned/pine_nuts, +/obj/item/kitchen/fork, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"jD" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/shuttle, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"kj" = ( +/obj/structure/mannequin/plastic, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"kz" = ( +/obj/item/storage/wallet/random, +/obj/item/coin/plastic, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"ld" = ( +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"lg" = ( +/obj/structure/lattice/catwalk, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/toystore) +"lm" = ( +/obj/structure/spider/stickyweb, +/obj/structure/spider/sticky, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"mf" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/spawner/random/structure/tank_holder, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"mM" = ( +/obj/structure/spider/stickyweb, +/obj/item/food/badrecipe/moldy, +/obj/item/storage/box/pdas, +/obj/effect/spawner/random/entertainment/money_small, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"ng" = ( +/obj/item/vending_refill/snack, +/obj/item/food/candy, +/obj/structure/broken_flooring/side, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"nM" = ( +/turf/closed/wall/mineral/titanium, +/area/ruin/space/has_grav/garbagetruck/toystore) +"nP" = ( +/obj/structure/bed/maint, +/obj/item/pen/survival, +/obj/item/bedsheet/grey, +/obj/effect/decal/cleanable/shreds, +/obj/effect/spawner/random/bureaucracy/pen, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"pi" = ( +/obj/item/chair/wood, +/obj/item/c_tube, +/obj/effect/decal/cleanable/generic, +/obj/structure/broken_flooring/corner, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"ps" = ( +/obj/effect/spawner/random/trash, +/obj/effect/spawner/random/bureaucracy/paper, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"pA" = ( +/obj/structure/spider/effigy, +/obj/structure/spider/stickyweb, +/obj/item/coin/silver, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"pN" = ( +/obj/structure/closet/crate/cardboard/mothic, +/obj/item/clothing/head/mothcap, +/obj/item/clothing/mask/gas/explorer, +/obj/item/clothing/under/misc/overalls, +/obj/item/clothing/shoes/magboots, +/obj/item/clothing/glasses/meson, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"qX" = ( +/obj/structure/spider/sticky, +/obj/item/food/badrecipe/moldy, +/obj/structure/spider/stickyweb, +/obj/item/food/spidereggs{ + pixel_x = 4; + pixel_y = 6 + }, +/obj/structure/closet/crate/trashcart, +/obj/item/food/spidereggs{ + pixel_x = -4; + pixel_y = 6 + }, +/obj/effect/spawner/random/trash/food_packaging, +/obj/item/food/spidereggs, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"rb" = ( +/obj/structure/sign/warning, +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/garbagetruck/toystore) +"rc" = ( +/obj/effect/decal/cleanable/oil, +/obj/item/flashlight/flare/torch, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"ri" = ( +/obj/structure/lattice/catwalk, +/obj/item/crowbar/large/emergency, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/toystore) +"rr" = ( +/obj/structure/floodlight_frame, +/obj/effect/spawner/random/decoration/glowstick, +/obj/effect/spawner/random/decoration/glowstick, +/obj/effect/spawner/random/decoration/glowstick, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"rI" = ( +/obj/structure/lattice, +/obj/structure/grille, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/toystore) +"sh" = ( +/obj/item/food/badrecipe/moldy/bacteria, +/obj/effect/decal/cleanable/ants, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"sw" = ( +/obj/effect/decal/cleanable/glass/plastitanium/screws, +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/cardboard_cutout, +/obj/item/clothing/neck/tie/horrible, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"sA" = ( +/obj/item/clothing/head/costume/rabbitears, +/obj/item/grown/bananapeel, +/obj/effect/decal/cleanable/garbage, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"sO" = ( +/obj/item/clothing/suit/syndicatefake, +/obj/item/weldingtool/largetank{ + pixel_x = -4; + pixel_y = 2 + }, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"ts" = ( +/obj/structure/spider/solid, +/obj/structure/spider/stickyweb, +/obj/structure/closet/crate/trashcart/filled, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"tQ" = ( +/obj/item/rack_parts, +/obj/structure/spider/stickyweb, +/obj/item/folder/blue{ + pixel_x = -3; + pixel_y = -2 + }, +/obj/item/folder/blue, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"ub" = ( +/obj/structure/filingcabinet, +/obj/structure/spider/stickyweb, +/obj/item/storage/wallet/random, +/obj/item/pen/blue, +/obj/item/paper/fluff/junkmail_redpill, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"uT" = ( +/obj/structure/table/reinforced, +/obj/item/gas_filter, +/obj/item/gas_filter, +/obj/item/clothing/mask/gas, +/obj/item/clothing/head/utility/hardhat/orange{ + pixel_y = 8 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/toystore) +"uX" = ( +/obj/structure/table/reinforced, +/obj/item/gps/spaceruin{ + pixel_x = 6; + pixel_y = 2 + }, +/obj/item/storage/backpack/industrial{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/item/clothing/suit/hazardvest{ + pixel_x = -8; + pixel_y = -6 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/toystore) +"vz" = ( +/obj/structure/frame/computer, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"wo" = ( +/obj/machinery/door/airlock/shuttle, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"wu" = ( +/obj/machinery/airalarm{ + pixel_y = 25 + }, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/toystore) +"ww" = ( +/obj/machinery/door/airlock/external/glass, +/obj/structure/fans/tiny, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"wy" = ( +/obj/item/barcodescanner, +/obj/effect/decal/cleanable/dirt, +/obj/item/cardpack/series_one{ + pixel_x = 2; + pixel_y = 1 + }, +/obj/item/cardpack/series_one{ + pixel_y = 4 + }, +/obj/item/cardpack/series_one{ + pixel_x = -3; + pixel_y = 2 + }, +/obj/item/cardpack/series_one, +/obj/structure/closet/crate/cardboard, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"wE" = ( +/obj/structure/closet/crate/wooden, +/obj/item/toy/figure/wizard{ + pixel_x = 8; + pixel_y = 6 + }, +/obj/item/toy/figure/clown{ + pixel_x = -2; + pixel_y = 6 + }, +/obj/item/toy/figure/secofficer{ + pixel_x = 2; + pixel_y = 2 + }, +/obj/item/toy/figure/secofficer{ + pixel_x = 8; + pixel_y = 2 + }, +/obj/item/toy/figure/secofficer{ + pixel_x = -4; + pixel_y = 2 + }, +/obj/item/toy/figure/dsquad{ + pixel_x = 4; + pixel_y = -1 + }, +/obj/item/toy/figure/dsquad{ + pixel_y = -1 + }, +/obj/item/toy/figure/dsquad{ + pixel_x = -4; + pixel_y = -1 + }, +/obj/item/toy/figure/dsquad{ + pixel_x = -8; + pixel_y = -1 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"wK" = ( +/obj/effect/decal/cleanable/robot_debris/down, +/obj/item/clothing/under/costume/skeleton, +/obj/item/clothing/mask/gas/prop, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"wW" = ( +/obj/structure/spider/stickyweb, +/obj/item/food/badrecipe/moldy, +/obj/item/grown/bananapeel, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"xd" = ( +/obj/effect/decal/cleanable/robot_debris/up, +/obj/effect/decal/cleanable/oil, +/obj/item/melee/skateboard, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"xf" = ( +/obj/structure/door_assembly/door_assembly_wood, +/obj/effect/decal/cleanable/plastic, +/obj/effect/decal/cleanable/oil/slippery, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"xC" = ( +/obj/item/stack/sheet/plastic/five, +/obj/item/stack/sheet/plastic/five, +/obj/structure/mannequin/plastic, +/obj/item/clothing/neck/tie/black, +/obj/effect/decal/cleanable/glass, +/obj/effect/decal/cleanable/plastic, +/obj/item/spear, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"xI" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/effect/decal/cleanable/plastic, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"xQ" = ( +/obj/item/storage/box/mousetraps, +/obj/structure/table/reinforced, +/obj/item/melee/flyswatter, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/toystore) +"xW" = ( +/obj/structure/broken_flooring/pile, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"yb" = ( +/obj/item/food/canned/tomatoes{ + pixel_x = 3; + pixel_y = 6 + }, +/obj/item/food/canned/tomatoes{ + pixel_x = 5; + pixel_y = 7 + }, +/obj/structure/closet/crate/cardboard/mothic, +/obj/item/food/uncooked_rice{ + pixel_x = 0; + pixel_y = -6 + }, +/obj/item/food/uncooked_rice{ + pixel_x = 2; + pixel_y = -6 + }, +/obj/item/food/uncooked_rice{ + pixel_x = 4; + pixel_y = -6 + }, +/obj/item/food/uncooked_rice{ + pixel_x = 6; + pixel_y = -6 + }, +/obj/item/food/uncooked_rice{ + pixel_x = 8; + pixel_y = -6 + }, +/obj/item/food/cracker, +/obj/item/food/cracker, +/obj/item/food/cracker, +/obj/item/food/cracker, +/obj/item/food/cracker, +/obj/item/food/cracker{ + pixel_x = -2; + pixel_y = -4 + }, +/obj/item/food/cracker{ + pixel_x = -7; + pixel_y = -2 + }, +/obj/item/food/cracker{ + pixel_y = 1 + }, +/obj/item/food/cracker{ + pixel_x = 2; + pixel_y = 1 + }, +/obj/item/food/cracker{ + pixel_y = -2 + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"yP" = ( +/obj/structure/lattice, +/obj/structure/grille, +/obj/effect/spawner/random/entertainment/plushie, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/toystore) +"yS" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"zs" = ( +/obj/machinery/computer/terminal{ + content = list("Property of Spinward-Upsilon Sanitation Department. Authorised employees only."); + desc = "A garbage truck's dusty old control console."; + name = "dashboard"; + upperinfo = "Controls locked." + }, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/toystore) +"AG" = ( +/obj/item/clothing/glasses/blindfold, +/obj/effect/decal/cleanable/plastic, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"AQ" = ( +/obj/item/food/spidereggs, +/obj/effect/mob_spawn/corpse/human{ + brute_damage = 200; + mob_type = /mob/living/carbon/human/species/moth; + outfit = /datum/outfit/abductorcorpse; + oxy_damage = 200 + }, +/obj/structure/spider/cocoon{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/mod/control/pre_equipped/standard{ + pixel_x = -6; + pixel_y = 4 + }, +/mob/living/basic/spider/giant/viper, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"BK" = ( +/obj/structure/closet/mini_fridge, +/obj/item/storage/cans/sixsoda, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"BO" = ( +/obj/structure/spider/stickyweb, +/obj/item/stock_parts/water_recycler, +/obj/effect/decal/cleanable/insectguts, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Dm" = ( +/obj/item/trash/cheesie, +/obj/item/shovel, +/obj/item/seeds/nettle, +/obj/item/popsicle_stick, +/obj/item/hatchet/wooden, +/obj/item/cigbutt, +/obj/item/secateurs, +/obj/item/pickaxe/rusted, +/obj/item/boxcutter, +/obj/structure/closet/crate/preopen, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Dv" = ( +/obj/machinery/door/poddoor/shutters/preopen, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"ER" = ( +/obj/structure/chair/comfy/shuttle, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/toystore) +"FM" = ( +/obj/structure/closet/crate/trashcart, +/obj/item/clothing/mask/surgical, +/obj/item/clothing/suit/costume/whitedress, +/obj/structure/broken_flooring/singular, +/obj/item/clothing/head/costume/nursehat, +/obj/item/clothing/neck/stethoscope, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Gt" = ( +/obj/structure/sign/flag/mothic, +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/garbagetruck/toystore) +"He" = ( +/obj/structure/spider/passage, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Hj" = ( +/obj/structure/lattice, +/obj/structure/grille/broken, +/turf/open/space/basic, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Hv" = ( +/obj/effect/decal/cleanable/glass/plastitanium/screws, +/obj/effect/spawner/random/bureaucracy/paper, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Hy" = ( +/obj/item/toy/xmas_cracker, +/obj/item/kirbyplants/synthetic/plant26, +/obj/item/storage/pill_bottle/probital, +/obj/item/clothing/head/costume/festive, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"HK" = ( +/obj/structure/closet/crate/large, +/obj/item/rwd/loaded, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Ix" = ( +/obj/structure/closet/cardboard, +/obj/item/bodypart/chest/robot, +/obj/item/toy/katana, +/obj/item/toy/plush/snakeplushie, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"IQ" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/broken_flooring/pile, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"IS" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Ja" = ( +/obj/structure/closet/crate/trashcart/filled, +/obj/effect/decal/cleanable/plastic, +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/card/cardboard, +/obj/item/broken_bottle, +/obj/item/cardpack/resin, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"JB" = ( +/obj/structure/spider/stickyweb, +/obj/structure/closet/crate/cardboard, +/obj/item/bikehorn/rubberducky, +/obj/item/clothing/glasses/monocle, +/obj/item/clothing/head/hats/tophat{ + desc = "It's a fancy looking hat. Inside is a label with a triangle drawn on it." + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"JI" = ( +/obj/item/dice/d10, +/obj/structure/filingcabinet/chestdrawer, +/obj/item/computer_disk/maintenance/modsuit_control, +/obj/item/computer_disk/maintenance/modsuit_control, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"KR" = ( +/obj/item/clothing/head/cone{ + pixel_x = 8; + pixel_y = 8 + }, +/obj/machinery/light/warm, +/obj/machinery/power/apc{ + cell_type = /obj/item/stock_parts/cell/lead; + locked = 0; + pixel_y = -25; + start_charge = 0 + }, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Lm" = ( +/obj/effect/decal/cleanable/garbage, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Lu" = ( +/obj/item/kirbyplants/synthetic/plant27, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Mp" = ( +/obj/structure/table/reinforced, +/obj/machinery/cell_charger, +/obj/item/stock_parts/cell/lead, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/toystore) +"MK" = ( +/obj/structure/filingcabinet/chestdrawer, +/obj/item/mail/junkmail, +/obj/item/healthanalyzer/simple/disease, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"OZ" = ( +/obj/item/trash/candy, +/obj/structure/broken_flooring/pile, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Pn" = ( +/obj/structure/closet/crate/mail, +/obj/item/trash/can, +/obj/item/mail/junkmail, +/obj/item/mail/junkmail, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Pv" = ( +/obj/structure/spider/stickyweb, +/obj/item/kirbyplants/synthetic/plant29, +/obj/item/crowbar/hammer, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"PJ" = ( +/obj/structure/spider/passage, +/obj/effect/spawner/random/mod/maint, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"PU" = ( +/obj/structure/table/reinforced, +/obj/item/storage/box/gloves{ + pixel_x = 10; + pixel_y = 8 + }, +/obj/item/storage/box/masks{ + pixel_x = -6; + pixel_y = 8 + }, +/obj/machinery/recharger{ + pixel_y = -10 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Qe" = ( +/obj/item/hand_labeler, +/obj/item/hand_labeler_refill, +/obj/structure/spider/stickyweb, +/mob/living/basic/spider/giant/hunter/scrawny, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"QD" = ( +/obj/effect/spawner/random/structure/crate_empty, +/obj/effect/spawner/random/entertainment/plushie_delux, +/obj/effect/spawner/random/entertainment/toy, +/obj/item/c_tube{ + pixel_y = -6 + }, +/obj/structure/spider/stickyweb, +/obj/item/toy/sword{ + pixel_y = 4 + }, +/obj/item/toy/sword{ + pixel_y = 8 + }, +/obj/item/kitchen/spoon/plastic, +/obj/effect/spawner/random/entertainment/toy, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Rb" = ( +/obj/item/stack/spacecash/c500, +/obj/item/coin/plastic, +/obj/structure/safe, +/obj/structure/spider/stickyweb, +/obj/item/tank/jetpack/oxygen, +/obj/item/switchblade, +/obj/item/survivalcapsule/bathroom, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Rl" = ( +/obj/item/paper/crumpled, +/obj/item/stock_parts/cell/hyper, +/obj/item/hand_labeler, +/obj/item/hand_labeler_refill, +/obj/item/hand_labeler_refill, +/obj/item/hand_labeler_refill, +/obj/item/hand_labeler_refill, +/obj/item/barcodescanner, +/obj/item/pen, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Sb" = ( +/obj/structure/reagent_dispensers/beerkeg, +/obj/structure/spider/stickyweb, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Sj" = ( +/obj/item/trash/pistachios, +/obj/structure/closet/crate/cardboard/mothic, +/obj/item/storage/fancy/pickles_jar, +/obj/item/food/spaghetti/raw, +/obj/item/food/spaghetti/raw, +/obj/item/food/sustenance_bar/wonka, +/obj/item/food/fueljacks_lunch, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Sk" = ( +/obj/effect/spawner/random/decoration/paint, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"ST" = ( +/obj/machinery/power/terminal, +/obj/structure/tank_dispenser/oxygen, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/toystore) +"TO" = ( +/obj/item/mop, +/obj/item/multitool{ + pixel_x = 8; + pixel_y = -6 + }, +/obj/structure/mop_bucket, +/obj/item/broken_bottle, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"UD" = ( +/obj/structure/closet/preopen, +/obj/item/stack/spacecash/c200, +/obj/item/storage/backpack/satchel, +/obj/item/toy/plush/shark, +/obj/item/instrument/banjo, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"VL" = ( +/obj/machinery/power/shuttle_engine/propulsion, +/turf/open/space/basic, +/area/space) +"Wl" = ( +/obj/structure/plasticflaps/opaque, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"WZ" = ( +/obj/item/paper/fluff/junkmail_generic, +/obj/item/pen/red, +/obj/structure/table_frame/wood, +/obj/item/mod/paint, +/obj/effect/spawner/random/decoration/paint, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Xg" = ( +/obj/structure/spider/stickyweb, +/obj/item/clothing/ears/earmuffs, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Xs" = ( +/obj/structure/spider/passage, +/mob/living/basic/spider/giant/hunter/scrawny, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"XI" = ( +/obj/structure/spider/solid, +/obj/item/food/badrecipe/moldy/bacteria, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"XL" = ( +/obj/item/scooter_frame, +/obj/effect/decal/cleanable/oil/streak, +/obj/effect/decal/cleanable/garbage, +/obj/effect/decal/cleanable/blood/old, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Ym" = ( +/obj/structure/table/reinforced, +/obj/item/analyzer{ + pixel_y = 6 + }, +/obj/item/geiger_counter{ + pixel_x = -8; + pixel_y = -2 + }, +/obj/item/flashlight{ + pixel_x = 4 + }, +/turf/open/floor/iron/smooth, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Yr" = ( +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Yz" = ( +/obj/structure/spider/stickyweb, +/obj/structure/tank_holder/extinguisher, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"YR" = ( +/obj/item/food/badrecipe/moldy/bacteria, +/obj/effect/spawner/random/bureaucracy/paper, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) +"Zi" = ( +/turf/open/space/basic, +/area/space) +"ZM" = ( +/obj/item/papercutter, +/obj/item/paper_bin, +/obj/structure/spider/stickyweb, +/obj/structure/spider/spikes, +/obj/structure/table_frame/wood, +/obj/effect/spawner/random/bureaucracy/paper, +/turf/open/floor/plating, +/area/ruin/space/has_grav/garbagetruck/toystore) + +(1,1,1) = {" +Zi +Zi +lg +lg +lg +nM +VL +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +"} +(2,1,1) = {" +Zi +nM +dn +dn +nM +nM +Yr +Yr +Yr +Yr +Yr +Yr +Yr +Yr +Yr +Yr +Yr +Yr +Yr +Yr +"} +(3,1,1) = {" +Hj +jD +PU +Mp +xQ +nM +Yr +sw +wy +FM +YR +Qe +cf +ZM +WZ +xC +Ix +dq +TO +rb +"} +(4,1,1) = {" +yP +dn +zs +ER +cq +nM +Yr +ng +pi +OZ +xI +IS +xf +ub +AG +lm +cg +sO +Dm +Yr +"} +(5,1,1) = {" +rI +dn +uX +uT +bU +nM +Yr +mf +xW +rc +Hv +ps +HK +ts +Pv +cT +xd +wK +QD +Yr +"} +(6,1,1) = {" +Hj +dn +jD +nM +wu +wo +Dv +IS +ld +ld +ld +Lu +XL +He +Xs +wW +JB +sA +wE +Yr +"} +(7,1,1) = {" +Hj +jD +bL +Ym +bU +wo +Dv +ld +ld +ld +IS +ld +Sb +Rb +IQ +Yz +PJ +pA +mM +Yr +"} +(8,1,1) = {" +yP +jD +eL +eL +bU +nM +Yr +rr +ld +Sk +ld +ld +Ja +hS +Lm +BO +XI +hH +qX +Yr +"} +(9,1,1) = {" +Hj +jD +eL +bU +KR +nM +Gt +UD +nP +pN +Pn +ld +kj +JI +sh +ld +Xg +AQ +tQ +Yr +"} +(10,1,1) = {" +rI +jD +eL +ST +aj +nM +Yr +BK +it +Sj +yb +yS +vz +MK +kz +ld +Hy +Rl +hD +rb +"} +(11,1,1) = {" +Zi +nM +ww +jD +nM +nM +Yr +Yr +Yr +Yr +Yr +Yr +Yr +Wl +Wl +Wl +Yr +Yr +Yr +Yr +"} +(12,1,1) = {" +Zi +Zi +lg +lg +ri +nM +VL +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +Zi +"} diff --git a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm new file mode 100644 index 00000000000000..0c4e9cd740b372 --- /dev/null +++ b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm @@ -0,0 +1,4338 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"ab" = ( +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/machinery/door/airlock/engineering, +/obj/structure/cable, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"af" = ( +/obj/effect/spawner/structure/window/reinforced/shuttle/indestructible, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"aj" = ( +/obj/effect/turf_decal/siding/blue, +/obj/structure/table, +/obj/item/paper_bin, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"at" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"au" = ( +/obj/lightning_thrower, +/obj/structure/cable, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"ay" = ( +/obj/structure/table, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/structure/sign/poster/contraband/lusty_xenomorph/directional/north, +/obj/item/flashlight/flare/candle{ + pixel_x = 7; + pixel_y = 4 + }, +/obj/item/flashlight/flare/candle{ + pixel_x = -7; + pixel_y = 4 + }, +/obj/item/flashlight/flare/candle{ + pixel_y = 8 + }, +/obj/item/toy/toy_xeno, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"aE" = ( +/obj/structure/bodycontainer/morgue{ + dir = 2 + }, +/turf/open/indestructible/white{ + icon_state = "showroomfloor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"aF" = ( +/obj/machinery/light/small/dim/directional/north, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"aV" = ( +/obj/effect/gibspawner/generic, +/obj/item/mop, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"aW" = ( +/obj/effect/turf_decal/tile/red, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"bh" = ( +/obj/structure/sign/directions/science/directional/west, +/obj/effect/turf_decal/siding/purple{ + dir = 8 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"bi" = ( +/obj/effect/turf_decal/siding/purple{ + dir = 8 + }, +/obj/effect/decal/cleanable/blood/splatter, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"bR" = ( +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/structure/table, +/obj/structure/microscope, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"ch" = ( +/turf/open/indestructible/white{ + icon_state = "showroomfloor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"cp" = ( +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"cQ" = ( +/obj/structure/holosign/barrier, +/turf/open/floor/plating/airless, +/area/ruin/space) +"dv" = ( +/obj/structure/window/spawner/directional/west, +/obj/structure/window/spawner/directional/north, +/obj/effect/gibspawner/generic, +/mob/living/basic/living_limb_flesh, +/mob/living/basic/living_limb_flesh, +/obj/structure/window/spawner/directional/east, +/turf/open/floor/circuit{ + baseturfs = /turf/open/indestructible/plating + }, +/area/ruin/space/has_grav/powered/biooutpost) +"dD" = ( +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/yellow/filled/warning{ + dir = 1 + }, +/obj/machinery/computer/old, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"dQ" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/obj/structure/rack, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"dR" = ( +/turf/open/floor/iron/white, +/area/ruin/space/has_grav/powered/biooutpost) +"dW" = ( +/obj/effect/decal/cleanable/blood/tracks{ + dir = 8 + }, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"ea" = ( +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/mob_spawn/corpse/human/scientist, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"eo" = ( +/obj/structure/marker_beacon/burgundy, +/obj/effect/turf_decal/stripes{ + dir = 10 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/turf/open/floor/plating/airless, +/area/ruin/space) +"eq" = ( +/mob/living/basic/living_floor/white, +/obj/effect/gibspawner/generic, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"ex" = ( +/obj/machinery/door/airlock/grunge{ + id_tag = "md_morgue" + }, +/obj/effect/mapping_helpers/airlock/locked, +/obj/effect/mapping_helpers/airlock_note_placer{ + note_info = "Reminder for medbay staff to not stick failed and active experiments in the morgue." + }, +/turf/open/indestructible/white{ + icon_state = "showroomfloor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"eA" = ( +/obj/machinery/door/airlock/security/glass, +/obj/effect/turf_decal/siding/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"eD" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/obj/machinery/button/door/directional/north{ + normaldoorcontrol = 1; + specialfunctions = 4; + id = "md_morgue" + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"eF" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/machinery/light/cold/dim/directional/west, +/obj/machinery/computer/old{ + dir = 4 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"eP" = ( +/obj/structure/meateor_fluff/eyeball, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"eT" = ( +/obj/item/fakeartefact, +/obj/structure/table/wood/fancy/orange, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"fc" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 10 + }, +/obj/structure/table, +/obj/effect/spawner/random/medical/supplies, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"fm" = ( +/obj/effect/turf_decal/tile/red/half/contrasted, +/obj/machinery/computer/old{ + dir = 8 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"fo" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/structure/chair/office/light{ + dir = 1 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"fB" = ( +/obj/machinery/computer/operating, +/turf/open/indestructible/white{ + icon_state = "showroomfloor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"fH" = ( +/turf/closed/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"fW" = ( +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"go" = ( +/obj/effect/turf_decal/siding/purple/corner, +/obj/effect/turf_decal/siding/purple/corner{ + dir = 4 + }, +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 4 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"gK" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/end, +/obj/structure/rack, +/obj/item/climbing_hook, +/obj/item/extinguisher, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"gN" = ( +/obj/structure/table, +/obj/item/storage/box/petridish, +/obj/item/healthanalyzer, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"gO" = ( +/obj/structure/toiletbong, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"gP" = ( +/obj/structure/broken_flooring/pile/always_floorplane{ + dir = 8 + }, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"gQ" = ( +/obj/item/ammo_casing/spent, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/decal/cleanable/blood/tracks{ + dir = 8 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"gX" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red/anticorner/contrasted{ + dir = 4 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"hd" = ( +/turf/closed/indestructible/riveted/plastinum/nodiagonal, +/area/ruin/space) +"hf" = ( +/obj/structure/table/reinforced/rglass, +/obj/item/storage/medkit/toxin, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"hk" = ( +/obj/structure/aquarium/prefilled, +/turf/open/floor/iron/dark/textured_large, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"hN" = ( +/obj/structure/puzzle_blockade{ + id = "md_toeng" + }, +/obj/effect/turf_decal/stripes/full, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"hQ" = ( +/obj/structure/broken_flooring/plating/directional/west, +/obj/item/crowbar, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"hR" = ( +/obj/structure/sign/warning, +/turf/closed/indestructible/reinforced, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"hW" = ( +/obj/effect/turf_decal/siding/purple, +/obj/effect/decal/cleanable/blood/splatter, +/obj/item/scalpel{ + pixel_y = 16; + pixel_x = 4 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"hY" = ( +/obj/structure/barricade/wooden, +/obj/machinery/door/airlock/science/glass{ + name = "Janitorial Closet" + }, +/obj/effect/mapping_helpers/airlock_note_placer{ + note_info = "DO NOT ENTER!!!" + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"id" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"ih" = ( +/obj/effect/decal/cleanable/blood/old, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"ij" = ( +/turf/closed/indestructible/reinforced, +/area/ruin/space/has_grav/powered/biooutpost) +"il" = ( +/obj/effect/decal/cleanable/glass, +/turf/open/floor/iron/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"io" = ( +/mob/living/basic/living_floor, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"iA" = ( +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"iB" = ( +/obj/structure/broken_flooring/plating/directional/east, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"iI" = ( +/obj/structure/chair/sofa/bench/left, +/obj/effect/turf_decal/siding/purple{ + dir = 1 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"iO" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 4 + }, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"iQ" = ( +/obj/machinery/computer/old, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/structure/sign/poster/official/random/directional/north, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"iX" = ( +/obj/structure/broken_flooring/pile/always_floorplane{ + dir = 8 + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"ja" = ( +/obj/item/food/muffin/moffin{ + preserved_food = 1 + }, +/obj/structure/flora/bush/fullgrass/style_random, +/obj/structure/window/reinforced/spawner/directional/south, +/turf/open/floor/grass, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"jf" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 8 + }, +/obj/structure/table, +/obj/structure/window/spawner/directional/north, +/obj/effect/spawner/random/medical/supplies, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"jj" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 8 + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"jo" = ( +/obj/machinery/door/airlock/external, +/obj/effect/mapping_helpers/airlock_note_placer{ + note_name = "notice"; + note_info = "This area is condemned by Nanotrasen. Employees seen near or in this area will be fined or punished otherwise." + }, +/turf/open/floor/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"jr" = ( +/obj/effect/spawner/random/trash/garbage, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"jt" = ( +/obj/item/crowbar, +/obj/structure/broken_flooring/plating/directional/north, +/obj/item/reagent_containers/cup/bucket, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"jA" = ( +/obj/effect/decal/cleanable/glass, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"jE" = ( +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"jO" = ( +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"jU" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/rack, +/obj/item/ammo_box/magazine/wt550m9, +/obj/item/ammo_box/magazine/wt550m9{ + pixel_x = 6; + pixel_y = 6 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"jV" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 6 + }, +/obj/item/surgery_tray/full/deployed, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"kh" = ( +/obj/machinery/computer/terminal/meatderelict{ + dir = 1 + }, +/obj/machinery/light/small/directional/south, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"ki" = ( +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/yellow/filled/warning{ + dir = 1 + }, +/obj/structure/cable, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"kl" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"kn" = ( +/obj/effect/turf_decal/siding/purple, +/obj/machinery/light/cold/directional/south, +/obj/structure/table/reinforced/rglass, +/obj/item/reagent_containers/cup/glass/coffee_cup{ + pixel_y = 3 + }, +/obj/item/reagent_containers/cup/glass/coffee_cup{ + pixel_y = 6 + }, +/obj/item/reagent_containers/cup/glass/coffee_cup, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"ku" = ( +/obj/structure/rack, +/obj/item/reagent_containers/cup/bottle/flash_powder, +/obj/item/reagent_containers/cup/bottle/lithium, +/obj/item/reagent_containers/cup/bottle/nitrogen, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"kB" = ( +/obj/effect/spawner/random/vending/snackvend, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"kX" = ( +/obj/effect/turf_decal/stripes, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plating/airless, +/area/ruin/space) +"la" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 8 + }, +/obj/structure/table, +/obj/machinery/light/cold/directional/west, +/obj/effect/spawner/random/medical/supplies, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"lf" = ( +/obj/structure/table/reinforced/rglass, +/obj/item/reagent_containers/syringe, +/obj/item/reagent_containers/syringe{ + pixel_y = -4 + }, +/obj/item/reagent_containers/syringe{ + pixel_y = 4 + }, +/obj/item/reagent_containers/syringe{ + pixel_y = 8 + }, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"lh" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, +/obj/machinery/computer/old{ + dir = 4 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"lm" = ( +/obj/effect/decal/cleanable/blood/tracks{ + dir = 10 + }, +/obj/item/ammo_casing/c45/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"lJ" = ( +/obj/machinery/door/airlock/science/glass, +/obj/effect/mapping_helpers/airlock/welded, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"lT" = ( +/obj/structure/chair/office{ + dir = 8 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"mc" = ( +/obj/machinery/door/airlock/engineering, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"mx" = ( +/obj/structure/broken_flooring/side/always_floorplane, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"mA" = ( +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/blood/innards, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"mM" = ( +/obj/effect/decal/cleanable/blood/splatter, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"mO" = ( +/obj/effect/turf_decal/siding/blue, +/obj/structure/table, +/obj/item/storage/medkit/brute, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"mU" = ( +/obj/effect/turf_decal/stripes, +/obj/effect/turf_decal/siding/purple, +/obj/machinery/light/cold/dim/directional/south, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"ne" = ( +/obj/structure/table/wood/fancy/purple, +/obj/item/reagent_containers/hypospray/medipen/methamphetamine{ + pixel_x = -3 + }, +/obj/item/book/manual/wiki/research_and_development{ + pixel_x = 5; + pixel_y = 5 + }, +/turf/open/floor/iron/dark/textured_large, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"ni" = ( +/mob/living/basic/living_floor/white, +/obj/machinery/light/small/dim/directional/east, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"nr" = ( +/turf/open/misc/asteroid/airless, +/area/ruin/space) +"nx" = ( +/obj/structure/table, +/obj/item/pen/fourcolor, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"ny" = ( +/obj/structure/closet/secure_closet/chemical, +/obj/machinery/light/small/directional/east, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"nM" = ( +/obj/structure/broken_flooring/side/directional/north, +/obj/machinery/door/puzzle{ + puzzle_id = "md_42069"; + desc = "This door only opens from the other side. It looks virtually indestructible." + }, +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 1 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"nP" = ( +/obj/effect/turf_decal/tile/red/half/contrasted{ + dir = 8 + }, +/obj/structure/table/reinforced, +/obj/item/grenade/flashbang, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"nR" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/mapping_helpers/broken_machine, +/obj/machinery/vending/snack/orange, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"nY" = ( +/obj/effect/decal/cleanable/blood/tracks, +/obj/effect/turf_decal/stripes, +/obj/effect/turf_decal/siding/purple, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"oh" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/item/storage/fancy/cigarettes/cigpack_mindbreaker, +/obj/machinery/light/directional/east, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"oj" = ( +/obj/machinery/door/airlock/security, +/obj/effect/turf_decal/siding/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/decal/cleanable/blood/tracks{ + dir = 8 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"op" = ( +/turf/closed/mineral/random/stationside/asteroid{ + baseturfs = /turf/open/indestructible/white + }, +/area/ruin/space/has_grav/powered/biooutpost) +"os" = ( +/obj/structure/grille/indestructible, +/obj/structure/cable, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"oI" = ( +/mob/living/basic/living_floor, +/obj/structure/sign/poster/random/directional/west, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"oO" = ( +/obj/effect/turf_decal/siding/purple{ + dir = 1 + }, +/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/a357/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"oQ" = ( +/obj/machinery/puzzle_button/meatderelict{ + pixel_y = 32; + queue_size = 4 + }, +/turf/open/floor/iron/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"oX" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"pe" = ( +/obj/structure/chair/office, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"ph" = ( +/obj/machinery/door/airlock/external, +/obj/effect/mapping_helpers/airlock/welded, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"pj" = ( +/obj/machinery/door/airlock/research/glass{ + id_tag = "md_scis" + }, +/obj/effect/mapping_helpers/airlock/locked, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"pk" = ( +/obj/effect/decal/cleanable/blood/old, +/turf/open/indestructible/white{ + icon_state = "showroomfloor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"pl" = ( +/obj/effect/turf_decal/tile/yellow/half/contrasted, +/obj/effect/turf_decal/trimline/yellow/filled/warning, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"po" = ( +/obj/structure/broken_flooring/corner/always_floorplane, +/obj/structure/table, +/obj/item/flashlight/lamp, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"pp" = ( +/obj/item/pressure_plate/puzzle{ + puzzle_id = "md_42069" + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"pC" = ( +/obj/structure/table, +/obj/item/flashlight/lamp, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"pK" = ( +/obj/machinery/iv_drip, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/siding/purple{ + dir = 6 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"pQ" = ( +/obj/machinery/computer/old{ + dir = 1 + }, +/obj/machinery/light/cold/dim/directional/south, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"pY" = ( +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 8 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"qg" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red/anticorner/contrasted, +/obj/structure/chair{ + dir = 1 + }, +/obj/item/restraints/handcuffs, +/obj/machinery/light/warm/directional/south, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"qh" = ( +/obj/structure/table, +/obj/effect/spawner/random/bureaucracy/folder, +/obj/effect/spawner/random/bureaucracy/stamp, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"qi" = ( +/obj/structure/bodycontainer/morgue{ + dir = 2 + }, +/obj/effect/mob_spawn/corpse/human/damaged, +/obj/machinery/light/cold/dim/directional/north, +/turf/open/indestructible/white{ + icon_state = "showroomfloor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"qs" = ( +/obj/effect/decal/cleanable/blood/tracks{ + dir = 9 + }, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"qw" = ( +/obj/effect/turf_decal/tile/red, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"qx" = ( +/mob/living/basic/living_floor/white, +/obj/effect/spawner/random/structure/chair_flipped, +/obj/effect/gibspawner/generic, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"qV" = ( +/obj/machinery/power/rtg/old_station, +/obj/structure/cable, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"qY" = ( +/obj/effect/turf_decal/tile/yellow/fourcorners, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"qZ" = ( +/obj/structure/table, +/obj/effect/spawner/random/bureaucracy/paper, +/obj/effect/spawner/random/bureaucracy/pen, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"ra" = ( +/obj/structure/closet/emcloset/anchored, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"re" = ( +/turf/closed/mineral/random/low_chance, +/area/ruin/space) +"rh" = ( +/obj/effect/turf_decal/siding/purple{ + dir = 1 + }, +/obj/item/ammo_casing/a357/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"rl" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 6 + }, +/obj/structure/closet/secure_closet/chemical, +/obj/structure/window/reinforced/spawner/directional/north, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"rm" = ( +/obj/effect/spawner/random/engineering/flashlight, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"rw" = ( +/obj/effect/turf_decal/siding/blue/corner, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"rK" = ( +/obj/structure/showcase/horrific_experiment, +/obj/machinery/light/small/dim/directional/east, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"sd" = ( +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"se" = ( +/obj/structure/rack, +/obj/item/reagent_containers/cup/bottle/mutagen, +/obj/item/reagent_containers/cup/bottle/mutagen, +/obj/item/reagent_containers/cup/bottle/mutagen, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"sk" = ( +/obj/structure/chair/sofa/bench/right, +/obj/effect/mob_spawn/corpse/human/scientist{ + brute_damage = 100; + corpse_description = "They were shot in the head, and heart." + }, +/obj/effect/turf_decal/siding/purple{ + dir = 1 + }, +/obj/effect/decal/cleanable/blood/splatter, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"sl" = ( +/obj/effect/spawner/structure/window/reinforced/shuttle/indestructible, +/obj/effect/decal/cleanable/blood/splatter/over_window, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"sp" = ( +/obj/machinery/button/door/directional/south{ + normaldoorcontrol = 1; + specialfunctions = 4; + id = "md_scis"; + name = "safety lock control" + }, +/obj/effect/decal/cleanable/blood/tracks{ + dir = 6 + }, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"sJ" = ( +/obj/structure/broken_flooring/corner/always_floorplane{ + dir = 4 + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"sL" = ( +/obj/structure/marker_beacon/burgundy, +/obj/effect/turf_decal/stripes{ + dir = 5 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/turf/open/floor/plating/airless, +/area/ruin/space) +"sM" = ( +/obj/item/ammo_casing/spent, +/obj/item/ammo_casing/spent, +/obj/item/ammo_casing/c45/spent, +/obj/item/ammo_casing/c45/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"sR" = ( +/obj/effect/turf_decal/trimline/yellow/filled/end, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"tg" = ( +/obj/structure/table/wood/fancy/orange, +/obj/effect/spawner/random/exotic/technology, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"tq" = ( +/mob/living/basic/living_floor, +/obj/effect/mob_spawn/corpse/human/engineer, +/obj/machinery/light/small/dim/directional/west, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"tt" = ( +/obj/effect/spawner/structure/window/hollow/middle{ + dir = 4 + }, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"tv" = ( +/obj/effect/decal/cleanable/blood/tracks, +/mob/living/simple_animal/hostile/zombie, +/turf/open/indestructible/white{ + icon_state = "showroomfloor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"tF" = ( +/obj/structure/broken_flooring/plating/directional/east, +/obj/effect/spawner/random/structure/chair_flipped, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"tN" = ( +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 4 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"tS" = ( +/obj/effect/turf_decal/stripes{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plating/airless, +/area/ruin/space) +"uc" = ( +/obj/effect/turf_decal/siding/purple/corner, +/obj/item/ammo_casing/shotgun/buckshot/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"uf" = ( +/obj/machinery/light/small/dim/directional/west, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"uh" = ( +/obj/effect/turf_decal/tile/red/half/contrasted{ + dir = 1 + }, +/obj/structure/chair/office{ + dir = 8 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"ui" = ( +/obj/structure/closet/wardrobe/science_white, +/obj/effect/turf_decal/siding/purple{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"uq" = ( +/obj/machinery/door/airlock/external, +/obj/effect/decal/cleanable/blood/tracks, +/turf/open/floor/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"us" = ( +/obj/machinery/suit_storage_unit/spaceruin, +/obj/machinery/light/small/dim/directional/south, +/turf/open/floor/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"uC" = ( +/obj/effect/decal/cleanable/blood/tracks, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"uH" = ( +/obj/effect/decal/cleanable/blood/tracks, +/obj/structure/holosign/barrier, +/turf/open/floor/plating/airless, +/area/ruin/space) +"uS" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 1 + }, +/obj/structure/table, +/obj/effect/spawner/random/food_or_drink/snack, +/obj/effect/spawner/random/food_or_drink/refreshing_beverage{ + pixel_x = 16 + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"uU" = ( +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"uZ" = ( +/obj/machinery/door/airlock/security, +/obj/effect/turf_decal/tile/purple/half/contrasted{ + dir = 8 + }, +/turf/open/indestructible{ + icon_state = "whitehall"; + dir = 8 + }, +/area/ruin/space/has_grav/powered/biooutpost) +"vd" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 9 + }, +/obj/machinery/vending/medical{ + shut_up = 1 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"vl" = ( +/obj/structure/table, +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ + dir = 4 + }, +/obj/item/crowbar, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"vt" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"vF" = ( +/obj/structure/fluff/empty_cryostasis_sleeper{ + name = "broken genetics device"; + desc = "Depowered and broken, this machine no longer serves its purpose." + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"vY" = ( +/obj/machinery/door/puzzle/keycard{ + puzzle_id = "md_director"; + name = "Directors Office" + }, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"vZ" = ( +/obj/structure/window/spawner/directional/west, +/obj/structure/window/spawner/directional/east, +/obj/structure/window/spawner/directional/south, +/obj/structure/window/spawner/directional/north, +/obj/effect/gibspawner/generic, +/turf/open/floor/circuit{ + baseturfs = /turf/open/indestructible/plating + }, +/area/ruin/space/has_grav/powered/biooutpost) +"wf" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 6 + }, +/obj/structure/bed/medical/anchored{ + dir = 1 + }, +/obj/structure/sign/poster/official/random/directional/south, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"wj" = ( +/obj/effect/spawner/structure/window/reinforced/indestructible, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"wn" = ( +/obj/structure/bodycontainer/morgue{ + dir = 2 + }, +/obj/item/knife/combat/survival, +/turf/open/indestructible/white{ + icon_state = "showroomfloor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"wy" = ( +/obj/effect/decal/cleanable/glass, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"wH" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/end{ + dir = 1 + }, +/obj/structure/rack, +/obj/item/gun/ballistic/automatic/wt550{ + pin = /obj/item/firing_pin/explorer + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"wJ" = ( +/obj/structure/grille/broken, +/obj/effect/decal/cleanable/glass, +/obj/structure/window/spawner/directional/east, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"wM" = ( +/obj/structure/sign/warning/biohazard/directional/east, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"wR" = ( +/obj/effect/turf_decal/tile/red/anticorner/contrasted{ + dir = 1 + }, +/obj/machinery/computer/old{ + dir = 4 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"wU" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 1 + }, +/obj/structure/cable, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"wX" = ( +/obj/item/kirbyplants/random, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/light/broken/directional/north, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"xk" = ( +/obj/structure/window/spawner/directional/north, +/obj/structure/window/spawner/directional/east, +/obj/structure/window/spawner/directional/south, +/obj/effect/gibspawner/generic, +/mob/living/basic/living_limb_flesh, +/turf/open/floor/circuit{ + baseturfs = /turf/open/indestructible/plating + }, +/area/ruin/space/has_grav/powered/biooutpost) +"xm" = ( +/obj/item/kirbyplants/random/dead, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"xr" = ( +/obj/machinery/door/puzzle/meatderelict, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"xA" = ( +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/effect/decal/cleanable/dirt, +/obj/structure/cable, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"xE" = ( +/obj/lightning_thrower, +/obj/machinery/light/small/dim/directional/north, +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/yellow/filled/warning{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"xU" = ( +/mob/living/basic/living_floor/white, +/obj/item/flashlight, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"yf" = ( +/obj/machinery/light/small/directional/south, +/obj/structure/broken_flooring/corner/always_floorplane{ + dir = 8 + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"yl" = ( +/obj/effect/decal/cleanable/blood/tracks{ + dir = 8 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"yp" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/cable, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"yr" = ( +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"yu" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/light/small/dim/directional/north, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"yw" = ( +/obj/effect/turf_decal/tile/red/half/contrasted{ + dir = 8 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"yU" = ( +/obj/structure/fluff/empty_cryostasis_sleeper{ + name = "broken genetics device"; + desc = "Depowered and broken, this machine no longer serves its purpose." + }, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/siding/purple{ + dir = 5 + }, +/obj/structure/sign/warning/chem_diamond/directional/west, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"za" = ( +/obj/structure/table, +/obj/item/clothing/gloves/color/yellow, +/obj/structure/sign/poster/contraband/missing_gloves/directional/west, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"zg" = ( +/obj/effect/turf_decal/tile/red/anticorner/contrasted{ + dir = 8 + }, +/obj/structure/table/reinforced, +/obj/item/storage/box/handcuffs, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"zs" = ( +/obj/structure/chair/office, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"zF" = ( +/obj/effect/mob_spawn/corpse/human/scientist{ + brute_damage = 100; + corpse_description = "They were shot in the head, and heart." + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"zL" = ( +/obj/structure/filingcabinet/chestdrawer, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"zP" = ( +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/structure/cable, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"zS" = ( +/obj/structure/table/wood/fancy/purple, +/obj/effect/spawner/random/entertainment/money_large, +/turf/open/floor/iron/dark/textured_large, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"An" = ( +/obj/item/storage/toolbox/mechanical, +/obj/structure/table, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"AD" = ( +/obj/machinery/computer/old{ + dir = 8 + }, +/turf/open/floor/circuit, +/area/ruin/space/has_grav/powered/biooutpost) +"AG" = ( +/obj/structure/table/wood/fancy/purple, +/obj/effect/spawner/random/clothing/kittyears_or_rabbitears, +/obj/item/seeds/cannabis/white, +/turf/open/floor/iron/dark/textured_large, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"AP" = ( +/obj/structure/fluff/empty_cryostasis_sleeper{ + name = "broken genetics device"; + desc = "Depowered and broken, this machine no longer serves its purpose." + }, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/siding/purple{ + dir = 6 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"AT" = ( +/obj/structure/sign/warning, +/turf/closed/indestructible/riveted/plastinum/nodiagonal, +/area/ruin/space/has_grav/powered/biooutpost) +"AV" = ( +/obj/effect/turf_decal/stripes/full, +/turf/open/floor/plating/airless, +/area/ruin/space) +"AX" = ( +/obj/machinery/light/directional/north, +/mob/living/basic/mothroach{ + name = "Moff" + }, +/obj/machinery/door/window/right/directional/south{ + req_access = list("science") + }, +/turf/open/floor/grass, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"AY" = ( +/obj/effect/turf_decal/tile/red/diagonal_centre, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Be" = ( +/obj/effect/turf_decal/siding/purple, +/obj/structure/table/reinforced/rglass, +/obj/item/storage/fancy/coffee_cart_rack, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Bl" = ( +/obj/effect/turf_decal/siding/wood, +/obj/effect/decal/cleanable/glass, +/obj/structure/chair/office{ + dir = 1 + }, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"Bp" = ( +/obj/structure/broken_flooring/pile/always_floorplane, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"Br" = ( +/obj/structure/closet/l3closet/scientist, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"Bt" = ( +/obj/machinery/door/puzzle/meatderelict, +/obj/effect/turf_decal/stripes/corner, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Bu" = ( +/obj/item/ammo_casing/spent, +/obj/item/ammo_casing/spent, +/obj/effect/decal/cleanable/blood/splatter, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Bx" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 5 + }, +/obj/structure/table, +/obj/item/reagent_containers/cup/beaker/meta, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"By" = ( +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ + dir = 8 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"BA" = ( +/obj/structure/marker_beacon/burgundy, +/obj/effect/turf_decal/stripes{ + dir = 9 + }, +/obj/effect/turf_decal/stripes/corner, +/turf/open/floor/plating/airless, +/area/ruin/space) +"Ca" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 8 + }, +/obj/structure/sign/poster/random/directional/south, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"Cf" = ( +/obj/effect/turf_decal/siding/purple{ + dir = 5 + }, +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 4 + }, +/obj/effect/decal/cleanable/blood/splatter, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Cl" = ( +/obj/machinery/door/airlock/science, +/obj/effect/turf_decal/tile/purple/fourcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"CD" = ( +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"CF" = ( +/obj/machinery/computer/old{ + dir = 4 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"CI" = ( +/mob/living/basic/living_limb_flesh, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"CN" = ( +/obj/structure/table, +/obj/item/toy/figure/secofficer, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"CS" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/structure/table, +/obj/item/assembly/igniter, +/obj/item/assembly/igniter, +/obj/item/assembly/igniter, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"CW" = ( +/obj/effect/turf_decal/tile/purple/half/contrasted, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Df" = ( +/obj/machinery/vending/coffee, +/obj/effect/turf_decal/siding/purple{ + dir = 9 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Dg" = ( +/obj/structure/mecha_wreckage/ripley, +/obj/structure/window/spawner/directional/east, +/turf/open/indestructible{ + icon_state = "recharge_floor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"Dh" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, +/obj/machinery/chem_dispenser, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"Dk" = ( +/obj/structure/table, +/obj/item/flashlight/lamp, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Du" = ( +/obj/structure/table, +/obj/effect/spawner/random/engineering/tool, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"DB" = ( +/mob/living/basic/living_floor, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"DC" = ( +/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/a357/spent, +/obj/item/ammo_casing/a357/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"DJ" = ( +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"DR" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 1 + }, +/obj/structure/table, +/obj/item/paper/crumpled/fluff/meatderelict/fridge, +/obj/item/pen{ + pixel_x = 12 + }, +/obj/structure/sign/poster/random/directional/south, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"DU" = ( +/obj/structure/chair/sofa/bench, +/obj/effect/turf_decal/siding/purple{ + dir = 1 + }, +/obj/machinery/light/cold/directional/north, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Ec" = ( +/mob/living/basic/living_floor/white, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"Ei" = ( +/obj/machinery/door/airlock/science, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Ew" = ( +/obj/effect/decal/cleanable/blood/tracks{ + dir = 5 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Ex" = ( +/obj/structure/table/optable, +/turf/open/indestructible/white{ + icon_state = "showroomfloor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"EC" = ( +/turf/closed/indestructible/reinforced, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"EE" = ( +/obj/structure/broken_flooring/pile/always_floorplane, +/obj/structure/table, +/obj/machinery/microwave, +/obj/machinery/light/broken/directional/west, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"EN" = ( +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"EQ" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 1 + }, +/obj/structure/filingcabinet/chestdrawer, +/obj/item/keycard/meatderelict/engpost, +/obj/item/food/candy, +/obj/item/food/candy, +/obj/item/food/candy_corn, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"ES" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 8 + }, +/obj/structure/table, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"EY" = ( +/obj/structure/sign/poster/random/directional/east, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"Fc" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/structure/table, +/obj/item/storage/box/beakers, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"Fv" = ( +/obj/item/food/muffin/moffin{ + preserved_food = 1 + }, +/obj/structure/window/reinforced/spawner/directional/south, +/turf/open/floor/grass, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"FE" = ( +/turf/open/floor/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"FI" = ( +/obj/item/instrument/piano_synth/headphones, +/obj/structure/table, +/obj/machinery/puzzle_button/directional/north{ + used = 1 + }, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"Gb" = ( +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Gd" = ( +/obj/machinery/light/cold/dim/directional/east, +/obj/effect/turf_decal/tile/purple/half/contrasted{ + dir = 4 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Gj" = ( +/obj/effect/turf_decal/stripes{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/turf/open/floor/plating/airless, +/area/ruin/space) +"Gn" = ( +/obj/structure/table, +/obj/item/plate, +/obj/item/food/burger/cheese, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/machinery/light/small/broken/directional/south, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"GA" = ( +/obj/effect/turf_decal/siding/purple{ + dir = 8 + }, +/obj/item/ammo_casing/c45/spent, +/obj/item/ammo_casing/c45/spent, +/obj/item/ammo_casing/c45/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"GC" = ( +/obj/effect/turf_decal/siding/purple{ + dir = 6 + }, +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 4 + }, +/obj/structure/table/reinforced/rglass, +/obj/machinery/coffeemaker, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"GE" = ( +/obj/item/kirbyplants/random, +/turf/open/floor/iron/dark/textured_large, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"GF" = ( +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/structure/grille/indestructible, +/obj/structure/cable, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"GO" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 4 + }, +/obj/machinery/iv_drip, +/obj/machinery/light/cold/directional/east, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Hb" = ( +/obj/item/kirbyplants/organic/plant12, +/obj/effect/turf_decal/siding/purple{ + dir = 5 + }, +/obj/structure/sign/directions/engineering/directional/east, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Hh" = ( +/obj/effect/mob_spawn/corpse/human/scientist, +/obj/item/keycard/meatderelict/director, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Hm" = ( +/obj/structure/grille/indestructible, +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted, +/obj/effect/turf_decal/trimline/yellow/filled/warning, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Hx" = ( +/obj/item/ammo_casing/spent, +/obj/item/ammo_casing/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"HA" = ( +/obj/effect/turf_decal/stripes, +/obj/effect/turf_decal/siding/purple, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"HC" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"HF" = ( +/mob/living/basic/living_floor/white, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"HV" = ( +/obj/structure/broken_flooring/side/always_floorplane, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"Ip" = ( +/obj/structure/table, +/obj/effect/spawner/random/engineering/flashlight, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"IK" = ( +/obj/structure/puzzle_blockade{ + id = "md_armory" + }, +/obj/effect/turf_decal/stripes/full, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Jb" = ( +/obj/item/ammo_casing/c45/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Jf" = ( +/obj/effect/turf_decal/tile/purple/anticorner/contrasted, +/obj/structure/sign/departments/security/directional/east, +/obj/effect/decal/cleanable/blood/old, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Jh" = ( +/turf/closed/indestructible/riveted/plastinum/nodiagonal, +/area/ruin/space/has_grav/powered/biooutpost) +"Jo" = ( +/obj/structure/table/wood/fancy/purple, +/obj/item/mod/module/recycler/donk, +/obj/item/mod/module/recycler, +/turf/open/floor/iron/dark/textured_large, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Jt" = ( +/obj/machinery/puzzle_button/directional/north{ + id = "md_tosci"; + name = "shield power panel" + }, +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/yellow/filled/warning{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/remains/human, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Ju" = ( +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/effect/decal/cleanable/blood/old, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Jx" = ( +/obj/machinery/door/airlock/vault, +/obj/item/grown/bananapeel, +/turf/open/floor/iron/dark/textured_large, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"JF" = ( +/obj/structure/window/reinforced/spawner/directional/east, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/flora/bush/fullgrass/style_random, +/obj/item/food/grown/carrot{ + preserved_food = 1 + }, +/turf/open/floor/grass, +/area/ruin/space/has_grav/powered/biooutpost) +"Ka" = ( +/mob/living/basic/living_floor/white, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/blood/tracks, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"Kc" = ( +/obj/structure/window/reinforced/spawner/directional/east, +/mob/living/basic/rabbit, +/obj/structure/flora/bush/fullgrass/style_random, +/turf/open/floor/grass, +/area/ruin/space/has_grav/powered/biooutpost) +"Ki" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 5 + }, +/obj/structure/bed/medical/anchored{ + dir = 1 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Kl" = ( +/obj/structure/chair/sofa/bench, +/obj/effect/turf_decal/siding/purple{ + dir = 1 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Kx" = ( +/obj/effect/turf_decal/siding/purple/corner{ + dir = 4 + }, +/obj/effect/decal/cleanable/blood/splatter, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"KC" = ( +/obj/machinery/puzzle_button/directional/north{ + id = "md_toeng"; + queue_size = 4 + }, +/obj/structure/chair/office{ + dir = 8 + }, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/machinery/light/small/broken/directional/east, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"KH" = ( +/obj/structure/broken_flooring/pile/always_floorplane{ + dir = 1 + }, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"KP" = ( +/obj/effect/decal/cleanable/blood/tracks, +/obj/effect/turf_decal/tile/purple, +/turf/open/floor/iron/white, +/area/ruin/space/has_grav/powered/biooutpost) +"KU" = ( +/obj/machinery/door/airlock/engineering, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Lc" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/item/storage/fancy/rollingpapers, +/obj/item/paper/pamphlet/cybernetics, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"Lj" = ( +/obj/effect/mob_spawn/corpse/human/scientist, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"Ll" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/obj/structure/sign/poster/official/random/directional/north, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"LR" = ( +/obj/effect/turf_decal/stripes{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/plating/airless, +/area/ruin/space) +"Mb" = ( +/obj/effect/turf_decal/siding/red, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/structure/sign/poster/random/directional/west, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"Mo" = ( +/obj/effect/spawner/structure/window/hollow/reinforced/plasma/end{ + dir = 4 + }, +/obj/structure/sign/warning/electric_shock/directional/west, +/obj/structure/cable, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"Mp" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/blood/tracks, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"MF" = ( +/obj/structure/grille/indestructible, +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/yellow/filled/warning, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"MH" = ( +/obj/effect/turf_decal/siding/wood, +/obj/effect/decal/cleanable/blood/splatter, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"ML" = ( +/turf/open/floor/plating/airless, +/area/ruin/space) +"MO" = ( +/obj/effect/turf_decal/tile/purple, +/turf/open/floor/iron/white, +/area/ruin/space/has_grav/powered/biooutpost) +"MS" = ( +/obj/structure/table, +/obj/item/paper/crumpled/fluff/meatderelict, +/obj/item/pen, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Nn" = ( +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/structure/table, +/obj/item/petri_dish/random, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Nr" = ( +/obj/effect/turf_decal/siding/wood/corner{ + dir = 8 + }, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"Nz" = ( +/obj/structure/mecha_wreckage/ripley, +/turf/open/indestructible{ + icon_state = "recharge_floor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"NE" = ( +/obj/structure/sign/warning/biohazard/directional/west, +/obj/structure/broken_flooring/corner/always_floorplane{ + dir = 1 + }, +/obj/item/kirbyplants/random/dead, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"NI" = ( +/obj/lightning_thrower, +/obj/machinery/light/small/dim/directional/north, +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/yellow/filled/warning{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"NK" = ( +/obj/structure/filingcabinet/chestdrawer, +/turf/open/floor/iron/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"NL" = ( +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"NU" = ( +/obj/structure/window/spawner/directional/west, +/obj/structure/window/spawner/directional/east, +/obj/structure/window/spawner/directional/south, +/obj/effect/gibspawner/generic, +/turf/open/floor/circuit{ + baseturfs = /turf/open/indestructible/plating + }, +/area/ruin/space/has_grav/powered/biooutpost) +"Oh" = ( +/obj/effect/spawner/structure/window/hollow/end{ + dir = 1 + }, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"Oi" = ( +/obj/structure/sign/warning/biohazard/directional/north, +/obj/effect/turf_decal/tile/red/half/contrasted{ + dir = 1 + }, +/obj/structure/table/reinforced, +/obj/item/book/manual/wiki/security_space_law, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Oo" = ( +/obj/effect/decal/cleanable/blood/tracks, +/turf/open/floor/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"OC" = ( +/obj/structure/table, +/obj/item/plate/large, +/obj/effect/spawner/random/food_or_drink/donkpockets, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"OM" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 4 + }, +/obj/machinery/light/small/directional/west, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"OP" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 1 + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"OQ" = ( +/obj/machinery/door/airlock/vault{ + name = "Teleportation Research" + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"OW" = ( +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Pa" = ( +/obj/structure/reagent_dispensers/water_cooler, +/obj/effect/turf_decal/stripes/corner, +/obj/effect/turf_decal/siding/purple, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Pj" = ( +/obj/structure/broken_flooring/corner/always_floorplane, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"Pt" = ( +/obj/structure/broken_flooring/pile/always_floorplane{ + dir = 8 + }, +/obj/structure/broken_flooring/plating/directional/east, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"PF" = ( +/obj/structure/puzzle_blockade{ + id = "md_tosci" + }, +/obj/effect/turf_decal/stripes/full, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"PJ" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/obj/machinery/computer/old{ + dir = 4 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"PQ" = ( +/obj/structure/puzzle_blockade{ + id = "md_armory" + }, +/obj/effect/turf_decal/stripes/full, +/obj/machinery/puzzle_keycardpad/directional/south{ + id = "md_armory"; + name = "armory authentication pad"; + queue_size = 5 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"PT" = ( +/turf/open/floor/iron/dark/textured_large, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"PU" = ( +/turf/template_noop, +/area/template_noop) +"Qa" = ( +/obj/effect/turf_decal/siding/blue, +/obj/machinery/modular_computer/preset/civilian{ + dir = 1 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Qc" = ( +/obj/machinery/light/small/dim/directional/east, +/obj/machinery/suit_storage_unit/open, +/turf/open/floor/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"Qd" = ( +/obj/structure/table/wood/fancy/purple, +/obj/effect/spawner/random/engineering/tool_advanced, +/obj/effect/spawner/random/engineering/tool_advanced, +/turf/open/floor/iron/dark/textured_large, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Qh" = ( +/obj/effect/spawner/structure/window/hollow/reinforced/plasma/end{ + dir = 8 + }, +/obj/structure/sign/warning/electric_shock/directional/east, +/obj/structure/cable, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"Qj" = ( +/obj/machinery/door/airlock/external, +/obj/effect/mapping_helpers/airlock/welded, +/obj/effect/decal/cleanable/blood/tracks, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"Qw" = ( +/obj/structure/chair/office/light, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"QM" = ( +/obj/structure/table, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/effect/turf_decal/siding/purple{ + dir = 6 + }, +/obj/structure/sign/directions/engineering/directional/east, +/obj/effect/spawner/random/bureaucracy/pen, +/obj/item/paper/crumpled/fluff/meatderelict/shieldgens, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"QP" = ( +/obj/effect/decal/cleanable/blood/old, +/obj/structure/chair/office/light, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Ra" = ( +/obj/effect/spawner/structure/window/hollow/end, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"Rb" = ( +/obj/structure/cable, +/obj/effect/turf_decal/tile/yellow/half/contrasted, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Rf" = ( +/obj/machinery/light/dim/directional/north, +/obj/lightning_thrower, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"RD" = ( +/obj/structure/marker_beacon/burgundy, +/obj/effect/turf_decal/stripes{ + dir = 6 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/turf/open/floor/plating/airless, +/area/ruin/space) +"RH" = ( +/mob/living/basic/living_floor/white, +/obj/effect/decal/cleanable/blood/tracks, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"RN" = ( +/obj/item/flashlight/flare{ + icon_state = "flare-on" + }, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"RQ" = ( +/obj/effect/decal/cleanable/glass, +/mob/living/basic/living_limb_flesh, +/obj/item/kirbyplants/random/dead, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"RS" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"Se" = ( +/obj/effect/turf_decal/tile/red/half/contrasted, +/obj/structure/chair/office{ + dir = 8 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Sj" = ( +/obj/machinery/power/rtg/old_station, +/obj/structure/cable, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/machinery/light/small/directional/south, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Sz" = ( +/mob/living/basic/meteor_heart/opens_puzzle_door{ + id = "md_heart"; + name = "tumor heart" + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"SX" = ( +/obj/structure/chair/comfy/black, +/turf/open/floor/iron/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"SZ" = ( +/obj/machinery/door/airlock/engineering, +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 1 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Tc" = ( +/obj/structure/table, +/obj/effect/spawner/random/engineering/toolbox, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Tl" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Tw" = ( +/obj/structure/table/wood/fancy/orange, +/obj/item/food/pancakes/chocolatechip, +/obj/item/toy/figure/cargotech{ + pixel_y = 12 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"TP" = ( +/obj/effect/turf_decal/siding/purple/corner{ + dir = 4 + }, +/obj/effect/turf_decal/siding/purple/corner{ + dir = 1 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"TU" = ( +/obj/structure/showcase/horrific_experiment, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Ue" = ( +/obj/machinery/photocopier, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Ui" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 8 + }, +/obj/machinery/light/small/dim/directional/north, +/obj/effect/spawner/random/vending/colavend, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"Uj" = ( +/obj/structure/window/spawner/directional/north, +/obj/structure/window/spawner/directional/east, +/obj/structure/window/spawner/directional/south, +/obj/structure/window/spawner/directional/west, +/obj/effect/gibspawner/generic, +/mob/living/basic/living_limb_flesh, +/turf/open/floor/circuit{ + baseturfs = /turf/open/indestructible/plating + }, +/area/ruin/space/has_grav/powered/biooutpost) +"Ut" = ( +/mob/living/basic/living_limb_flesh, +/obj/machinery/light/small/dim/directional/east, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"Uv" = ( +/obj/machinery/light/small/dim/directional/west, +/obj/machinery/suit_storage_unit/open, +/turf/open/floor/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"UD" = ( +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"UG" = ( +/obj/machinery/vending/tool, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"UN" = ( +/obj/effect/turf_decal/siding/purple{ + dir = 10 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"UX" = ( +/turf/closed/indestructible/riveted/plastinum/nodiagonal, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Vc" = ( +/obj/structure/cable, +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/yellow/filled/warning{ + dir = 1 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Vj" = ( +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 8 + }, +/obj/structure/cable, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Vn" = ( +/obj/structure/table/wood/fancy/purple, +/obj/item/raw_anomaly_core/bluespace, +/turf/open/floor/iron/dark/textured_large, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Vu" = ( +/obj/structure/broken_flooring/side/always_floorplane{ + dir = 4 + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"VB" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red/half/contrasted{ + dir = 4 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"VJ" = ( +/obj/machinery/door/airlock/medical, +/obj/effect/turf_decal/siding/blue{ + dir = 8 + }, +/obj/effect/turf_decal/siding/blue{ + dir = 4 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"VN" = ( +/obj/effect/decal/cleanable/dirt, +/obj/item/ammo_casing/c45/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"VT" = ( +/obj/structure/broken_flooring/singular{ + dir = 1 + }, +/obj/structure/table, +/obj/item/food/strawberryicecreamsandwich, +/obj/item/food/strawberryicecreamsandwich, +/obj/item/food/strawberryicecreamsandwich, +/obj/item/food/strawberryicecreamsandwich, +/obj/structure/closet/mini_fridge, +/obj/structure/broken_flooring/singular/always_floorplane{ + dir = 1 + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"VW" = ( +/obj/effect/turf_decal/tile/yellow/fourcorners, +/obj/machinery/light/floor, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"We" = ( +/obj/machinery/door/airlock/engineering, +/obj/structure/cable, +/obj/effect/turf_decal/tile/yellow/fourcorners, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Wj" = ( +/mob/living/basic/living_floor, +/obj/item/chair, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"Wx" = ( +/obj/structure/broken_flooring/pile/always_floorplane{ + dir = 1 + }, +/obj/structure/broken_flooring/plating/directional/north, +/obj/machinery/light/cold/dim/directional/east, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"WJ" = ( +/obj/effect/turf_decal/tile/purple/half/contrasted{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Xe" = ( +/obj/effect/turf_decal/siding/red, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/machinery/light/cold/directional/east, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"Xh" = ( +/obj/machinery/door/airlock/engineering, +/obj/structure/cable, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Xl" = ( +/obj/structure/table, +/obj/item/flashlight/lamp, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"Xm" = ( +/obj/structure/table/wood/fancy/orange, +/obj/item/ai_module/core/full/ten_commandments, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/carpet, +/area/ruin/space/has_grav/powered/biooutpost) +"Xo" = ( +/obj/structure/showcase/horrific_experiment, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Xp" = ( +/obj/structure/puzzle_blockade/meat{ + id = "md_heart" + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Xz" = ( +/obj/machinery/door/puzzle/keycard{ + puzzle_id = "md_engpost" + }, +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 1 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"XA" = ( +/turf/closed/mineral/random, +/area/ruin/space) +"XD" = ( +/obj/structure/broken_flooring/pile/always_floorplane, +/obj/structure/cable, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"XO" = ( +/obj/structure/sign/directions/security/directional/south{ + pixel_x = 32 + }, +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/structure/sign/poster/official/random/directional/east, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"XP" = ( +/turf/closed/mineral/bananium, +/area/ruin/space) +"XQ" = ( +/obj/effect/mob_spawn/corpse/human/scientist, +/obj/effect/decal/cleanable/glass, +/obj/machinery/light/small/dim/directional/west, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Yc" = ( +/turf/closed/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost/vault) +"Yd" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/turf/open/indestructible/plating, +/area/ruin/space/has_grav/powered/biooutpost) +"Yr" = ( +/obj/structure/window/spawner/directional/east, +/mob/living/basic/living_limb_flesh, +/mob/living/basic/living_limb_flesh, +/obj/item/keycard/meatderelict/armory, +/obj/machinery/light/small/dim/directional/west, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"Ys" = ( +/obj/effect/turf_decal/trimline/yellow/filled/end{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/cable, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"YD" = ( +/obj/item/ammo_casing/spent, +/obj/item/ammo_casing/spent, +/obj/effect/decal/cleanable/blood/tracks, +/obj/item/ammo_casing/c45/spent, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"YI" = ( +/obj/structure/broken_flooring/corner/always_floorplane{ + dir = 8 + }, +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"YW" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line, +/obj/structure/rack, +/obj/structure/sign/warning/chem_diamond/directional/south, +/obj/machinery/door/window/left/directional/north, +/obj/item/grenade/chem_grenade/large, +/obj/item/grenade/chem_grenade/adv_release{ + pixel_x = 8 + }, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"YY" = ( +/obj/structure/filingcabinet/chestdrawer, +/turf/open/indestructible/white{ + icon_state = "showroomfloor" + }, +/area/ruin/space/has_grav/powered/biooutpost) +"Zd" = ( +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ + dir = 8 + }, +/obj/structure/chair/office{ + dir = 1 + }, +/turf/open/indestructible, +/area/ruin/space/has_grav/powered/biooutpost) +"Zp" = ( +/obj/effect/turf_decal/siding/blue/corner, +/obj/effect/turf_decal/siding/blue/corner{ + dir = 8 + }, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Zr" = ( +/obj/item/gps/spaceruin, +/turf/open/floor/plating/airless, +/area/ruin/space) +"Zs" = ( +/obj/structure/door_assembly/door_assembly_science, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"Zv" = ( +/obj/effect/decal/cleanable/glass, +/obj/item/kirbyplants/random, +/turf/open/floor/iron/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"Zx" = ( +/turf/open/indestructible/meat, +/area/ruin/space/has_grav/powered/biooutpost) +"ZG" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/rack, +/obj/item/storage/medkit/brute, +/turf/open/indestructible/dark, +/area/ruin/space/has_grav/powered/biooutpost) +"ZT" = ( +/obj/effect/turf_decal/tile/purple/opposingcorners, +/obj/machinery/light/cold/dim/directional/east, +/turf/open/indestructible/white, +/area/ruin/space/has_grav/powered/biooutpost) +"ZZ" = ( +/obj/structure/fluff/oldturret, +/turf/open/floor/plating/airless, +/area/ruin/space) + +(1,1,1) = {" +PU +PU +PU +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +PU +re +re +re +re +re +re +re +PU +PU +PU +re +re +re +re +re +PU +PU +PU +PU +PU +PU +"} +(2,1,1) = {" +PU +PU +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +PU +"} +(3,1,1) = {" +PU +PU +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +Jh +Jh +Jh +Jh +Jh +re +re +re +re +re +re +re +re +re +re +re +re +re +re +"} +(4,1,1) = {" +PU +PU +re +re +XA +XA +XA +XA +XA +XA +XA +XA +re +Jh +Jh +Jh +Jh +Jh +Jh +Jh +Jh +Jh +lh +eF +PJ +Jh +hd +re +re +re +Jh +Jh +Jh +Jh +re +re +re +re +re +re +"} +(5,1,1) = {" +PU +PU +re +re +XA +XA +XA +XA +XA +XA +XA +XA +re +Jh +fH +fH +fH +fH +fH +fH +Jh +Dh +vt +vt +oX +dQ +hd +re +re +Jh +Jh +se +ku +Jh +Jh +re +re +re +re +re +"} +(6,1,1) = {" +PU +PU +re +re +XA +XA +XA +XA +XA +XA +XA +XA +re +Jh +fH +xU +Ec +eq +tF +fH +Jh +Fc +fo +oX +oX +YW +hd +re +re +Jh +ny +Gb +Gb +ny +Jh +Jh +Jh +re +re +re +"} +(7,1,1) = {" +PU +PU +re +re +XA +XA +XA +XA +XA +XA +XA +XA +re +Jh +fH +Ec +Hh +Ec +aV +fH +Jh +Bx +CS +RS +HC +rl +hd +re +re +Jh +Jh +Ei +Jh +Jh +Jh +Yr +Jh +Jh +re +re +"} +(8,1,1) = {" +PU +XA +XA +XA +XA +XA +XA +XA +XA +XA +XA +XA +re +Jh +fH +qx +ni +Ec +jt +fH +Jh +Jh +Ra +Zs +Oh +fH +Jh +re +Jh +Jh +AP +DJ +yU +AT +vF +ih +hf +Jh +Jh +re +"} +(9,1,1) = {" +PU +XA +XA +XA +XA +XA +XA +XA +XA +XA +XA +XA +re +Jh +Jh +Jh +Jh +Jh +hY +Jh +fH +EE +Ec +at +Ec +Pt +Jh +Jh +Jh +pK +DJ +DJ +qs +pj +kl +kl +QP +kh +Jh +re +"} +(10,1,1) = {" +XA +XA +XP +XP +XA +XA +XA +re +re +re +re +re +re +re +re +Jh +dv +cp +DJ +NU +fH +OC +Ec +yl +Ec +Ec +Jh +Kc +JF +DJ +kl +qs +sp +Jh +RQ +jA +lf +Jh +Jh +re +"} +(11,1,1) = {" +XA +XA +XP +re +re +re +re +re +re +re +re +re +re +re +re +Jh +iQ +cp +DJ +CI +lJ +Ka +RH +uC +Mp +uC +Cl +DJ +DJ +DJ +DJ +dW +DJ +Jh +Jh +Ut +Jh +Jh +re +re +"} +(12,1,1) = {" +XA +XA +XA +re +re +re +re +re +Jh +Jh +Jh +Jh +Jh +Jh +Jh +Jh +Uj +DJ +Gb +xk +Jh +hQ +iX +Zx +Zx +iB +Jh +Nn +DJ +ZT +DJ +dW +kl +ui +Jh +Jh +Jh +re +re +re +"} +(13,1,1) = {" +XA +XA +re +re +re +re +Jh +Jh +Jh +eT +Xm +Tw +tg +Jh +gN +Ue +cp +Ju +fW +pQ +Jh +Bp +Lj +wy +Zx +Wx +Jh +bR +DJ +Jh +Jh +oj +Jh +Jh +Jh +re +re +re +re +re +"} +(14,1,1) = {" +XA +re +re +re +re +re +Jh +Zv +il +id +MH +HF +KP +vY +Ju +DJ +ea +mA +Gb +vZ +Jh +Jh +tt +wJ +tt +Jh +Jh +Jh +Cl +Jh +oX +gQ +zL +Jh +re +re +re +re +re +re +"} +(15,1,1) = {" +re +re +re +re +re +re +Jh +oQ +SX +Lc +Bl +dR +MO +Jh +wX +wM +DJ +cp +XO +Ju +op +op +at +HF +CW +Jh +Br +Mb +at +eA +vt +zs +Gn +Jh +re +re +re +re +re +re +"} +(16,1,1) = {" +re +re +re +re +re +re +Jh +NK +il +oh +Nr +kB +Jh +UX +UX +EC +xr +hR +UX +UX +UX +op +Gd +WJ +Jf +Jh +Br +Xe +jE +Jh +FI +CN +Xl +Jh +re +re +nr +nr +re +nr +"} +(17,1,1) = {" +re +re +re +re +re +re +Jh +Jh +Jh +Jh +Jh +Jh +Jh +Yc +Yc +EC +OQ +EC +Yc +Yc +UX +UX +Jh +uZ +Jh +Jh +Jh +Jh +PF +Jh +af +sl +Jh +Jh +re +ZZ +ML +ML +ML +ML +"} +(18,1,1) = {" +re +re +re +EC +EC +EC +EC +EC +EC +re +re +re +Yc +Yc +TU +EN +EN +eP +TU +Yc +Yc +UX +wR +yw +nP +zg +Jh +Df +GA +bh +bi +UN +Jh +ij +ij +ML +BA +LR +LR +eo +"} +(19,1,1) = {" +re +re +EC +EC +Jo +Qd +zS +hk +EC +Yc +EC +Yc +Yc +TU +EN +eP +EN +EN +EN +TU +Yc +UX +uh +AY +AY +Se +Jh +sk +at +sM +Jb +Pa +Jh +Uv +ij +ML +tS +AV +AV +kX +"} +(20,1,1) = {" +re +re +EC +Fv +PT +aW +OW +PT +EC +Xo +XQ +TU +Yc +EN +EN +EN +EN +EN +eP +EN +EC +EC +Oi +AY +AY +fm +Jh +Kl +zF +Bu +VN +HA +ph +FE +jo +cQ +tS +AV +AV +kX +"} +(21,1,1) = {" +re +re +EC +AX +PT +qw +sd +PT +Jx +CD +EN +CD +Xp +EN +eP +EN +Sz +eP +EN +EN +OQ +Bt +gX +VB +VB +qg +Jh +DU +mM +YD +lm +mU +Jh +us +ij +cQ +tS +AV +AV +kX +"} +(22,1,1) = {" +re +re +EC +ja +PT +NL +uU +PT +EC +TU +rK +Xo +Yc +EN +EN +EN +EN +EN +EN +eP +EC +hR +IK +IK +IK +PQ +Jh +iI +jE +Hx +Ew +nY +Qj +Oo +uq +uH +tS +AV +AV +kX +"} +(23,1,1) = {" +re +re +EC +EC +ne +AG +Vn +GE +EC +Yc +EC +Yc +Yc +TU +EN +eP +EN +eP +EN +TU +Yc +UX +wH +jU +ZG +gK +Jh +Hb +Kx +nR +uc +QM +Jh +Qc +ij +ML +tS +AV +AV +kX +"} +(24,1,1) = {" +re +re +re +EC +EC +EC +EC +EC +EC +EC +EC +EC +Yc +Yc +TU +EN +EN +EN +TU +Yc +Yc +Jh +Jh +Jh +Jh +Jh +Jh +Jh +oO +zF +hW +Jh +Jh +ij +ij +Zr +sL +Gj +Gj +RD +"} +(25,1,1) = {" +re +re +re +re +re +ij +xE +MF +Mo +dD +Zd +EC +EC +Yc +Yc +EC +OQ +EC +Yc +Yc +UX +Jh +Jh +vd +jf +la +fc +Jh +rh +DC +Be +Jh +re +re +re +ZZ +ML +ML +ML +ML +"} +(26,1,1) = {" +re +re +re +re +re +ij +Jt +pl +We +Vc +Rb +Sj +EC +Yc +hR +EC +xr +EC +EC +UX +Jh +YY +Jh +Tl +jE +jE +Zp +VJ +TP +jE +kn +Jh +re +re +re +re +nr +re +re +nr +"} +(27,1,1) = {" +re +re +re +re +re +ij +NI +Hm +Qh +ki +UD +qV +ij +Nz +sJ +OM +Vu +NE +fH +Jh +fB +ch +Jh +Ll +jE +nx +aj +Jh +Cf +go +GC +Jh +re +re +re +re +re +re +re +re +"} +(28,1,1) = {" +re +re +re +re +re +ij +ij +ij +ij +ab +ij +ij +ij +Dg +jj +mx +Zx +EQ +fH +Jh +Ex +tv +ex +Tl +jE +Qw +Qa +Jh +Jh +KU +Jh +Jh +ij +ij +ij +ij +re +re +re +re +"} +(29,1,1) = {" +re +re +re +re +re +re +re +ij +GF +zP +iA +iA +hN +sJ +OP +io +jj +uS +ij +Jh +qi +ch +Jh +eD +jE +at +mO +Jh +ra +rm +iA +An +ij +yu +za +ij +re +re +nr +nr +"} +(30,1,1) = {" +PU +re +re +re +re +re +re +ij +Rf +Ys +sR +iA +hN +jj +Zx +Vu +pe +DR +ij +Jh +aE +pk +Jh +Tl +jE +rw +jV +Jh +pY +Vj +pY +By +nM +pp +jr +ij +re +re +nr +nr +"} +(31,1,1) = {" +PU +re +re +re +re +re +re +ij +GF +xA +iA +qY +hN +jj +Zx +Zx +VT +po +ij +Jh +wn +ch +Jh +Ki +GO +wf +Jh +Jh +Yd +yp +Yd +ij +ij +DB +Zx +fH +re +re +nr +PU +"} +(32,1,1) = {" +PU +re +re +re +re +re +re +ij +ij +ij +wj +wj +ij +Ui +Zx +Zx +OP +fH +fH +Jh +Jh +Jh +Jh +Jh +Jh +Jh +Jh +ij +KH +au +yr +ij +CF +sJ +ij +ij +re +re +re +PU +"} +(33,1,1) = {" +PU +re +re +re +re +re +re +re +re +ij +MS +pC +wj +ES +Zx +Zx +OP +ij +fH +ij +fH +fH +fH +ij +ij +ij +re +ij +RN +os +yr +wj +lT +Ca +ij +re +re +re +re +PU +"} +(34,1,1) = {" +PU +PU +re +re +re +re +re +re +re +ij +KC +qY +Xz +YI +mx +mx +Pj +ij +tq +Wj +DB +DB +DB +oI +uf +ij +ij +ij +yr +au +yr +wj +jO +yf +ij +re +re +re +re +PU +"} +(35,1,1) = {" +PU +PU +re +nr +nr +nr +re +re +re +ij +ij +ij +ij +ij +vl +tN +UD +ij +DB +DB +qh +qZ +Ip +Du +mx +ij +aF +yr +yr +os +yr +ij +gO +jO +ij +re +re +re +re +nr +"} +(36,1,1) = {" +PU +PU +nr +nr +nr +nr +nr +re +re +re +re +re +re +ij +ay +VW +iA +SZ +jO +Tc +Dk +DB +DB +Du +jO +mc +yr +au +os +au +XD +ij +ij +iO +ij +re +re +re +re +nr +"} +(37,1,1) = {" +PU +PU +re +re +re +nr +nr +nr +re +re +re +re +re +ij +UG +iA +xm +ij +DB +DB +DB +DB +Wj +DB +Vu +ij +aF +gP +EY +yr +wU +Xh +jO +HV +ij +re +re +re +re +re +"} +(38,1,1) = {" +PU +PU +PU +re +re +nr +re +re +re +re +re +re +re +ij +ij +ij +ij +ij +ij +fH +AD +AD +AD +AD +fH +ij +ij +ij +ij +ij +ij +ij +ij +ij +ij +re +re +re +re +re +"} +(39,1,1) = {" +PU +PU +PU +re +re +nr +nr +nr +re +re +re +re +re +re +re +re +re +re +re +fH +fH +ij +fH +ij +ij +re +re +re +re +re +re +re +re +re +re +re +re +re +re +nr +"} +(40,1,1) = {" +PU +PU +PU +PU +PU +PU +PU +PU +PU +PU +PU +PU +PU +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +re +nr +nr +"} diff --git a/_maps/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/RandomRuins/SpaceRuins/oldstation.dmm index 18dc918a109216..88da3cd7f72b99 100644 --- a/_maps/RandomRuins/SpaceRuins/oldstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/oldstation.dmm @@ -5152,15 +5152,6 @@ /obj/machinery/light/directional/south, /turf/open/floor/iron, /area/ruin/space/ancientstation/beta/hall) -"By" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/computer/monitor, -/obj/machinery/computer/monitor, -/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ - dir = 1 - }, -/turf/open/floor/iron, -/area/ruin/space/ancientstation/charlie/engie) "Bz" = ( /turf/open/floor/plating/airless, /area/ruin/space/ancientstation/beta/hall) @@ -5178,11 +5169,6 @@ /obj/structure/cable, /turf/template_noop, /area/space/nearstation) -"BC" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/fluff/broken_canister_frame, -/turf/open/floor/engine/airless, -/area/ruin/space/ancientstation/beta/supermatter) "BH" = ( /obj/item/solar_assembly, /obj/structure/cable, @@ -5427,6 +5413,11 @@ }, /turf/open/floor/iron, /area/ruin/space/ancientstation/delta/rnd) +"DK" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/fluff/broken_canister_frame, +/turf/open/floor/engine/airless, +/area/ruin/space/ancientstation/beta/supermatter) "DM" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, @@ -6513,6 +6504,14 @@ /obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/engine/o2, /area/ruin/space/ancientstation/beta/atmos) +"Ll" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/computer/monitor, +/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ + dir = 1 + }, +/turf/open/floor/iron, +/area/ruin/space/ancientstation/charlie/engie) "Lm" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -10556,7 +10555,7 @@ NU xY lI CN -BC +DK iv Qi ZD @@ -11607,7 +11606,7 @@ mS jE aa Ma -By +Ll eK fc Wn diff --git a/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm b/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm index 76e7da25fa414e..65c1413bec84bd 100644 --- a/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm +++ b/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm @@ -744,7 +744,6 @@ "jD" = ( /obj/machinery/light/small/directional/east, /obj/structure/closet/emcloset, -/obj/machinery/light/small/directional/east, /turf/open/floor/iron/airless, /area/ruin/space/ks13/dorms) "jV" = ( @@ -3633,8 +3632,6 @@ pixel_x = -5; pixel_y = 9 }, -/obj/item/wallframe/apc, -/obj/machinery/light/small/directional/west, /turf/open/floor/iron/airless, /area/ruin/space/ks13/engineering/tech_storage) "Ce" = ( @@ -4080,7 +4077,6 @@ /area/ruin/space/ks13/science/rnd) "EC" = ( /obj/machinery/portable_atmospherics/canister/plasma, -/obj/machinery/portable_atmospherics/canister/plasma, /turf/open/floor/iron/airless, /area/ruin/space/ks13/engineering/singulo) "ED" = ( @@ -4254,7 +4250,6 @@ /area/ruin/space/ks13/hallway/aft) "Fy" = ( /obj/machinery/light/small/directional/west, -/obj/machinery/light/small/directional/west, /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/iron/airless, /area/ruin/space/ks13/engineering/singulo) @@ -6070,7 +6065,6 @@ /obj/machinery/light/small/directional/east, /obj/item/circuitboard/machine/smes, /obj/structure/table, -/obj/machinery/light/small/directional/east, /obj/effect/spawner/random/maintenance, /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/iron/airless, diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/cargodiselost.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/cargodiselost.dmm index 5fc13acae1695a..fa4f71418e1df7 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/cargodiselost.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/cargodiselost.dmm @@ -250,7 +250,7 @@ /turf/open/floor/iron/smooth, /area/ruin/space/has_grav/cargodise_freighter/utility) "dT" = ( -/mob/living/simple_animal/hostile/pirate/melee{ +/mob/living/basic/trooper/pirate/melee{ faction = list("hostile") }, /turf/open/floor/mineral/plastitanium, @@ -2159,11 +2159,6 @@ }, /turf/open/floor/iron/white, /area/ruin/space/has_grav/cargodise_freighter/trauma) -"IA" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/kitchen, -/area/ruin/space/has_grav/cargodise_freighter/kitchen) "IP" = ( /obj/machinery/vending/dinnerware, /turf/open/floor/iron/kitchen, @@ -2902,7 +2897,7 @@ /area/ruin/space/has_grav/cargodise_freighter/primaryhall) "UP" = ( /obj/effect/turf_decal/trimline/blue/line, -/mob/living/simple_animal/hostile/pirate/melee{ +/mob/living/basic/trooper/pirate/melee{ faction = list("hostile") }, /turf/open/floor/iron/dark/textured_half{ @@ -3039,12 +3034,6 @@ /obj/machinery/light/directional/south, /turf/open/floor/iron/kitchen, /area/ruin/space/has_grav/cargodise_freighter/kitchen) -"WE" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/ruin/space/has_grav/cargodise_freighter/kitchen) "WJ" = ( /obj/effect/turf_decal/tile/yellow/half{ dir = 4 @@ -4066,7 +4055,7 @@ Ey WQ Gg Zq -WE +wd YY Gg UL @@ -4635,7 +4624,7 @@ vH vH Gg gc -IA +FT FT FT JC diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/piratefort.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/piratefort.dmm index 097dacaa1fd1df..e79f5902d5d705 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/piratefort.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/piratefort.dmm @@ -171,7 +171,7 @@ /turf/open/floor/iron/dark, /area/ruin/space/has_grav/powered) "ga" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /turf/open/floor/carpet, /area/ruin/space/has_grav/powered) "ge" = ( @@ -340,7 +340,7 @@ /turf/open/floor/iron/dark, /area/ruin/space/has_grav/powered) "mx" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /obj/effect/turf_decal/trimline/dark_blue/filled/line{ dir = 10 }, @@ -459,7 +459,7 @@ /turf/open/floor/wood, /area/ruin/space/has_grav/powered) "pS" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /obj/effect/turf_decal/trimline/dark_red/filled/line{ dir = 8 }, @@ -665,7 +665,7 @@ /turf/open/floor/iron/dark, /area/ruin/space/has_grav/powered) "wr" = ( -/mob/living/simple_animal/hostile/pirate/ranged, +/mob/living/basic/trooper/pirate/ranged, /obj/effect/turf_decal/trimline/dark_red/filled/line{ dir = 8 }, @@ -737,7 +737,7 @@ /turf/open/floor/iron/dark, /area/ruin/space/has_grav/powered) "xM" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /turf/open/floor/wood, /area/ruin/space/has_grav/powered) "xV" = ( @@ -779,7 +779,7 @@ /turf/open/floor/iron/kitchen, /area/ruin/space/has_grav/powered) "yE" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /obj/effect/turf_decal/trimline/dark_red/filled/corner{ dir = 8 }, @@ -837,7 +837,7 @@ /turf/open/floor/carpet, /area/ruin/space/has_grav/powered) "AA" = ( -/mob/living/simple_animal/hostile/pirate/ranged, +/mob/living/basic/trooper/pirate/ranged, /obj/effect/turf_decal/trimline/dark_red/filled/line{ dir = 4 }, @@ -944,7 +944,7 @@ /turf/open/floor/iron/dark, /area/ruin/space/has_grav/powered) "EC" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /obj/effect/turf_decal/trimline/dark_red/filled/line{ dir = 1 }, @@ -999,7 +999,7 @@ /turf/open/floor/iron/kitchen, /area/ruin/space/has_grav/powered) "Gc" = ( -/mob/living/simple_animal/hostile/pirate/ranged, +/mob/living/basic/trooper/pirate/ranged, /turf/open/floor/wood, /area/ruin/space/has_grav/powered) "Gf" = ( @@ -1096,7 +1096,7 @@ /turf/closed/wall/r_wall/syndicate, /area/ruin/space/has_grav/powered) "LG" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/powered) "LI" = ( @@ -1112,7 +1112,7 @@ /turf/open/floor/wood, /area/ruin/space/has_grav/powered) "Ma" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /obj/effect/turf_decal/trimline/dark_red/filled/line, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/powered) @@ -1281,7 +1281,7 @@ /turf/open/floor/plating, /area/ruin/space/has_grav/powered) "TK" = ( -/mob/living/simple_animal/hostile/pirate/ranged/space, +/mob/living/basic/trooper/pirate/ranged/space, /turf/open/misc/asteroid/lowpressure, /area/ruin/space) "TO" = ( @@ -1332,7 +1332,7 @@ /turf/open/floor/iron/dark, /area/ruin/space/has_grav/powered) "UL" = ( -/mob/living/simple_animal/hostile/pirate/ranged{ +/mob/living/basic/trooper/pirate/ranged{ health = 200; maxHealth = 200; name = "Pirate Captain" @@ -1360,11 +1360,11 @@ /turf/open/floor/iron/dark, /area/ruin/space/has_grav/powered) "VI" = ( -/mob/living/simple_animal/hostile/pirate/melee/space, +/mob/living/basic/trooper/pirate/melee/space, /turf/open/misc/asteroid/lowpressure, /area/ruin/space) "VL" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /obj/effect/turf_decal/trimline/dark_red/filled/corner{ dir = 1 }, diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon2.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon2.dmm index fdf272d8aa453d..808950d1cafb7f 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon2.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon2.dmm @@ -107,7 +107,7 @@ /turf/open/misc/asteroid/airless, /area/solars/tarkon) "aA" = ( -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/dirt, /turf/open/floor/cult, /area/ruin/space/has_grav/port_tarkon/observ) @@ -128,7 +128,7 @@ /turf/open/floor/cult, /area/ruin/space/has_grav/port_tarkon/porthall) "aO" = ( -/mob/living/simple_animal/hostile/construct/wraith/hostile{ +/mob/living/basic/construct/wraith/hostile{ health = 125; maxHealth = 125 }, @@ -657,7 +657,7 @@ /obj/structure/chair/sofa/corp{ dir = 8 }, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/ruin/space/has_grav/port_tarkon/observ) @@ -1462,7 +1462,7 @@ /area/ruin/space/has_grav/port_tarkon/secoff) "id" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/mob/living/simple_animal/hostile/construct/wraith/hostile{ +/mob/living/basic/construct/wraith/hostile{ health = 125; maxHealth = 125 }, @@ -1794,7 +1794,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/firealarm/directional/east, -/mob/living/simple_animal/hostile/construct/wraith/hostile, +/mob/living/basic/construct/wraith/hostile, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/ruin/space/has_grav/port_tarkon/starboardhall) @@ -2901,7 +2901,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, -/mob/living/simple_animal/hostile/construct/wraith/hostile{ +/mob/living/basic/construct/wraith/hostile{ health = 125; maxHealth = 125 }, @@ -4445,7 +4445,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/port_tarkon/trauma) "yT" = ( -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/ruin/space/has_grav/port_tarkon/porthall) @@ -4646,7 +4646,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/decal/cleanable/blood, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/ruin/space/has_grav/port_tarkon/porthall) @@ -6493,7 +6493,7 @@ "Kb" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/effect/decal/cleanable/blood, -/mob/living/simple_animal/hostile/construct/wraith/hostile{ +/mob/living/basic/construct/wraith/hostile{ health = 125; maxHealth = 125 }, @@ -6918,7 +6918,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/mob/living/simple_animal/hostile/construct/wraith/hostile{ +/mob/living/basic/construct/wraith/hostile{ health = 125; maxHealth = 125 }, @@ -7234,7 +7234,7 @@ "NZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/ruin/space/has_grav/port_tarkon/observ) @@ -7253,7 +7253,7 @@ /turf/open/floor/engine, /area/ruin/space/has_grav/port_tarkon/atmos) "Od" = ( -/mob/living/simple_animal/hostile/construct/wraith/hostile{ +/mob/living/basic/construct/wraith/hostile{ health = 125; maxHealth = 125 }, @@ -7615,7 +7615,6 @@ "Qy" = ( /obj/machinery/firealarm/directional/west, /obj/machinery/suit_storage_unit/industrial/hauler, -/obj/machinery/suit_storage_unit/industrial/hauler, /obj/effect/turf_decal/tile/brown/half{ dir = 8 }, @@ -7972,7 +7971,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 }, -/mob/living/simple_animal/hostile/construct/wraith/hostile{ +/mob/living/basic/construct/wraith/hostile{ health = 125; maxHealth = 125 }, @@ -8302,7 +8301,7 @@ /area/ruin/space/has_grav/port_tarkon/developement) "Uh" = ( /obj/effect/decal/cleanable/blood, -/mob/living/simple_animal/hostile/construct/wraith/hostile{ +/mob/living/basic/construct/wraith/hostile{ health = 125; maxHealth = 125 }, @@ -8613,7 +8612,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/port_tarkon/secoff) "Wi" = ( -/mob/living/simple_animal/hostile/construct/wraith/hostile, +/mob/living/basic/construct/wraith/hostile, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/ruin/space/has_grav/port_tarkon/starboardhall) @@ -8681,7 +8680,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/port_tarkon/forehall) "WK" = ( -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/dirt, /turf/open/floor/cult, /area/ruin/space/has_grav/port_tarkon/afthall) @@ -9060,7 +9059,7 @@ /area/ruin/space/has_grav/port_tarkon/trauma) "Zt" = ( /obj/machinery/light/dim/directional/north, -/mob/living/simple_animal/hostile/construct/wraith/hostile{ +/mob/living/basic/construct/wraith/hostile{ health = 125; maxHealth = 125 }, diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon3.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon3.dmm index 0589f45fba18c9..8232aa56a5d78a 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon3.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon3.dmm @@ -7213,7 +7213,6 @@ /obj/effect/decal/cleanable/dirt, /obj/machinery/firealarm/directional/west, /obj/machinery/suit_storage_unit/industrial/hauler, -/obj/machinery/suit_storage_unit/industrial/hauler, /obj/effect/turf_decal/tile/brown/half{ dir = 8 }, diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon4.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon4.dmm index 5514e997812365..a7294b23f633fe 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon4.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon4.dmm @@ -6335,7 +6335,6 @@ "Qy" = ( /obj/machinery/firealarm/directional/west, /obj/machinery/suit_storage_unit/industrial/hauler, -/obj/machinery/suit_storage_unit/industrial/hauler, /obj/effect/turf_decal/tile/brown/half{ dir = 8 }, diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon5.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon5.dmm index 5ebeb6648402e0..1a0adf42c2acbc 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon5.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon5.dmm @@ -6955,7 +6955,6 @@ "Qy" = ( /obj/machinery/firealarm/directional/west, /obj/machinery/suit_storage_unit/industrial/hauler, -/obj/machinery/suit_storage_unit/industrial/hauler, /obj/effect/turf_decal/tile/brown/half{ dir = 8 }, diff --git a/_maps/RandomRuins/SpaceRuins/the_outlet.dmm b/_maps/RandomRuins/SpaceRuins/the_outlet.dmm index 89f41588081387..e10d5abc1118d5 100644 --- a/_maps/RandomRuins/SpaceRuins/the_outlet.dmm +++ b/_maps/RandomRuins/SpaceRuins/the_outlet.dmm @@ -75,7 +75,7 @@ /turf/open/floor/eighties, /area/ruin/space/has_grav/the_outlet/storefront) "cK" = ( -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/machinery/light/small/directional/west, /obj/effect/decal/cleanable/blood{ icon_state = "floor2-old" @@ -1056,7 +1056,7 @@ /obj/effect/decal/cleanable/dirt{ icon_state = "dirt-4" }, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/crayon{ icon_state = "rune6" }, @@ -1222,7 +1222,7 @@ /area/ruin/space/has_grav/the_outlet/storefront) "Db" = ( /obj/effect/decal/cleanable/crayon, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /turf/open/floor/cult, /area/ruin/space/has_grav/the_outlet/cultinfluence) "Do" = ( @@ -1481,7 +1481,7 @@ /obj/effect/decal/cleanable/crayon{ icon_state = "rune2" }, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /turf/open/floor/iron/white, /area/ruin/space/has_grav/the_outlet/researchrooms) "IF" = ( @@ -1573,7 +1573,7 @@ /turf/template_noop, /area/template_noop) "LL" = ( -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/crayon{ icon_state = "rune2" }, @@ -1667,7 +1667,7 @@ /obj/effect/decal/cleanable/crayon{ icon_state = "rune4" }, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /turf/open/floor/cult, /area/ruin/space/has_grav/the_outlet/cultinfluence) "NE" = ( @@ -1976,7 +1976,7 @@ dir = 8 }, /obj/effect/decal/cleanable/crayon, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/dirt{ icon_state = "dirt-127" }, @@ -2101,7 +2101,7 @@ /turf/open/floor/iron/white, /area/ruin/space/has_grav/the_outlet/researchrooms) "Yr" = ( -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/crayon, /turf/open/floor/cult, /area/ruin/space/has_grav/the_outlet/cultinfluence) diff --git a/_maps/RandomRuins/SpaceRuins/waystation.dmm b/_maps/RandomRuins/SpaceRuins/waystation.dmm index a13a5087ee3d8f..9399ee029474db 100644 --- a/_maps/RandomRuins/SpaceRuins/waystation.dmm +++ b/_maps/RandomRuins/SpaceRuins/waystation.dmm @@ -1,13 +1,4 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"ak" = ( -/obj/structure/table/wood, -/obj/item/flashlight/lamp{ - pixel_x = -5; - pixel_y = 2; - start_on = 0 - }, -/turf/open/floor/wood, -/area/ruin/space/has_grav/waystation/dorms) "ar" = ( /obj/machinery/vending/coffee, /obj/effect/turf_decal/siding/green, @@ -35,6 +26,15 @@ }, /turf/open/floor/iron/freezer, /area/ruin/space/has_grav/waystation/dorms) +"bg" = ( +/obj/structure/table/wood, +/obj/item/flashlight/lamp{ + pixel_x = -5; + pixel_y = 2; + start_on = 0 + }, +/turf/open/floor/wood, +/area/ruin/space/has_grav/waystation/dorms) "bt" = ( /obj/effect/turf_decal/bot, /obj/effect/decal/cleanable/dirt, @@ -179,6 +179,17 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/wood, /area/ruin/space/has_grav/waystation/dorms) +"dX" = ( +/obj/effect/turf_decal/siding/red, +/obj/structure/table/reinforced, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/item/flashlight/lamp{ + pixel_x = -5; + pixel_y = 2; + start_on = 0 + }, +/turf/open/floor/iron/dark, +/area/ruin/space/has_grav/waystation/securestorage) "dY" = ( /obj/effect/mapping_helpers/burnt_floor, /obj/item/ammo_casing/c45/spent{ @@ -1377,17 +1388,6 @@ /obj/structure/broken_flooring/pile/directional/east, /turf/template_noop, /area/template_noop) -"xk" = ( -/obj/machinery/porta_turret/syndicate/pod{ - dir = 1; - max_integrity = 80 - }, -/obj/machinery/porta_turret/syndicate/pod{ - dir = 1; - max_integrity = 80 - }, -/turf/closed/wall/mineral/plastitanium, -/area/ruin/space/has_grav/powered/waystation/assaultpod) "xq" = ( /obj/machinery/conveyor{ dir = 1; @@ -1791,24 +1791,6 @@ /obj/item/storage/toolbox/mechanical/old, /turf/open/floor/plating, /area/ruin/space/has_grav/waystation) -"FK" = ( -/obj/structure/table, -/obj/item/folder{ - pixel_x = 6; - pixel_y = 3 - }, -/obj/item/pen, -/obj/item/pen{ - pixel_x = 6; - pixel_y = 2 - }, -/obj/item/flashlight/lamp{ - pixel_x = -5; - pixel_y = 2; - start_on = 0 - }, -/turf/open/floor/iron, -/area/ruin/space/has_grav/waystation/cargooffice) "FM" = ( /obj/structure/chair/comfy/shuttle{ dir = 4; @@ -1911,6 +1893,24 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/wood, /area/ruin/space/has_grav/waystation/dorms) +"IU" = ( +/obj/structure/table, +/obj/item/folder{ + pixel_x = 6; + pixel_y = 3 + }, +/obj/item/pen, +/obj/item/pen{ + pixel_x = 6; + pixel_y = 2 + }, +/obj/item/flashlight/lamp{ + pixel_x = -5; + pixel_y = 2; + start_on = 0 + }, +/turf/open/floor/iron, +/area/ruin/space/has_grav/waystation/cargooffice) "IZ" = ( /obj/effect/turf_decal/loading_area/red{ dir = 8 @@ -2101,6 +2101,16 @@ }, /turf/open/floor/iron, /area/ruin/space/has_grav/waystation/cargooffice) +"LL" = ( +/obj/structure/table/wood, +/obj/effect/decal/cleanable/dirt, +/obj/item/flashlight/lamp{ + pixel_x = -5; + pixel_y = 2; + start_on = 0 + }, +/turf/open/floor/wood, +/area/ruin/space/has_grav/waystation/dorms) "LQ" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/effect/decal/cleanable/blood/tracks{ @@ -2458,16 +2468,6 @@ }, /turf/open/floor/iron, /area/ruin/space/has_grav/waystation/cargooffice) -"RO" = ( -/obj/structure/table/wood, -/obj/effect/decal/cleanable/dirt, -/obj/item/flashlight/lamp{ - pixel_x = -5; - pixel_y = 2; - start_on = 0 - }, -/turf/open/floor/wood, -/area/ruin/space/has_grav/waystation/dorms) "RW" = ( /obj/effect/turf_decal/tile/brown/half/contrasted, /obj/item/kirbyplants/random, @@ -2581,17 +2581,6 @@ }, /turf/open/floor/iron, /area/ruin/space/has_grav/waystation/dorms) -"Uc" = ( -/obj/effect/turf_decal/siding/red, -/obj/structure/table/reinforced, -/obj/structure/window/reinforced/spawner/directional/south, -/obj/item/flashlight/lamp{ - pixel_x = -5; - pixel_y = 2; - start_on = 0 - }, -/turf/open/floor/iron/dark, -/area/ruin/space/has_grav/waystation/securestorage) "Ud" = ( /obj/machinery/door/airlock, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -4007,22 +3996,22 @@ pK pK pK Ls -ak +bg Of Ls -RO +LL Of lB -ak +bg dW Ls -RO +LL dW Ls -ak +bg dW Ls -ak +bg TL QN Dj @@ -4646,7 +4635,7 @@ xw jV UG lx -FK +IU Dc fc zh @@ -4714,7 +4703,7 @@ Qx SL jG my -xk +lM tb FM TW @@ -4832,7 +4821,7 @@ xw jV UG xv -FK +IU Dc Cx Pd @@ -5063,7 +5052,7 @@ pK yi vn LQ -Uc +dX Oj WS yi diff --git a/_maps/RandomZLevels/SnowCabin.dmm b/_maps/RandomZLevels/SnowCabin.dmm index 42e6fd5279b152..9685c667d2c263 100644 --- a/_maps/RandomZLevels/SnowCabin.dmm +++ b/_maps/RandomZLevels/SnowCabin.dmm @@ -1381,7 +1381,6 @@ /obj/machinery/space_heater, /obj/effect/decal/remains/robot, /obj/structure/sign/warning/fire/directional/north, -/obj/machinery/space_heater, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/awaymission/cabin) @@ -1640,7 +1639,7 @@ }, /area/awaymission/cabin/caves/sovietcave) "is" = ( -/obj/structure/closet/secure_closet/freezer/kitchen, +/obj/structure/closet/secure_closet/freezer/fridge/open, /obj/item/reagent_containers/condiment/enzyme, /turf/open/floor/iron/freezer, /area/awaymission/cabin) diff --git a/_maps/RandomZLevels/blackmesa.dmm b/_maps/RandomZLevels/blackmesa.dmm index a4484e7711d3f4..187a8793e96e8f 100644 --- a/_maps/RandomZLevels/blackmesa.dmm +++ b/_maps/RandomZLevels/blackmesa.dmm @@ -5090,9 +5090,6 @@ /turf/open/floor/iron/smooth, /area/awaymission/black_mesa/entrance_internal_hall) "cTO" = ( -/obj/machinery/power/emitter/energycannon{ - dir = 8 - }, /obj/machinery/power/emitter/energycannon{ dir = 8 }, @@ -6329,9 +6326,6 @@ /turf/open/floor/iron/smooth_large, /area/awaymission/black_mesa/lambda_teleporter) "fjj" = ( -/obj/machinery/power/emitter/energycannon{ - dir = 4 - }, /obj/machinery/power/emitter/energycannon{ dir = 4 }, diff --git a/_maps/RandomZLevels/moonoutpost19.dmm b/_maps/RandomZLevels/moonoutpost19.dmm index fa636a49184a81..c6eb6b38b64429 100644 --- a/_maps/RandomZLevels/moonoutpost19.dmm +++ b/_maps/RandomZLevels/moonoutpost19.dmm @@ -290,6 +290,12 @@ }, /turf/open/floor/iron/white, /area/awaymission/moonoutpost19/research) +"ca" = ( +/mob/living/basic/construct/proteon/hostile, +/turf/open/misc/asteroid/moon{ + initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251" + }, +/area/awaymission/moonoutpost19/mines) "cb" = ( /obj/machinery/light/broken/directional/east, /obj/machinery/airalarm/directional/east, @@ -393,13 +399,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/awaymission/moonoutpost19/research) -"cS" = ( -/mob/living/simple_animal/hostile/construct/proteon/hostile, -/obj/structure/flora/lunar_plant, -/turf/open/misc/asteroid/moon{ - initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251" - }, -/area/awaymission/moonoutpost19/mines) "cT" = ( /obj/structure/cable, /obj/effect/decal/cleanable/xenoblood, @@ -433,12 +432,6 @@ temperature = 251 }, /area/awaymission/moonoutpost19/syndicate) -"dr" = ( -/mob/living/simple_animal/hostile/construct/proteon/hostile, -/turf/open/misc/asteroid/moon{ - initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251" - }, -/area/awaymission/moonoutpost19/mines) "ds" = ( /obj/item/pizzabox{ pixel_x = 20; @@ -2956,6 +2949,16 @@ }, /turf/open/floor/iron, /area/awaymission/moonoutpost19/arrivals) +"sM" = ( +/obj/effect/mapping_helpers/burnt_floor, +/obj/item/flashlight/flare{ + start_on = 1 + }, +/turf/open/floor/iron{ + initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"; + temperature = 251 + }, +/area/awaymission/moonoutpost19/syndicate) "sO" = ( /obj/machinery/light/small/directional/west, /obj/effect/turf_decal/lunar_sand, @@ -3500,14 +3503,6 @@ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251" }, /area/awaymission/moonoutpost19/mines) -"wA" = ( -/obj/item/flashlight/flare{ - start_on = 1 - }, -/turf/open/misc/asteroid/moon{ - initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251" - }, -/area/awaymission/moonoutpost19/mines) "wD" = ( /obj/machinery/light/small/broken/directional/east, /obj/effect/decal/cleanable/dirt, @@ -4980,6 +4975,13 @@ /obj/structure/cable, /turf/open/floor/iron, /area/awaymission/moonoutpost19/arrivals) +"GQ" = ( +/mob/living/basic/construct/proteon/hostile, +/obj/structure/flora/lunar_plant, +/turf/open/misc/asteroid/moon{ + initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251" + }, +/area/awaymission/moonoutpost19/mines) "GR" = ( /obj/effect/decal/cleanable/cobweb/cobweb2, /turf/open/floor/plating, @@ -5450,16 +5452,6 @@ temperature = 251 }, /area/awaymission/moonoutpost19/syndicate) -"JU" = ( -/obj/effect/mapping_helpers/burnt_floor, -/obj/item/flashlight/flare{ - start_on = 1 - }, -/turf/open/floor/iron{ - initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"; - temperature = 251 - }, -/area/awaymission/moonoutpost19/syndicate) "JV" = ( /obj/structure/sink{ dir = 4; @@ -6176,6 +6168,14 @@ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251" }, /area/awaymission/moonoutpost19/mines) +"Pf" = ( +/obj/item/flashlight/flare{ + start_on = 1 + }, +/turf/open/misc/asteroid/moon{ + initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251" + }, +/area/awaymission/moonoutpost19/mines) "Ph" = ( /obj/effect/decal/cleanable/blood/tracks{ desc = "Your instincts say you shouldn't be following these."; @@ -15631,7 +15631,7 @@ tb tb tb tb -dr +ca mo mo FB @@ -16408,7 +16408,7 @@ eA tb tb tb -cS +GQ mo mo mo @@ -16419,7 +16419,7 @@ mo mo mo PP -dr +ca tb tb sn @@ -18718,7 +18718,7 @@ tb tb vE mo -dr +ca Qe Qe tb @@ -18987,13 +18987,13 @@ tb mo Np Zs -dr +ca mo rd tb tb sn -dr +ca tb tb tb @@ -19989,7 +19989,7 @@ tb mo mo mo -dr +ca tb tb tb @@ -20515,7 +20515,7 @@ tb tb Qe tb -dr +ca mo mo mo @@ -20529,7 +20529,7 @@ eA sn tb tb -dr +ca eA tb tb @@ -21784,7 +21784,7 @@ FB tb tb eA -dr +ca tb tb tb @@ -22077,7 +22077,7 @@ tb tb tb mo -dr +ca tb tb tb @@ -23321,7 +23321,7 @@ tb tb tb tb -dr +ca mo tb tb @@ -23577,7 +23577,7 @@ zk tb tb tb -dr +ca mo tb tb @@ -40252,7 +40252,7 @@ WZ JQ WZ lj -JU +sM WZ WZ Nr @@ -56533,7 +56533,7 @@ tb mo mo mo -wA +Pf pS tb tb diff --git a/_maps/RandomZLevels/mothership_astrum.dmm b/_maps/RandomZLevels/mothership_astrum.dmm index dac0135a5a05ae..e42e33f49a7819 100644 --- a/_maps/RandomZLevels/mothership_astrum.dmm +++ b/_maps/RandomZLevels/mothership_astrum.dmm @@ -1164,7 +1164,7 @@ /turf/open/misc/beach/coast, /area/awaymission/mothership_astrum/deck5) "tz" = ( -/mob/living/simple_animal/hostile/pirate/ranged{ +/mob/living/basic/trooper/pirate/ranged{ faction = list("Abductor") }, /turf/open/misc/beach/sand, @@ -1777,7 +1777,7 @@ /turf/open/floor/mineral/abductor, /area/awaymission/mothership_astrum/halls) "CU" = ( -/mob/living/simple_animal/hostile/pirate/melee{ +/mob/living/basic/trooper/pirate/melee{ faction = list("Abductor"); loot = list(/obj/effect/mob_spawn/corpse/human/pirate) }, @@ -1844,7 +1844,7 @@ /turf/open/floor/plating/abductor, /area/awaymission/mothership_astrum/halls) "DE" = ( -/mob/living/simple_animal/hostile/pirate/ranged{ +/mob/living/basic/trooper/pirate/ranged{ faction = list("Abductor") }, /turf/open/floor/wood, @@ -2305,10 +2305,10 @@ }, /area/awaymission/mothership_astrum/deck1) "IO" = ( -/mob/living/simple_animal/hostile/pirate/ranged{ +/mob/living/basic/trooper/pirate/ranged{ faction = list("Abductor") }, -/mob/living/simple_animal/hostile/pirate/ranged{ +/mob/living/basic/trooper/pirate/ranged{ faction = list("Abductor"); health = 200 }, diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index 4371f4f2489257..e6af579a236c81 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -85,14 +85,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/engineering/atmos/project) -"acO" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/effect/spawner/random/maintenance, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/security/tram) "acS" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -528,6 +520,10 @@ /obj/item/clothing/mask/gas/owl_mask, /turf/open/floor/wood, /area/station/maintenance/fore/greater) +"akF" = ( +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, +/turf/closed/wall, +/area/station/maintenance/port/aft) "akR" = ( /obj/effect/turf_decal/tile/dark_red/half/contrasted{ dir = 1 @@ -1093,6 +1089,12 @@ /obj/machinery/airalarm/directional/west, /turf/open/floor/iron/dark, /area/station/medical/pharmacy) +"awe" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/tram, +/area/station/security/tram) "awi" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/chair/plastic{ @@ -1195,11 +1197,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/fore) -"ays" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/structure/frame/machine, -/turf/open/floor/tram, -/area/station/security/tram) "ayu" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -1321,6 +1318,15 @@ }, /turf/open/floor/iron/dark, /area/station/science/xenobiology) +"aAV" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/frame/computer{ + dir = 1 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "aBs" = ( /obj/effect/turf_decal/stripes/line{ dir = 5 @@ -1412,6 +1418,10 @@ }, /turf/closed/wall, /area/station/hallway/primary/central/fore) +"aCR" = ( +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/maint_right, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "aCZ" = ( /obj/effect/turf_decal/sand/plating, /obj/structure/rack, @@ -1426,6 +1436,10 @@ }, /turf/open/floor/plating/airless, /area/station/science/ordnance/bomb) +"aEa" = ( +/obj/effect/turf_decal/stripes/white/line, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "aEc" = ( /obj/structure/disposalpipe/trunk{ dir = 1 @@ -1769,6 +1783,17 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/construction/mining/aux_base) +"aLv" = ( +/obj/structure/transport/linear/tram, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/structure/fluff/tram_rail/floor{ + dir = 1 + }, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "aLA" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -1919,6 +1944,12 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/station/engineering/supermatter/room) +"aOX" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 6 + }, +/turf/open/floor/tram, +/area/station/security/tram) "aOZ" = ( /obj/effect/decal/cleanable/dirt, /obj/item/pickaxe, @@ -1936,13 +1967,6 @@ "aPb" = ( /turf/open/floor/plating/rust, /area/station/engineering/atmos/project) -"aPe" = ( -/obj/structure/transport/linear/tram, -/obj/structure/thermoplastic, -/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/sec_wing, -/obj/effect/landmark/transport/nav_beacon/tram/nav/birdshot/prison, -/turf/open/floor/tram, -/area/station/security/tram) "aPh" = ( /obj/structure/window/reinforced/plasma/spawner/directional/north, /obj/effect/turf_decal/stripes/white/line{ @@ -2462,12 +2486,15 @@ dir = 8 }, /area/station/command/corporate_showroom) -"aYO" = ( +"aYv" = ( +/obj/structure/transport/linear/tram, /obj/effect/turf_decal/stripes/white/line{ - dir = 1 + dir = 8 }, +/obj/structure/fluff/tram_rail/floor, +/obj/structure/tram, /turf/open/floor/tram, -/area/station/security/tram) +/area/station/maintenance/port/aft) "aYR" = ( /obj/structure/broken_flooring/singular/directional/east, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -2973,6 +3000,9 @@ /obj/effect/spawner/random/maintenance, /turf/open/floor/plating/rust, /area/station/maintenance/fore/greater) +"bjZ" = ( +/turf/open/floor/tram, +/area/station/security/tram) "bka" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -3152,6 +3182,13 @@ /obj/item/wrench, /turf/open/floor/plating, /area/station/engineering/supermatter/room) +"bmT" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/tram, +/area/station/security/tram) "bnc" = ( /obj/structure/table/reinforced/titaniumglass, /obj/item/pipe_dispenser, @@ -3215,6 +3252,13 @@ /obj/structure/cable, /turf/open/floor/iron/showroomfloor, /area/station/medical/surgery/theatre) +"boI" = ( +/obj/machinery/mecha_part_fabricator/maint{ + name = "forgotten exosuit fabricator" + }, +/obj/machinery/light/small/broken/directional/west, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "boK" = ( /obj/effect/turf_decal/stripes/asteroid/end{ dir = 1 @@ -3361,11 +3405,33 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark, /area/station/security/prison/workout) +"bro" = ( +/obj/structure/frame/machine, +/turf/open/floor/tram, +/area/station/security/tram) "brw" = ( /obj/effect/decal/cleanable/glass, /obj/structure/grille, /turf/open/floor/plating, /area/station/hallway/primary/port) +"bry" = ( +/obj/structure/table, +/obj/item/storage/toolbox/mechanical{ + pixel_x = -2; + pixel_y = 8 + }, +/obj/machinery/requests_console/directional/west{ + department = "Ordnance Test Range"; + name = "Test Range Requests Console" + }, +/obj/effect/mapping_helpers/requests_console/information, +/obj/effect/mapping_helpers/requests_console/assistance, +/obj/item/storage/toolbox/mechanical{ + pixel_x = 3; + pixel_y = -2 + }, +/turf/open/floor/iron, +/area/station/science/ordnance/testlab) "brz" = ( /obj/effect/turf_decal/sand/plating, /obj/effect/decal/cleanable/dirt, @@ -4218,12 +4284,6 @@ /obj/machinery/telecomms/server/presets/science, /turf/open/floor/circuit, /area/station/tcommsat/server) -"bFG" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/item/stack/sheet/mineral/titanium, -/obj/machinery/light/small/directional/south, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "bFM" = ( /obj/effect/turf_decal/tile/yellow{ dir = 4 @@ -4699,13 +4759,6 @@ /obj/machinery/computer/records/security, /turf/open/floor/wood/tile, /area/station/command/bridge) -"bQz" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/effect/spawner/random/maintenance, -/turf/open/floor/tram, -/area/station/security/tram) "bQU" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -4762,6 +4815,13 @@ /obj/effect/spawner/random/structure/grille, /turf/open/floor/plating, /area/station/maintenance/department/engine) +"bRN" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/line, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "bSj" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/rack, @@ -4857,12 +4917,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating/rust, /area/station/maintenance/department/engine) -"bUo" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 9 - }, -/turf/open/floor/tram, -/area/station/security/tram) "bUr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/tile/blue{ @@ -4935,6 +4989,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/department/engine) +"bUO" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/machinery/light/cold/directional/west, +/turf/open/floor/tram, +/area/station/security/tram) "bUX" = ( /obj/effect/turf_decal/tile/yellow, /turf/open/floor/iron/dark, @@ -5191,14 +5252,6 @@ /obj/effect/turf_decal/box/red, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) -"caE" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/button/transport/tram/directional/south{ - specific_transport_id = "bird_2"; - id = 1 - }, -/turf/open/floor/iron, -/area/station/maintenance/port/aft) "caI" = ( /obj/structure/cable, /obj/effect/decal/cleanable/glass, @@ -5852,15 +5905,12 @@ /obj/effect/turf_decal/stripes/line{ dir = 8 }, -/turf/open/floor/iron/smooth, -/area/station/engineering/supermatter) -"coH" = ( -/obj/machinery/mecha_part_fabricator/maint{ - name = "forgotten exosuit fabricator" +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "engine" }, -/obj/machinery/light/small/broken/directional/west, -/turf/open/floor/plating, -/area/station/maintenance/port/aft) +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/iron/smooth, +/area/station/engineering/supermatter/room) "coJ" = ( /obj/structure/chair/stool/directional/east, /obj/effect/decal/cleanable/dirt, @@ -6027,13 +6077,6 @@ }, /turf/open/floor/engine, /area/station/maintenance/disposal/incinerator) -"crr" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 6 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "crE" = ( /obj/structure/window/spawner/directional/north, /turf/open/space/basic, @@ -6057,6 +6100,14 @@ /obj/structure/flora/bush/flowers_pp/style_random, /turf/open/floor/grass, /area/station/service/hydroponics/garden/monastery) +"css" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 10 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "csw" = ( /obj/structure/window/reinforced/spawner/directional/south, /obj/effect/turf_decal/stripes/end, @@ -6144,13 +6195,6 @@ /obj/machinery/light/cold/directional/north, /turf/open/floor/iron, /area/station/security/prison/rec) -"cuG" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "cuS" = ( /obj/effect/mapping_helpers/broken_floor, /obj/effect/decal/cleanable/dirt, @@ -6213,17 +6257,6 @@ }, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) -"cwd" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/obj/machinery/computer/tram_controls{ - specific_transport_id = "bird_2" - }, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "cwf" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -6642,6 +6675,12 @@ }, /turf/open/space/basic, /area/space/nearstation) +"cDt" = ( +/obj/structure/chair/comfy/shuttle, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/security/tram) "cDy" = ( /obj/structure/cable, /turf/open/floor/iron/white/side{ @@ -6949,14 +6988,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/department/engine) -"cID" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/structure/transport/linear/tram, -/obj/structure/thermoplastic, -/turf/open/floor/tram, -/area/station/security/tram) "cIE" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -6979,13 +7010,6 @@ /obj/structure/chair/stool/directional/east, /turf/open/floor/iron/small, /area/station/maintenance/department/engine) -"cJu" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/effect/spawner/random/maintenance, -/turf/open/floor/tram, -/area/station/security/tram) "cJz" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -7404,6 +7428,12 @@ /obj/item/vending_refill/hydroseeds, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) +"cRW" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 9 + }, +/turf/open/floor/tram, +/area/station/security/tram) "cSk" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/structure/closet/l3closet, @@ -7462,12 +7492,6 @@ "cSC" = ( /turf/closed/wall, /area/station/commons/vacant_room/office) -"cSD" = ( -/obj/structure/transport/linear/tram, -/obj/structure/fluff/tram_rail/floor, -/obj/structure/thermoplastic/light, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "cSR" = ( /obj/structure/chair{ dir = 1 @@ -7808,14 +7832,30 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/general, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/port/aft) +"cZA" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt, +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, +/turf/open/floor/iron, +/area/station/security/prison/garden) +"cZC" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/security/tram) "cZL" = ( /obj/item/reagent_containers/cup/bucket, /obj/item/mop, /obj/structure/sink/kitchen/directional/east, /obj/machinery/airalarm/directional/south, /obj/machinery/button/door/directional/west{ - pixel_y = 8; - id = "custodialshutters" + id = "custodialshutters"; + pixel_y = 8 }, /turf/open/floor/iron/white/small, /area/station/service/janitor) @@ -7886,12 +7926,6 @@ "dbF" = ( /turf/open/floor/plating/rust, /area/station/ai_monitored/turret_protected/aisat/maint) -"dbO" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/effect/spawner/random/maintenance, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "dbR" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -8004,6 +8038,12 @@ }, /turf/open/floor/iron/dark, /area/station/medical/pharmacy) +"ddq" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/spawner/random/maintenance, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "ddy" = ( /obj/effect/spawner/structure/window, /turf/open/floor/plating, @@ -8197,10 +8237,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/department/engine) -"dhX" = ( -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/tram, -/area/station/security/tram) "dim" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -8463,6 +8499,15 @@ /obj/structure/tank_holder/extinguisher/advanced, /turf/open/floor/iron, /area/station/engineering/atmos) +"dlx" = ( +/obj/structure/flora/bush/flowers_br/style_random, +/obj/structure/flora/rock/pile/style_random, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/turf_decal/siding/wideplating{ + dir = 4 + }, +/turf/open/misc/sandy_dirt, +/area/station/security/tram) "dlz" = ( /obj/machinery/light/small/directional/east, /obj/structure/closet/secure_closet/medical3, @@ -8502,6 +8547,11 @@ }, /turf/open/floor/plating, /area/station/maintenance/disposal/incinerator) +"dmG" = ( +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "dmT" = ( /obj/machinery/camera/directional/north{ c_tag = "Xenobiology - Cell 2"; @@ -8692,6 +8742,12 @@ /obj/structure/firelock_frame, /turf/open/floor/iron/dark, /area/station/maintenance/department/engine/atmos) +"dpR" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/turf/open/floor/tram, +/area/station/security/tram) "dqj" = ( /obj/effect/turf_decal/stripes/red/line, /obj/effect/turf_decal/stripes/red/line{ @@ -8782,6 +8838,14 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/security/lockers) +"dsU" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 6 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "dtj" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -9070,14 +9134,6 @@ /obj/machinery/portable_atmospherics/canister, /turf/open/floor/plating, /area/station/engineering/atmos/storage/gas) -"dyn" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/security/tram) "dyp" = ( /obj/effect/turf_decal/sand/plating, /obj/effect/decal/cleanable/dirt, @@ -9308,14 +9364,6 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/carpet/royalblack, /area/station/commons/dorms) -"dBF" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 9 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "dBH" = ( /turf/open/floor/iron/white/corner{ dir = 1 @@ -9370,6 +9418,14 @@ dir = 1 }, /area/station/service/library) +"dCs" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 9 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "dCH" = ( /obj/structure/table, /obj/item/storage/box/lights/mixed{ @@ -9472,6 +9528,12 @@ /obj/machinery/vending/cigarette, /turf/open/floor/iron/kitchen/small, /area/station/security/breakroom) +"dEF" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/turf/open/floor/tram, +/area/station/security/tram) "dER" = ( /obj/machinery/power/emitter, /obj/effect/turf_decal/stripes/white/line{ @@ -9535,6 +9597,12 @@ }, /turf/open/floor/iron/dark, /area/station/medical/chemistry) +"dHn" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 10 + }, +/turf/open/floor/tram, +/area/station/security/tram) "dHC" = ( /obj/structure/cable, /obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, @@ -9671,6 +9739,11 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron, /area/station/maintenance/department/engine/atmos) +"dJz" = ( +/obj/structure/chair/stool/directional/west, +/mob/living/basic/trooper/russian/ranged/lootless, +/turf/open/floor/carpet/orange, +/area/station/service/abandoned_gambling_den) "dJN" = ( /obj/machinery/griddle, /turf/open/floor/plating, @@ -9762,13 +9835,6 @@ dir = 1 }, /area/station/maintenance/disposal/incinerator) -"dLd" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 10 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "dLf" = ( /obj/effect/turf_decal/tile/yellow/opposingcorners, /obj/structure/table/reinforced/titaniumglass, @@ -10158,6 +10224,14 @@ /obj/machinery/meter, /turf/open/floor/plating, /area/station/engineering/atmos) +"dSV" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "dTa" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -10652,6 +10726,13 @@ }, /turf/open/floor/iron/small, /area/station/security/prison/shower) +"dZT" = ( +/obj/machinery/button/transport/tram/directional/south{ + id = 2; + specific_transport_id = "bird_2" + }, +/turf/open/floor/iron, +/area/station/maintenance/department/medical/central) "dZZ" = ( /obj/structure/cable/layer3, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, @@ -10852,10 +10933,6 @@ /obj/machinery/status_display/ai/directional/north, /turf/open/floor/iron/smooth, /area/station/ai_monitored/turret_protected/aisat_interior) -"edW" = ( -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "eeb" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -12288,6 +12365,13 @@ /obj/machinery/status_display/evac/directional/east, /turf/open/floor/circuit/red, /area/station/ai_monitored/turret_protected/ai) +"eDt" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/security/tram) "eDy" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -12357,11 +12441,6 @@ /obj/item/stamp/head/hos, /turf/open/floor/carpet/red, /area/station/command/heads_quarters/hos) -"eEl" = ( -/obj/structure/transport/linear/tram, -/obj/structure/thermoplastic/light, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "eEq" = ( /obj/effect/turf_decal/bot_white, /obj/effect/turf_decal/stripes/corner, @@ -12383,10 +12462,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/station/ai_monitored/turret_protected/aisat/equipment) -"eFi" = ( -/obj/structure/frame/machine, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "eFk" = ( /obj/structure/cable/layer3, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -13039,6 +13114,11 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark, /area/station/engineering/atmos) +"eQC" = ( +/obj/effect/spawner/random/maintenance, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/security/tram) "eQJ" = ( /obj/structure/cable, /turf/open/floor/iron/stairs{ @@ -13193,14 +13273,6 @@ /obj/effect/landmark/start/roboticist, /turf/open/floor/iron/grimy, /area/station/science/cubicle) -"eTq" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/security/tram) "eTr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -13319,14 +13391,6 @@ /obj/machinery/light/warm/directional/east, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/port/aft) -"eVe" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 6 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "eVu" = ( /obj/effect/mapping_helpers/broken_floor, /obj/structure/chair/sofa/bench{ @@ -13515,9 +13579,6 @@ /obj/machinery/portable_atmospherics/pump, /turf/open/floor/iron/dark, /area/station/engineering/atmos) -"fay" = ( -/turf/open/floor/tram, -/area/station/security/tram) "faB" = ( /obj/structure/table/wood, /obj/item/book/bible, @@ -13627,15 +13688,6 @@ }, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/rd) -"fbX" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/fluff/tram_rail/end{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/port/aft) "fca" = ( /obj/structure/flora/bush/lavendergrass/style_random, /obj/structure/flora/bush/flowers_br/style_random, @@ -14222,15 +14274,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/fore) -"fos" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/fluff/tram_rail/end{ - dir = 8 - }, -/turf/open/floor/plating, -/area/station/maintenance/port/aft) "fov" = ( /obj/effect/turf_decal/tile/dark_red/opposingcorners, /obj/machinery/vending/security, @@ -14350,15 +14393,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) -"fqT" = ( -/obj/effect/turf_decal/stripes/white/corner{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/corner{ - dir = 8 - }, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "frf" = ( /obj/structure/table/glass, /obj/item/defibrillator/loaded{ @@ -14402,13 +14436,6 @@ /obj/machinery/door/firedoor, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/command/heads_quarters/ce) -"frB" = ( -/obj/machinery/button/transport/tram/directional/south{ - specific_transport_id = "bird_2"; - id = 2 - }, -/turf/open/floor/iron, -/area/station/maintenance/department/medical/central) "frI" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/tile/neutral{ @@ -14604,12 +14631,6 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/stone, /area/station/command/heads_quarters/hos) -"fuk" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "fun" = ( /obj/structure/cable/layer3, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -14839,10 +14860,6 @@ /obj/machinery/coffeemaker{ pixel_y = 12 }, -/obj/item/reagent_containers/cup/coffeepot{ - pixel_x = 3; - pixel_y = -5 - }, /turf/open/floor/iron/kitchen/small, /area/station/security/breakroom) "fyr" = ( @@ -16165,6 +16182,12 @@ /obj/effect/mapping_helpers/airlock/access/all/command/minisat, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/ai_monitored/turret_protected/aisat_interior) +"fTd" = ( +/obj/structure/transport/linear/tram, +/obj/effect/landmark/transport/transport_id/birdshot/line_1, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/security/tram) "fTe" = ( /turf/closed/wall/r_wall, /area/station/ai_monitored/turret_protected/aisat_interior) @@ -16324,12 +16347,6 @@ /obj/machinery/camera/directional/east, /turf/open/floor/iron, /area/station/service/hydroponics) -"fWh" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "fWr" = ( /obj/structure/closet/crate, /obj/structure/barricade/wooden/crude, @@ -16403,6 +16420,14 @@ }, /turf/open/floor/iron/smooth, /area/station/ai_monitored/turret_protected/aisat/foyer) +"fXD" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "fXJ" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -16750,8 +16775,12 @@ /obj/machinery/atmospherics/pipe/smart/simple/purple/visible, /obj/machinery/airalarm/directional/east, /obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnancefreezer" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, /turf/open/floor/iron/dark, -/area/station/science/ordnance/freezerchamber) +/area/station/science/ordnance) "gfE" = ( /obj/effect/turf_decal/siding/red{ dir = 8 @@ -16785,6 +16814,13 @@ /obj/effect/turf_decal/sand/plating, /turf/open/floor/plating/airless, /area/space/nearstation) +"ggh" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/security/tram) "ggi" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -17002,12 +17038,6 @@ /obj/structure/lattice, /turf/open/space/basic, /area/space/nearstation) -"gjr" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/effect/spawner/random/structure/girder, -/obj/machinery/light/small/directional/south, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "gjL" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/heat_exchanging/junction{ @@ -17032,6 +17062,15 @@ }, /turf/open/floor/engine/vacuum, /area/station/engineering/atmos) +"gkq" = ( +/obj/structure/transport/linear/tram, +/obj/effect/turf_decal/stripes/white/corner, +/obj/effect/turf_decal/stripes/white/corner{ + dir = 4 + }, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "gkw" = ( /obj/structure/cable, /obj/machinery/light_switch/directional/west, @@ -17062,12 +17101,6 @@ /obj/machinery/power/apc/auto_name/directional/west, /turf/open/floor/iron, /area/station/hallway/primary/fore) -"gkO" = ( -/obj/structure/rack, -/obj/structure/transport/linear/tram, -/obj/structure/thermoplastic, -/turf/open/floor/tram, -/area/station/security/tram) "glb" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/brown/full, @@ -17238,6 +17271,15 @@ /obj/machinery/keycard_auth/directional/south, /turf/open/floor/iron, /area/station/command/heads_quarters/ce) +"gow" = ( +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) +"goB" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 6 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "goE" = ( /obj/structure/disposalpipe/trunk{ dir = 4 @@ -17621,12 +17663,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/orange/hidden/layer1, /turf/open/floor/iron/dark, /area/station/engineering/atmos) -"gwh" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "gwo" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/simple/purple/visible{ @@ -18176,6 +18212,14 @@ /obj/machinery/camera/directional/north, /turf/open/floor/iron, /area/station/hallway/secondary/dock) +"gFZ" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 6 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "gGc" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -18896,6 +18940,17 @@ /obj/effect/gibspawner/human, /turf/open/floor/plating, /area/station/maintenance/starboard/greater) +"gSs" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 10 + }, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) +"gSz" = ( +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "gSD" = ( /obj/machinery/mass_driver/chapelgun{ dir = 8 @@ -18957,20 +19012,6 @@ }, /turf/open/floor/carpet/executive, /area/station/command/meeting_room) -"gTk" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/transport/linear/tram, -/obj/structure/thermoplastic/light, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) -"gTC" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 6 - }, -/turf/open/floor/tram, -/area/station/security/tram) "gTH" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -19208,14 +19249,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/hallway/secondary/entry) -"gXd" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 9 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/security/tram) "gXf" = ( /obj/effect/turf_decal/sand/plating, /obj/effect/decal/cleanable/dirt, @@ -19735,6 +19768,34 @@ dir = 1 }, /area/station/command/gateway) +"heT" = ( +/obj/structure/table, +/obj/machinery/airalarm/directional/west, +/obj/item/pipe_dispenser{ + pixel_x = 3; + pixel_y = -1 + }, +/obj/item/assembly/timer{ + pixel_x = -3; + pixel_y = 13 + }, +/obj/item/transfer_valve{ + pixel_x = 10; + pixel_y = 21 + }, +/obj/item/transfer_valve{ + pixel_x = 7; + pixel_y = 19 + }, +/obj/item/transfer_valve{ + pixel_x = 4; + pixel_y = 17 + }, +/obj/item/pipe_dispenser{ + pixel_y = 4 + }, +/turf/open/floor/iron, +/area/station/science/ordnance/testlab) "hfc" = ( /obj/structure/rack, /obj/effect/spawner/random/maintenance/three, @@ -19957,8 +20018,8 @@ pixel_y = 11 }, /obj/item/mod/module/signlang_radio{ - pixel_y = 2; - pixel_x = -2 + pixel_x = -2; + pixel_y = 2 }, /turf/open/floor/iron/small, /area/station/security/office) @@ -20152,6 +20213,14 @@ /obj/structure/sign/poster/official/random/directional/west, /turf/open/floor/iron/smooth, /area/station/commons/storage/tools) +"hmf" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/spawner/random/maintenance, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/security/tram) "hmg" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -20189,10 +20258,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/white/small, /area/station/science/ordnance/storage) -"hmB" = ( -/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/maint_right, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "hmQ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/table, @@ -20936,12 +21001,6 @@ "hzm" = ( /turf/closed/wall/rust, /area/station/cargo/miningoffice) -"hzI" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/firealarm/directional/east, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) "hzK" = ( /obj/structure/disposalpipe/segment, /turf/open/floor/plating, @@ -21776,6 +21835,11 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"hPq" = ( +/obj/effect/turf_decal/siding/wood, +/mob/living/basic/trooper/russian/ranged/lootless, +/turf/open/floor/wood, +/area/station/service/abandoned_gambling_den) "hPs" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/airalarm/directional/south, @@ -21972,15 +22036,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/showroomfloor, /area/station/commons/toilet/restrooms) -"hUT" = ( -/obj/structure/flora/bush/flowers_br/style_random, -/obj/structure/flora/rock/pile/style_random, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/siding/wideplating{ - dir = 4 - }, -/turf/open/misc/sandy_dirt, -/area/station/security/tram) "hVb" = ( /obj/machinery/plate_press, /obj/effect/turf_decal/stripes/line, @@ -22189,12 +22244,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/engine, /area/station/engineering/gravity_generator) -"hYz" = ( -/obj/structure/transport/linear/tram, -/obj/machinery/transport/tram_controller, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/security/tram) "hYC" = ( /turf/closed/wall, /area/station/engineering/atmos) @@ -22336,17 +22385,6 @@ /obj/machinery/holopad, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/rd) -"iaZ" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/transport/linear/tram, -/obj/structure/thermoplastic/light, -/obj/machinery/door/airlock/tram{ - transport_linked_id = "bird_2" - }, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "ibe" = ( /obj/effect/turf_decal/bot_white, /obj/structure/closet/crate/freezer, @@ -22643,6 +22681,13 @@ }, /turf/open/floor/plating, /area/station/maintenance/fore/lesser) +"igD" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "ihc" = ( /obj/structure/cable, /obj/machinery/door/airlock/command/glass{ @@ -23065,10 +23110,6 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/command/meeting_room) -"ipn" = ( -/obj/effect/turf_decal/stripes/white/line, -/turf/open/floor/tram, -/area/station/security/tram) "ips" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -23244,18 +23285,6 @@ /obj/effect/turf_decal/tile/blue/opposingcorners, /turf/open/floor/iron/dark/textured, /area/station/command/heads_quarters/hop) -"isf" = ( -/obj/effect/turf_decal/stripes/white/corner{ - dir = 4 - }, -/obj/structure/transport/linear/tram, -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/structure/fluff/tram_rail/floor, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "isi" = ( /obj/structure/table, /obj/effect/turf_decal/siding/thinplating_new{ @@ -23309,11 +23338,6 @@ dir = 1 }, /area/station/command/gateway) -"isW" = ( -/obj/effect/turf_decal/siding/wood, -/mob/living/basic/trooper/russian/ranged/lootless, -/turf/open/floor/wood, -/area/station/service/abandoned_gambling_den) "isY" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -23324,14 +23348,6 @@ "itb" = ( /turf/closed/wall/r_wall/rust, /area/station/ai_monitored/turret_protected/aisat/maint) -"itv" = ( -/obj/structure/transport/linear/tram, -/obj/structure/chair{ - dir = 1 - }, -/obj/structure/thermoplastic, -/turf/open/floor/tram, -/area/station/security/tram) "itw" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -23416,14 +23432,6 @@ /obj/machinery/power/apc/worn_out/directional/east, /turf/open/floor/plating, /area/station/maintenance/hallway/abandoned_command) -"ius" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/security/tram) "iut" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -23658,11 +23666,6 @@ }, /turf/open/floor/plating, /area/station/security/brig/entrance) -"iyk" = ( -/obj/effect/spawner/random/maintenance, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/security/tram) "iyq" = ( /obj/machinery/atmospherics/pipe/smart/simple/green/hidden{ dir = 9 @@ -23807,13 +23810,6 @@ /obj/structure/cable, /turf/open/floor/wood/tile, /area/station/maintenance/port/lesser) -"iBV" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/line, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "iBZ" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -24273,11 +24269,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/white/small, /area/station/security/warden) -"iLk" = ( -/obj/structure/chair/stool/directional/west, -/mob/living/basic/trooper/russian/ranged/lootless, -/turf/open/floor/carpet/orange, -/area/station/service/abandoned_gambling_den) "iLp" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -24443,6 +24434,13 @@ /obj/effect/mapping_helpers/airlock/abandoned, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"iNO" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 6 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/security/tram) "iNV" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -24607,12 +24605,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark/small, /area/station/service/chapel/storage) -"iRp" = ( -/obj/structure/transport/linear/tram, -/obj/effect/landmark/transport/transport_id/birdshot/line_1, -/obj/structure/thermoplastic, -/turf/open/floor/tram, -/area/station/security/tram) "iRv" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, @@ -24812,6 +24804,19 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron, /area/station/cargo/storage) +"iVq" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 10 + }, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/security/tram) +"iVu" = ( +/obj/structure/transport/linear/tram, +/obj/machinery/transport/tram_controller, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "iVx" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -25234,6 +25239,12 @@ }, /turf/open/floor/wood/parquet, /area/station/command/heads_quarters/cmo) +"jbt" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "jbV" = ( /obj/machinery/photocopier, /turf/open/floor/iron/dark, @@ -25418,13 +25429,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/fore/greater) -"jfX" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 6 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/security/tram) "jfZ" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -26188,13 +26192,11 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"jwC" = ( -/obj/structure/transport/linear/tram, -/obj/effect/landmark/transport/nav_beacon/tram/nav/birdshot/maint, -/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/maint_left, -/obj/structure/thermoplastic/light, +"jwZ" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/structure/frame/machine, /turf/open/floor/tram, -/area/station/maintenance/port/aft) +/area/station/security/tram) "jxd" = ( /obj/machinery/atmospherics/pipe/smart/simple/purple/visible/layer2{ dir = 9 @@ -26389,6 +26391,17 @@ }, /turf/open/floor/iron/kitchen/small, /area/station/hallway/secondary/service) +"jzg" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/obj/machinery/door/airlock/tram{ + transport_linked_id = "bird_2" + }, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "jzo" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -26719,13 +26732,6 @@ }, /turf/open/floor/iron, /area/station/cargo/office) -"jEX" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/machinery/light/cold/directional/west, -/turf/open/floor/tram, -/area/station/security/tram) "jEZ" = ( /obj/structure/hedge, /obj/effect/decal/cleanable/dirt, @@ -26917,6 +26923,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/cargo/sorting) +"jHI" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/security/tram) "jHU" = ( /obj/structure/chair/sofa/bench/left{ dir = 8 @@ -27622,14 +27635,6 @@ /obj/item/instrument/harmonica, /turf/open/floor/iron, /area/station/security/prison/rec) -"jUN" = ( -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/obj/machinery/computer/tram_controls{ - specific_transport_id = "bird_1" - }, -/turf/open/floor/tram, -/area/station/security/tram) "jVe" = ( /obj/structure/cable, /turf/open/floor/iron/smooth, @@ -27652,17 +27657,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/hallway/secondary/recreation) -"jVX" = ( -/obj/structure/transport/linear/tram, -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/structure/fluff/tram_rail/floor{ - dir = 1 - }, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "jWd" = ( /obj/structure/cable, /obj/item/kirbyplants/random/fullysynthetic, @@ -27824,12 +27818,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/starboard/greater) -"jYd" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 - }, -/turf/open/floor/tram, -/area/station/security/tram) "jYr" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/machinery/mecha_part_fabricator{ @@ -28020,6 +28008,14 @@ /obj/structure/broken_flooring/corner/directional/south, /turf/open/floor/plating, /area/station/maintenance/hallway/abandoned_recreation) +"kbc" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "kbE" = ( /obj/effect/decal/cleanable/blood/gibs/body, /obj/machinery/light/small/broken/directional/north, @@ -28143,13 +28139,6 @@ }, /turf/open/floor/iron, /area/station/cargo/storage) -"kef" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/security/tram) "kel" = ( /obj/machinery/light/cold/directional/south, /obj/machinery/modular_computer/preset/id{ @@ -28157,6 +28146,15 @@ }, /turf/open/floor/wood/parquet, /area/station/command/heads_quarters/cmo) +"keq" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/fluff/tram_rail/end{ + dir = 8 + }, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "ket" = ( /turf/open/floor/iron, /area/station/security/prison/work) @@ -28273,6 +28271,18 @@ /obj/machinery/newscaster/directional/east, /turf/open/floor/wood, /area/station/service/chapel/funeral) +"khl" = ( +/obj/effect/turf_decal/stripes/white/line, +/turf/open/floor/tram, +/area/station/security/tram) +"khp" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 9 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "khD" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/reagent_dispensers/watertank, @@ -28305,6 +28315,12 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/security/execution/transfer) +"khQ" = ( +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "khS" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -28390,20 +28406,6 @@ /obj/effect/spawner/random/structure/grille, /turf/open/floor/plating, /area/station/maintenance/fore/lesser) -"kjn" = ( -/obj/effect/turf_decal/stripes/corner, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/obj/structure/holosign/barrier/atmos/tram, -/turf/open/floor/tram, -/area/station/security/tram) "kjw" = ( /obj/effect/turf_decal/tile/blue, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -28555,6 +28557,11 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/carpet/orange, /area/station/service/abandoned_gambling_den) +"klY" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "kmb" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -28614,6 +28621,12 @@ }, /turf/open/floor/plating, /area/station/cargo/storage) +"kms" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/firealarm/directional/east, +/turf/open/floor/iron, +/area/station/hallway/secondary/entry) "kmC" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -28840,12 +28853,6 @@ "kqX" = ( /turf/closed/wall, /area/station/ai_monitored/aisat/exterior) -"kqZ" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 - }, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "krc" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -28943,6 +28950,13 @@ /obj/machinery/camera/autoname/directional/north, /turf/open/floor/iron, /area/station/hallway/secondary/spacebridge) +"ksv" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "ksx" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -28981,13 +28995,6 @@ }, /turf/open/floor/catwalk_floor/iron, /area/station/engineering/gravity_generator) -"ksL" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "ksN" = ( /obj/structure/transit_tube/station/dispenser, /obj/effect/decal/cleanable/dirt, @@ -29100,11 +29107,6 @@ /obj/effect/turf_decal/trimline/neutral/line, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) -"kvb" = ( -/obj/structure/transport/linear/tram, -/obj/structure/thermoplastic, -/turf/open/floor/tram, -/area/station/security/tram) "kvf" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, @@ -29236,10 +29238,6 @@ /obj/structure/window/spawner/directional/east, /turf/open/floor/plating/rust, /area/station/maintenance/fore/lesser) -"kye" = ( -/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/prison_wing, -/turf/open/floor/tram, -/area/station/security/tram) "kyr" = ( /obj/structure/window/reinforced/spawner/directional/south, /obj/machinery/airalarm/directional/west, @@ -29276,13 +29274,6 @@ /obj/effect/turf_decal/trimline/neutral/line, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) -"kyS" = ( -/obj/effect/turf_decal/stripes/white/corner, -/obj/effect/turf_decal/stripes/white/line, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/security/tram) "kyT" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/event_spawn, @@ -29933,13 +29924,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark/side, /area/station/science/xenobiology) -"kKy" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/security/tram) "kKB" = ( /obj/structure/window/spawner/directional/west, /obj/structure/window/spawner/directional/south, @@ -30000,12 +29984,6 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron/showroomfloor, /area/station/commons/toilet/restrooms) -"kLG" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/turf/open/floor/tram, -/area/station/security/tram) "kLS" = ( /turf/open/floor/iron/stairs{ dir = 1 @@ -30053,15 +30031,6 @@ /obj/structure/closet/emcloset, /turf/open/floor/iron/small, /area/station/maintenance/department/medical/central) -"kNA" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/turf/open/floor/tram, -/area/station/security/tram) "kND" = ( /turf/closed/wall/r_wall, /area/station/security/prison) @@ -30304,14 +30273,6 @@ /obj/machinery/holopad, /turf/open/floor/wood, /area/station/command/heads_quarters/qm) -"kSo" = ( -/obj/structure/chair{ - dir = 1 - }, -/obj/structure/transport/linear/tram, -/obj/structure/thermoplastic, -/turf/open/floor/tram, -/area/station/security/tram) "kSr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -30768,6 +30729,14 @@ /obj/effect/landmark/start/bitrunner, /turf/open/floor/iron/dark/smooth_half, /area/station/bitrunning/den) +"lbG" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "lbM" = ( /obj/structure/chair/sofa/bench/right{ dir = 1 @@ -31383,12 +31352,6 @@ /obj/structure/window/reinforced/spawner/directional/west, /turf/open/floor/iron, /area/station/maintenance/fore/greater) -"liU" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 6 - }, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "ljk" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -31817,6 +31780,10 @@ }, /turf/open/floor/wood/parquet, /area/station/service/library) +"lqL" = ( +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/prison_wing, +/turf/open/floor/tram, +/area/station/security/tram) "lrh" = ( /obj/structure/cable, /obj/effect/spawner/random/trash, @@ -32025,18 +31992,6 @@ }, /turf/open/floor/wood/parquet, /area/station/service/greenroom) -"lvM" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/airlock/public/glass{ - name = "Prison Garden" - }, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/textured_half{ - dir = 8 - }, -/area/station/security/prison/garden) "lvS" = ( /obj/machinery/porta_turret/ai{ dir = 4 @@ -33518,6 +33473,12 @@ }, /turf/open/floor/iron/dark, /area/station/cargo/storage) +"lTU" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 10 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "lUo" = ( /turf/open/floor/iron, /area/station/science/lobby) @@ -34128,6 +34089,10 @@ /obj/effect/landmark/start/chief_medical_officer, /turf/open/floor/wood/parquet, /area/station/command/heads_quarters/cmo) +"mdr" = ( +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "mdt" = ( /turf/closed/wall/r_wall, /area/station/science/robotics/mechbay) @@ -34553,25 +34518,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/science/xenobiology) -"mmf" = ( -/obj/structure/table, -/obj/effect/mapping_helpers/broken_floor, -/obj/item/assembly/timer{ - pixel_x = -3; - pixel_y = 9 - }, -/obj/item/assembly/timer{ - pixel_y = 7 - }, -/obj/machinery/light_switch/directional/south, -/obj/structure/extinguisher_cabinet/directional/west, -/obj/item/holosign_creator/atmos, -/obj/item/holosign_creator/atmos{ - pixel_x = 3; - pixel_y = -3 - }, -/turf/open/floor/iron, -/area/station/science/ordnance/testlab) "mmi" = ( /obj/structure/chair/sofa/bench/left{ dir = 4 @@ -34636,6 +34582,17 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/security/execution/transfer) +"mnb" = ( +/obj/effect/turf_decal/stripes/white/corner{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "mnc" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -35529,6 +35486,13 @@ /obj/machinery/light_switch/directional/south, /turf/open/floor/iron/white, /area/station/science/cytology) +"mET" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "mEU" = ( /obj/machinery/light/small/directional/east, /turf/open/floor/iron/showroomfloor, @@ -35627,13 +35591,6 @@ /obj/structure/sink/directional/west, /turf/open/floor/iron/white/small, /area/station/medical/storage) -"mGQ" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/frame/machine, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "mGT" = ( /obj/structure/cable, /obj/machinery/door/airlock{ @@ -35682,15 +35639,6 @@ /obj/effect/landmark/start/virologist, /turf/open/floor/iron/white/small, /area/station/medical/virology) -"mId" = ( -/obj/structure/window/reinforced/spawner/directional/west, -/obj/machinery/button/transport/tram/directional/north{ - specific_transport_id = "bird_1"; - id = 1 - }, -/obj/machinery/transport/destination_sign/indicator/directional/north, -/turf/open/floor/noslip, -/area/station/security/tram) "mIg" = ( /obj/machinery/light/small/directional/west, /turf/open/floor/catwalk_floor/iron_dark, @@ -36057,6 +36005,14 @@ /obj/effect/mapping_helpers/airlock/access/any/science/maintenance, /turf/open/floor/plating, /area/station/maintenance/aft) +"mNG" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/button/transport/tram/directional/south{ + id = 1; + specific_transport_id = "bird_2" + }, +/turf/open/floor/iron, +/area/station/maintenance/port/aft) "mNN" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/button/door/directional/east{ @@ -36512,6 +36468,13 @@ /obj/machinery/status_display/evac/directional/north, /turf/open/floor/iron/dark/small, /area/station/medical/storage) +"mXD" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/security/tram) "mXT" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -36805,6 +36768,12 @@ /obj/structure/cable, /turf/open/floor/iron/dark/smooth_large, /area/station/ai_monitored/turret_protected/ai_upload) +"ndp" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "ndq" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -36815,13 +36784,6 @@ }, /turf/open/floor/catwalk_floor/iron_dark, /area/station/maintenance/central/greater) -"ndA" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/security/tram) "ndM" = ( /obj/structure/tank_dispenser/oxygen, /turf/open/floor/iron, @@ -37002,6 +36964,12 @@ }, /turf/open/floor/iron/dark, /area/station/security/office) +"nhx" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "nhB" = ( /obj/effect/mapping_helpers/broken_floor, /obj/effect/decal/cleanable/dirt, @@ -38254,15 +38222,6 @@ /turf/open/floor/plating, /area/station/maintenance/starboard/greater) "nEl" = ( -/obj/machinery/computer/quantum_console{ - dir = 4 - }, -/obj/machinery/computer/quantum_console{ - dir = 4 - }, -/obj/machinery/computer/quantum_console{ - dir = 4 - }, /obj/machinery/computer/quantum_console{ dir = 4 }, @@ -38603,13 +38562,6 @@ /obj/structure/cable, /turf/open/floor/iron/small, /area/station/maintenance/solars/starboard/fore) -"nJm" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/spawner/random/maintenance, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "nJx" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -39385,6 +39337,16 @@ "nZx" = ( /turf/closed/mineral/random/stationside, /area/station/ai_monitored/turret_protected/ai) +"nZz" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/structure/holosign/barrier/atmos/tram, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "nZM" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -39436,14 +39398,6 @@ /obj/machinery/camera/autoname/directional/west, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai_upload_foyer) -"oaE" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 6 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/security/tram) "oaV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -39499,13 +39453,6 @@ "ocb" = ( /turf/open/floor/iron/white/small, /area/station/science/cubicle) -"ocg" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "ocs" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -40808,12 +40755,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/primary/port) -"oBo" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) "oBA" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -40932,6 +40873,20 @@ }, /turf/open/floor/iron/white/small, /area/station/science/server) +"oDY" = ( +/obj/effect/turf_decal/stripes/corner, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/obj/structure/holosign/barrier/atmos/tram, +/turf/open/floor/tram, +/area/station/security/tram) "oEi" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/decal/cleanable/dirt, @@ -40980,6 +40935,7 @@ /obj/effect/turf_decal/stripes/white/line{ dir = 4 }, +/obj/machinery/air_sensor/engine_chamber, /turf/open/floor/engine, /area/station/engineering/supermatter) "oFf" = ( @@ -41093,15 +41049,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/starboard/greater) -"oGS" = ( -/obj/structure/transport/linear/tram, -/obj/effect/turf_decal/stripes/white/corner, -/obj/effect/turf_decal/stripes/white/corner{ - dir = 4 - }, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "oHa" = ( /obj/structure/table, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -41138,6 +41085,13 @@ /obj/structure/table, /turf/open/floor/iron, /area/station/commons) +"oIK" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/frame/machine, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "oIP" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -41194,6 +41148,13 @@ /obj/machinery/camera/autoname/directional/west, /turf/open/floor/iron/dark/small, /area/station/medical/morgue) +"oJA" = ( +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/solo, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "oJE" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -41403,17 +41364,6 @@ /obj/structure/alien/weeds, /turf/open/floor/iron, /area/station/maintenance/starboard/greater) -"oNM" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/transport/linear/tram, -/obj/machinery/transport/tram_controller{ - configured_transport_id = "bird_2" - }, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "oNX" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -41491,6 +41441,17 @@ /obj/machinery/portable_atmospherics/canister, /turf/open/floor/iron, /area/station/maintenance/port/fore) +"oOL" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/machinery/transport/tram_controller{ + configured_transport_id = "bird_2" + }, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "oPc" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/machinery/computer/upload/borg{ @@ -41747,6 +41708,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port/greater) +"oTI" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "oTL" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating/rust, @@ -41846,18 +41814,6 @@ /obj/structure/broken_flooring/singular/directional/east, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"oVE" = ( -/obj/structure/flora/bush/large/style_random{ - pixel_x = -18; - pixel_y = -9 - }, -/obj/structure/flora/bush/flowers_yw/style_random, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/siding/wideplating{ - dir = 4 - }, -/turf/open/misc/sandy_dirt, -/area/station/security/tram) "oVK" = ( /obj/structure/chair{ pixel_y = -2 @@ -41924,17 +41880,6 @@ /obj/machinery/duct, /turf/open/floor/plating, /area/station/maintenance/central/greater) -"oXh" = ( -/obj/structure/transport/linear/tram, -/obj/structure/fluff/tram_rail/floor{ - dir = 1 - }, -/obj/structure/thermoplastic, -/obj/structure/chair/sofa/bench/tram/right{ - dir = 1 - }, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "oXs" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/closet/emcloset, @@ -42109,6 +42054,14 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/primary/port) +"paI" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "paL" = ( /obj/structure/fireplace, /obj/effect/turf_decal/siding/wood/end, @@ -42223,6 +42176,12 @@ /obj/structure/broken_flooring/corner/directional/south, /turf/open/floor/plating, /area/station/hallway/secondary/recreation) +"pdf" = ( +/obj/structure/transport/linear/tram, +/obj/effect/landmark/transport/transport_id/birdshot/line_2, +/obj/structure/thermoplastic/light, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "pds" = ( /obj/structure/cable, /obj/machinery/holopad, @@ -42355,6 +42314,15 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/iron/small, /area/station/maintenance/port/lesser) +"pfd" = ( +/obj/effect/turf_decal/stripes/white/corner{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/corner{ + dir = 8 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "pfh" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/alien/weeds, @@ -42409,16 +42377,6 @@ dir = 8 }, /area/station/service/bar/backroom) -"pfY" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/structure/holosign/barrier/atmos/tram, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "pgh" = ( /obj/effect/turf_decal/tile/red/fourcorners, /obj/structure/table/reinforced/titaniumglass, @@ -42600,6 +42558,12 @@ /obj/structure/broken_flooring/singular/directional/south, /turf/open/floor/iron, /area/station/maintenance/starboard/aft) +"pje" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/spawner/random/structure/girder, +/obj/machinery/light/small/directional/south, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "pjn" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/machinery/dna_scannernew, @@ -43023,9 +42987,6 @@ /obj/structure/window/reinforced/spawner/directional/east, /turf/open/space/basic, /area/space) -"pqf" = ( -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "pqm" = ( /turf/closed/wall/r_wall, /area/station/engineering/storage/tcomms) @@ -43103,11 +43064,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/cafeteria, /area/station/service/kitchen) -"prT" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/effect/spawner/random/maintenance, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "prW" = ( /obj/effect/turf_decal/stripes/red/line{ dir = 8 @@ -43420,13 +43376,6 @@ }, /turf/open/floor/iron/white/side, /area/station/science/research) -"pwG" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/line, -/turf/open/floor/plating/airless, -/area/space/nearstation) "pwJ" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -43459,15 +43408,6 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron, /area/station/service/hydroponics) -"pxs" = ( -/obj/structure/transport/linear/tram, -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/structure/fluff/tram_rail/floor, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "pxw" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -43616,6 +43556,13 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/security/checkpoint/customs/auxiliary) +"pzN" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "pzR" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -43818,6 +43765,12 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/recreation) +"pCC" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/tram, +/area/station/security/tram) "pCF" = ( /obj/machinery/door/window/brigdoor/right/directional/east{ id = "Cell 2"; @@ -43876,15 +43829,6 @@ }, /turf/open/floor/wood/tile, /area/station/service/lawoffice) -"pDG" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/frame/computer{ - dir = 1 - }, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "pDQ" = ( /obj/structure/cable, /obj/structure/table/glass, @@ -44307,6 +44251,13 @@ /obj/effect/turf_decal/delivery/red, /turf/open/floor/iron/white/small, /area/station/medical/medbay/central) +"pKp" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 6 + }, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "pKR" = ( /obj/effect/turf_decal/tile/blue/anticorner/contrasted{ dir = 4 @@ -44465,13 +44416,6 @@ }, /turf/open/floor/wood/tile, /area/station/command/corporate_showroom) -"pNm" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "pNy" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -44499,17 +44443,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/white/small, /area/station/science/lab) -"pNT" = ( -/obj/structure/transport/linear/tram, -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/structure/fluff/tram_rail/floor{ - dir = 1 - }, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "pOb" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -45126,6 +45059,14 @@ }, /turf/open/floor/iron/dark/small, /area/station/science/xenobiology) +"pXh" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/spawner/random/maintenance, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "pXo" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -45647,17 +45588,6 @@ }, /turf/open/misc/sandy_dirt, /area/station/security/tram) -"qfw" = ( -/obj/structure/transport/linear/tram, -/obj/structure/fluff/tram_rail/floor{ - dir = 1 - }, -/obj/structure/thermoplastic, -/obj/structure/chair/sofa/bench/tram/left{ - dir = 1 - }, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "qfz" = ( /obj/item/kirbyplants/organic/applebush, /obj/machinery/light/small/directional/south, @@ -45939,34 +45869,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/fore) -"qiH" = ( -/obj/structure/table, -/obj/machinery/airalarm/directional/west, -/obj/item/pipe_dispenser{ - pixel_x = 3; - pixel_y = -1 - }, -/obj/item/assembly/timer{ - pixel_x = -3; - pixel_y = 13 - }, -/obj/item/transfer_valve{ - pixel_x = 10; - pixel_y = 21 - }, -/obj/item/transfer_valve{ - pixel_x = 7; - pixel_y = 19 - }, -/obj/item/transfer_valve{ - pixel_x = 4; - pixel_y = 17 - }, -/obj/item/pipe_dispenser{ - pixel_y = 4 - }, -/turf/open/floor/iron, -/area/station/science/ordnance/testlab) "qiM" = ( /obj/structure/table, /turf/open/floor/iron/cafeteria, @@ -46654,15 +46556,6 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/grass, /area/station/service/hydroponics/garden/monastery) -"quQ" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/turf/open/floor/tram, -/area/station/security/tram) "quS" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -46926,6 +46819,15 @@ /obj/structure/table/glass, /turf/open/floor/iron/white, /area/station/science/research) +"qzp" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/obj/machinery/button/transport/tram/directional/north{ + id = 1; + specific_transport_id = "bird_1" + }, +/obj/machinery/transport/destination_sign/indicator/directional/north, +/turf/open/floor/noslip, +/area/station/security/tram) "qzq" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -47008,6 +46910,12 @@ /obj/effect/spawner/random/maintenance, /turf/open/floor/iron, /area/station/maintenance/department/medical/central) +"qAq" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "qAs" = ( /obj/machinery/door/firedoor, /obj/effect/turf_decal/stripes/red/line{ @@ -47239,12 +47147,6 @@ /obj/structure/sign/poster/contraband/random/directional/north, /turf/open/floor/iron/white/small, /area/station/maintenance/port/aft) -"qDD" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "qDK" = ( /obj/machinery/light_switch/directional/west, /obj/structure/reagent_dispensers/water_cooler, @@ -47532,6 +47434,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/commons/dorms) +"qIB" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/line, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "qID" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -47826,12 +47735,6 @@ /obj/machinery/light/cold/directional/north, /turf/open/floor/iron, /area/station/hallway/primary/port) -"qOv" = ( -/obj/structure/transport/linear/tram, -/obj/structure/fluff/tram_rail/floor, -/obj/structure/thermoplastic, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "qOG" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -47865,18 +47768,6 @@ }, /turf/open/floor/iron/smooth, /area/station/cargo/drone_bay) -"qOO" = ( -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) -"qOT" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/security/tram) "qPc" = ( /obj/effect/turf_decal/tile/green/opposingcorners{ dir = 1 @@ -48278,14 +48169,6 @@ /obj/machinery/power/apc/auto_name/directional/south, /turf/open/floor/wood/tile, /area/station/command/corporate_showroom) -"qVz" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "qVK" = ( /obj/machinery/firealarm/directional/west, /obj/effect/turf_decal/stripes/corner{ @@ -48309,10 +48192,6 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/wood, /area/station/cargo/boutique) -"qWd" = ( -/obj/structure/frame/machine, -/turf/open/floor/tram, -/area/station/security/tram) "qWh" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -48522,6 +48401,11 @@ /obj/effect/spawner/random/structure/girder, /turf/open/floor/plating, /area/station/maintenance/fore/lesser) +"qYA" = ( +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic/light, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "qYD" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron/showroomfloor, @@ -48600,6 +48484,17 @@ /obj/structure/broken_flooring/corner/directional/south, /turf/open/floor/plating, /area/station/hallway/secondary/dock) +"qZH" = ( +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor{ + dir = 1 + }, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/right{ + dir = 1 + }, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "qZU" = ( /obj/machinery/portable_atmospherics/canister/plasma, /obj/effect/turf_decal/stripes/white/line{ @@ -48620,6 +48515,15 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/commons/storage/tools) +"ral" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/turf/open/floor/tram, +/area/station/security/tram) "ram" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/wood/large, @@ -48668,6 +48572,14 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/wood/large, /area/station/service/hydroponics/garden/monastery) +"rbc" = ( +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/obj/machinery/computer/tram_controls{ + specific_transport_id = "bird_1" + }, +/turf/open/floor/tram, +/area/station/security/tram) "rbh" = ( /obj/structure/cable, /obj/effect/turf_decal/siding/wood{ @@ -49059,6 +48971,14 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/station/cargo/drone_bay) +"rhy" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/security/tram) "rhD" = ( /obj/structure/cable, /obj/structure/rack, @@ -49292,15 +49212,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, /area/station/cargo/boutique) -"rlV" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 4 - }, -/obj/structure/frame/computer{ - dir = 4 - }, -/turf/open/floor/tram, -/area/station/security/tram) "rma" = ( /obj/machinery/atmospherics/pipe/smart/simple/general/visible{ dir = 6 @@ -49370,6 +49281,13 @@ /obj/effect/mapping_helpers/mail_sorting/service/library, /turf/open/floor/plating, /area/station/maintenance/central/greater) +"rnZ" = ( +/obj/structure/transport/linear/tram, +/obj/effect/landmark/transport/nav_beacon/tram/nav/birdshot/maint, +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/maint_left, +/obj/structure/thermoplastic/light, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "roi" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -49579,12 +49497,6 @@ }, /turf/open/floor/glass, /area/station/hallway/secondary/spacebridge) -"rrB" = ( -/obj/structure/transport/linear/tram, -/obj/effect/landmark/transport/transport_id/birdshot/line_2, -/obj/structure/thermoplastic/light, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "rrC" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -49690,6 +49602,14 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/plating, /area/station/engineering/main) +"rsQ" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/landmark/navigate_destination/chapel, +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, +/turf/open/floor/iron, +/area/station/hallway/primary/port) "rsV" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -49757,6 +49677,18 @@ }, /turf/closed/wall, /area/station/hallway/secondary/recreation) +"ruc" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/door/airlock/public/glass{ + name = "Prison Garden" + }, +/obj/machinery/door/firedoor, +/turf/open/floor/iron/textured_half{ + dir = 8 + }, +/area/station/security/prison/garden) "rui" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, @@ -49803,6 +49735,12 @@ "rvp" = ( /turf/closed/mineral/random/stationside, /area/station/maintenance/hallway/abandoned_command) +"rvs" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/item/stack/sheet/mineral/titanium, +/obj/machinery/light/small/directional/south, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "rvy" = ( /obj/effect/mapping_helpers/broken_floor, /obj/effect/decal/cleanable/dirt, @@ -49947,8 +49885,8 @@ /obj/structure/table, /obj/machinery/airalarm/directional/south, /obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = -6 + pixel_x = -6; + pixel_y = 6 }, /obj/item/clipboard{ pixel_x = 4; @@ -50000,14 +49938,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/fore/lesser) -"ryj" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 10 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/security/tram) "ryk" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -50380,6 +50310,12 @@ /obj/machinery/airalarm/directional/west, /turf/open/floor/iron/smooth, /area/station/cargo/drone_bay) +"rDY" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "rEb" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/generic_maintenance_landmark, @@ -51192,14 +51128,6 @@ /obj/effect/mapping_helpers/airlock/access/all/medical/pharmacy, /turf/open/floor/iron/dark/small, /area/station/medical/pharmacy) -"rQM" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 5 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "rQN" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/neutral{ @@ -51516,12 +51444,6 @@ }, /turf/open/floor/iron/smooth_large, /area/station/science/auxlab/firing_range) -"rVz" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 10 - }, -/turf/open/floor/tram, -/area/station/security/tram) "rVH" = ( /obj/effect/turf_decal/tile/blue/fourcorners, /obj/structure/table/glass, @@ -51761,12 +51683,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/catwalk_floor/flat_white, /area/station/science/robotics/augments) -"rZk" = ( -/obj/structure/chair/comfy/shuttle, -/obj/structure/transport/linear/tram, -/obj/structure/thermoplastic, -/turf/open/floor/tram, -/area/station/security/tram) "rZn" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -52039,13 +51955,6 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) -"sdC" = ( -/obj/structure/transport/linear/tram, -/obj/structure/fluff/tram_rail/floor, -/obj/structure/thermoplastic, -/obj/structure/chair/sofa/bench/tram/solo, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "sdQ" = ( /obj/structure/cable, /obj/machinery/door/airlock/maintenance{ @@ -52623,6 +52532,14 @@ /obj/effect/spawner/random/engineering/tracking_beacon, /turf/open/floor/iron, /area/station/security/courtroom) +"snB" = ( +/obj/structure/transport/linear/tram, +/obj/structure/chair{ + dir = 1 + }, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/security/tram) "snJ" = ( /obj/effect/turf_decal/stripes/corner, /obj/machinery/light/small/directional/south, @@ -52674,6 +52591,12 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/small, /area/station/engineering/atmos) +"sox" = ( +/obj/effect/turf_decal/stripes/white/line, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "soD" = ( /obj/effect/turf_decal/siding/thinplating_new/dark/corner{ dir = 8 @@ -53490,6 +53413,12 @@ /obj/effect/spawner/structure/window/reinforced/tinted, /turf/open/floor/plating, /area/station/maintenance/central/lesser) +"sBm" = ( +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor, +/obj/structure/thermoplastic/light, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "sBp" = ( /obj/structure/table, /obj/machinery/processor{ @@ -54057,6 +53986,20 @@ /obj/structure/closet/secure_closet/security/med, /turf/open/floor/iron/smooth, /area/station/security/checkpoint/customs/auxiliary) +"sLS" = ( +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/corner, +/obj/structure/holosign/barrier/atmos/tram, +/turf/open/floor/tram, +/area/station/security/tram) "sLU" = ( /obj/structure/cable, /obj/effect/spawner/structure/window/reinforced, @@ -54760,6 +54703,10 @@ }, /turf/open/floor/engine, /area/station/science/cytology) +"sXI" = ( +/obj/structure/frame/machine, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "sXO" = ( /obj/structure/chair{ dir = 4 @@ -55157,6 +55104,25 @@ dir = 1 }, /area/station/security/execution/transfer) +"teE" = ( +/obj/structure/table, +/obj/effect/mapping_helpers/broken_floor, +/obj/item/assembly/timer{ + pixel_x = -3; + pixel_y = 9 + }, +/obj/item/assembly/timer{ + pixel_y = 7 + }, +/obj/machinery/light_switch/directional/south, +/obj/structure/extinguisher_cabinet/directional/west, +/obj/item/holosign_creator/atmos, +/obj/item/holosign_creator/atmos{ + pixel_x = 3; + pixel_y = -3 + }, +/turf/open/floor/iron, +/area/station/science/ordnance/testlab) "teG" = ( /obj/structure/chair/sofa/bench{ dir = 4 @@ -55245,15 +55211,6 @@ /obj/item/clipboard, /turf/open/floor/iron/white/small, /area/station/science/server) -"tfY" = ( -/obj/structure/transport/linear/tram, -/obj/structure/fluff/tram_rail/floor{ - dir = 1 - }, -/obj/structure/thermoplastic, -/obj/structure/rack, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "tgj" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/easel, @@ -55529,24 +55486,6 @@ "tnb" = ( /turf/open/floor/plating, /area/station/maintenance/central/lesser) -"tno" = ( -/obj/structure/table, -/obj/item/storage/toolbox/mechanical{ - pixel_x = -2; - pixel_y = 8 - }, -/obj/machinery/requests_console/directional/west{ - department = "Ordnance Test Range"; - name = "Test Range Requests Console" - }, -/obj/effect/mapping_helpers/requests_console/information, -/obj/effect/mapping_helpers/requests_console/assistance, -/obj/item/storage/toolbox/mechanical{ - pixel_x = 3; - pixel_y = -2 - }, -/turf/open/floor/iron, -/area/station/science/ordnance/testlab) "tns" = ( /obj/effect/mapping_helpers/broken_floor, /obj/effect/decal/cleanable/dirt, @@ -55581,6 +55520,17 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/engine) +"tnA" = ( +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor{ + dir = 1 + }, +/obj/structure/thermoplastic, +/obj/structure/chair/sofa/bench/tram/left{ + dir = 1 + }, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "tnO" = ( /obj/structure/cable, /obj/effect/mapping_helpers/broken_floor, @@ -55610,6 +55560,17 @@ }, /turf/open/floor/wood/tile, /area/station/tcommsat/server) +"top" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/obj/machinery/computer/tram_controls{ + specific_transport_id = "bird_2" + }, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "toA" = ( /turf/open/floor/iron, /area/station/hallway/secondary/recreation) @@ -56166,6 +56127,12 @@ /obj/structure/cable, /turf/open/floor/plating/rust, /area/station/maintenance/fore/greater) +"twQ" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 9 + }, +/turf/open/floor/tram, +/area/station/maintenance/department/medical/central) "twR" = ( /obj/structure/table/glass, /obj/machinery/cell_charger, @@ -56255,6 +56222,13 @@ /obj/structure/cable, /turf/open/floor/iron/smooth, /area/station/cargo/drone_bay) +"tyT" = ( +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/obj/effect/landmark/transport/nav_beacon/tram/platform/birdshot/sec_wing, +/obj/effect/landmark/transport/nav_beacon/tram/nav/birdshot/prison, +/turf/open/floor/tram, +/area/station/security/tram) "tyY" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/firealarm/directional/south, @@ -56586,18 +56560,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/port) -"tDM" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 1; - id = "rdordnance"; - name = "Ordnance Lab Shutters" - }, -/turf/open/floor/plating, -/area/station/science/ordnance) "tDP" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -56614,6 +56576,17 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood/parquet, /area/station/service/theater) +"tEg" = ( +/obj/structure/transport/linear/tram, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/structure/fluff/tram_rail/floor{ + dir = 1 + }, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "tEj" = ( /obj/effect/turf_decal/stripes/white/line{ dir = 1 @@ -56741,6 +56714,15 @@ "tGq" = ( /turf/closed/wall, /area/station/service/kitchen/coldroom) +"tGv" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/obj/machinery/button/transport/tram/directional/north{ + id = 2; + specific_transport_id = "bird_1" + }, +/obj/machinery/transport/destination_sign/indicator/directional/north, +/turf/open/floor/noslip, +/area/station/security/tram) "tGI" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -57772,6 +57754,15 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port/greater) +"tYM" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/tram, +/area/station/security/tram) "tYN" = ( /obj/structure/cable, /turf/open/floor/iron, @@ -58132,14 +58123,6 @@ }, /turf/open/floor/iron/textured_large, /area/station/security/brig/entrance) -"udE" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/spawner/random/maintenance, -/obj/effect/spawner/random/structure/girder, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "udI" = ( /obj/structure/closet{ name = "Evidence Closet 3" @@ -58269,14 +58252,6 @@ /obj/effect/turf_decal/trimline/neutral/line, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"ufU" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, -/turf/open/floor/iron, -/area/station/security/prison/garden) "ugb" = ( /obj/effect/turf_decal/tile/yellow/opposingcorners, /obj/effect/decal/cleanable/dirt, @@ -58349,12 +58324,6 @@ /obj/effect/mapping_helpers/airlock/access/all/science/robotics, /turf/open/floor/catwalk_floor/flat_white, /area/station/science/robotics/augments) -"ugY" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 10 - }, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "uhe" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/machinery/conveyor{ @@ -58653,6 +58622,13 @@ }, /turf/open/floor/engine, /area/station/science/explab) +"umx" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 9 + }, +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/security/tram) "umz" = ( /obj/effect/turf_decal/siding/wood{ dir = 5 @@ -58825,11 +58801,6 @@ dir = 5 }, /area/station/science/research) -"upR" = ( -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "uqc" = ( /obj/structure/cable, /obj/effect/spawner/random/trash, @@ -58990,14 +58961,6 @@ "usJ" = ( /turf/open/floor/iron/kitchen/small, /area/station/maintenance/aft) -"utg" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/landmark/navigate_destination/chapel, -/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, -/turf/open/floor/iron, -/area/station/hallway/primary/port) "uth" = ( /obj/effect/turf_decal/plaque{ icon_state = "L2" @@ -59193,6 +59156,12 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/fore/greater) +"uwI" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, +/turf/open/floor/iron, +/area/station/hallway/secondary/entry) "uwU" = ( /obj/structure/closet/secure_closet/hydroponics, /obj/effect/turf_decal/bot, @@ -59967,11 +59936,6 @@ }, /turf/open/floor/iron/showroomfloor, /area/station/commons/toilet/auxiliary) -"uJZ" = ( -/obj/structure/window/reinforced/shuttle, -/obj/structure/window/reinforced/shuttle, -/turf/open/floor/plating, -/area/station/commons/fitness/recreation/entertainment) "uKl" = ( /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -60242,6 +60206,15 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/maintenance/hallway/abandoned_command) +"uPw" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/structure/frame/computer{ + dir = 4 + }, +/turf/open/floor/tram, +/area/station/security/tram) "uPJ" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -60351,13 +60324,6 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron/smooth, /area/station/maintenance/solars/port/aft) -"uRp" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/tram, -/area/station/security/tram) "uRF" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -60660,20 +60626,6 @@ "uWo" = ( /turf/closed/wall, /area/station/medical/paramedic) -"uWu" = ( -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/corner, -/obj/structure/holosign/barrier/atmos/tram, -/turf/open/floor/tram, -/area/station/security/tram) "uWv" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/flora/bush/flowers_pp/style_random, @@ -61145,14 +61097,6 @@ /obj/machinery/door/firedoor, /turf/open/floor/catwalk_floor/flat_white, /area/station/science/robotics/augments) -"vez" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 10 - }, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/maintenance/port/aft) "veA" = ( /obj/machinery/atmospherics/pipe/smart/simple/green/visible, /obj/machinery/door/poddoor/shutters/preopen{ @@ -61726,6 +61670,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/machinery/camera/autoname/directional/north, /obj/machinery/light/small/directional/north, +/obj/vehicle/sealed/mecha/ripley/paddy/preset, /turf/open/floor/iron, /area/station/security/tram) "vmX" = ( @@ -63375,6 +63320,15 @@ "vMC" = ( /turf/closed/wall/r_wall, /area/station/science/lab) +"vMF" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/fluff/tram_rail/end{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "vMJ" = ( /obj/structure/disposalpipe/sorting/mail, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -63406,12 +63360,9 @@ /obj/effect/spawner/random/trash, /turf/open/floor/plating, /area/station/maintenance/central/greater) -"vNj" = ( -/obj/effect/turf_decal/stripes/white/corner{ - dir = 4 - }, +"vMX" = ( /obj/effect/turf_decal/stripes/white/line{ - dir = 1 + dir = 5 }, /obj/structure/transport/linear/tram, /obj/structure/tram, @@ -63477,6 +63428,10 @@ "vOP" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/decal/cleanable/dirt, +/obj/structure/curtain/cloth/fancy/mechanical{ + id = "detpriv"; + name = "Curtains" + }, /turf/open/floor/iron/dark/small, /area/station/security/detectives_office) "vPa" = ( @@ -63709,6 +63664,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold/purple/visible{ dir = 4 }, +/obj/machinery/air_sensor/ordnance_freezer_chamber, /turf/open/floor/engine/vacuum, /area/station/science/ordnance/freezerchamber) "vTm" = ( @@ -64447,12 +64403,6 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/iron, /area/station/construction/mining/aux_base) -"weV" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/turf/open/floor/tram, -/area/station/security/tram) "wfa" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -64502,12 +64452,6 @@ /obj/machinery/door/firedoor, /turf/open/floor/catwalk_floor/flat_white, /area/station/science/research) -"wfH" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 9 - }, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "wfP" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/security/glass{ @@ -64648,6 +64592,18 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/dock) +"whF" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 1; + id = "rdordnance"; + name = "Ordnance Lab Shutters" + }, +/turf/open/floor/plating, +/area/station/science/ordnance) "whL" = ( /obj/effect/spawner/structure/window, /turf/open/floor/plating, @@ -65314,6 +65270,13 @@ }, /turf/open/floor/iron/dark/side, /area/station/science/xenobiology) +"wte" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/line, +/turf/open/floor/plating/airless, +/area/space/nearstation) "wtm" = ( /obj/structure/cable, /obj/effect/turf_decal/siding/blue{ @@ -65806,9 +65769,10 @@ pixel_x = -5; pixel_y = 3 }, -/obj/machinery/button/door/directional/west{ - id = "detpriv"; - name = "Curtains" +/obj/machinery/button/curtain{ + pixel_x = -24; + name = "Curtains"; + id = "detpriv" }, /turf/open/floor/wood, /area/station/security/detectives_office) @@ -65994,10 +65958,6 @@ /obj/machinery/light_switch/directional/south, /turf/open/floor/iron/white, /area/station/medical/medbay/central) -"wDu" = ( -/obj/effect/turf_decal/stripes/white/line, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "wDA" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, @@ -66234,13 +66194,6 @@ /obj/effect/turf_decal/tile/neutral/opposingcorners, /turf/open/floor/iron, /area/station/hallway/secondary/spacebridge) -"wHY" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 9 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/tram, -/area/station/security/tram) "wIc" = ( /obj/structure/window/spawner/directional/west, /obj/structure/flora/rock/pile/jungle/style_random, @@ -66639,6 +66592,12 @@ /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron, /area/station/hallway/primary/port) +"wNS" = ( +/obj/structure/rack, +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/security/tram) "wNT" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -66761,18 +66720,9 @@ /turf/open/floor/iron/dark, /area/station/security/interrogation) "wPf" = ( -/obj/structure/cable, -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/door/poddoor/preopen{ - id = "hop"; - name = "Privacy Shutters" - }, -/obj/machinery/door/poddoor/preopen{ - id = "hop"; - name = "Privacy Shutters" - }, -/turf/open/floor/plating, -/area/station/command/heads_quarters/hop) +/obj/item/clothing/glasses/blindfold, +/turf/open/space/basic, +/area/space) "wPh" = ( /obj/structure/disposalpipe/trunk{ dir = 8 @@ -66976,8 +66926,8 @@ /obj/item/radio/intercom/directional/south, /obj/structure/extinguisher_cabinet/directional/west, /obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = 4 + pixel_x = 4; + pixel_y = 6 }, /obj/item/stack/medical/gauze{ pixel_x = -2; @@ -67735,6 +67685,13 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"xcq" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/tram, +/area/station/security/tram) "xcv" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -67962,6 +67919,15 @@ }, /turf/open/floor/iron/white, /area/station/science/cytology) +"xfy" = ( +/obj/structure/transport/linear/tram, +/obj/structure/fluff/tram_rail/floor{ + dir = 1 + }, +/obj/structure/thermoplastic, +/obj/structure/rack, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "xfH" = ( /obj/machinery/portable_atmospherics/canister/air, /turf/open/floor/iron, @@ -68128,6 +68094,18 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/central/greater) +"xhU" = ( +/obj/structure/flora/bush/large/style_random{ + pixel_x = -18; + pixel_y = -9 + }, +/obj/structure/flora/bush/flowers_yw/style_random, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/turf_decal/siding/wideplating{ + dir = 4 + }, +/turf/open/misc/sandy_dirt, +/area/station/security/tram) "xia" = ( /turf/closed/wall, /area/station/science/cubicle) @@ -68241,6 +68219,14 @@ "xjz" = ( /turf/closed/wall/r_wall, /area/station/security/prison/garden) +"xjE" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "xjG" = ( /obj/effect/decal/cleanable/dirt, /obj/item/radio/intercom/prison/directional/north, @@ -68534,6 +68520,13 @@ /obj/effect/turf_decal/delivery/white, /turf/open/floor/iron, /area/station/cargo/sorting) +"xnB" = ( +/obj/effect/turf_decal/stripes/white/corner, +/obj/effect/turf_decal/stripes/white/line, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "xnC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -68547,8 +68540,12 @@ /obj/effect/decal/cleanable/dirt, /obj/machinery/airalarm/directional/east, /obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnanceburn" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, /turf/open/floor/iron/dark, -/area/station/science/ordnance/burnchamber) +/area/station/science/ordnance) "xoa" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -68693,6 +68690,11 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"xpV" = ( +/obj/structure/transport/linear/tram, +/obj/structure/thermoplastic, +/turf/open/floor/tram, +/area/station/security/tram) "xpY" = ( /obj/structure/cable, /obj/structure/table/reinforced, @@ -68779,15 +68781,6 @@ "xqW" = ( /turf/closed/wall/r_wall, /area/station/hallway/primary/starboard) -"xrh" = ( -/obj/structure/window/reinforced/spawner/directional/west, -/obj/machinery/button/transport/tram/directional/north{ - specific_transport_id = "bird_1"; - id = 2 - }, -/obj/machinery/transport/destination_sign/indicator/directional/north, -/turf/open/floor/noslip, -/area/station/security/tram) "xrk" = ( /obj/effect/turf_decal/tile/dark_red/opposingcorners, /obj/effect/decal/cleanable/dirt, @@ -69212,6 +69205,14 @@ /obj/structure/barricade/wooden/crude, /turf/open/floor/plating, /area/station/maintenance/starboard/central) +"xwJ" = ( +/obj/effect/turf_decal/stripes/white/line{ + dir = 10 + }, +/obj/structure/transport/linear/tram, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/security/tram) "xwQ" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/white/line{ @@ -69684,13 +69685,6 @@ }, /turf/open/floor/iron/small, /area/station/hallway/primary/starboard) -"xDM" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 10 - }, -/obj/item/stack/sheet/mineral/titanium, -/turf/open/floor/tram, -/area/station/security/tram) "xDW" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -69852,12 +69846,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/engine) -"xGb" = ( -/obj/effect/turf_decal/stripes/white/line, -/obj/structure/transport/linear/tram, -/obj/structure/tram, -/turf/open/floor/tram, -/area/station/security/tram) "xGc" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -70367,6 +70355,10 @@ /obj/machinery/airalarm/directional/south, /turf/open/floor/iron/dark, /area/station/science/ordnance) +"xMM" = ( +/obj/item/stack/sheet/mineral/titanium, +/turf/open/floor/tram, +/area/station/security/tram) "xMO" = ( /obj/effect/spawner/random/entertainment/arcade{ dir = 1 @@ -71560,6 +71552,18 @@ /obj/structure/extinguisher_cabinet/directional/east, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) +"yci" = ( +/obj/effect/turf_decal/stripes/white/corner{ + dir = 4 + }, +/obj/structure/transport/linear/tram, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/structure/fluff/tram_rail/floor, +/obj/structure/tram, +/turf/open/floor/tram, +/area/station/maintenance/port/aft) "ycj" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -71579,13 +71583,6 @@ }, /turf/open/floor/iron/white, /area/station/science/research) -"ycv" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/white/line, -/turf/open/floor/tram, -/area/station/maintenance/department/medical/central) "ycC" = ( /turf/closed/wall/r_wall, /area/station/command/bridge) @@ -72008,10 +72005,6 @@ /obj/structure/window/spawner/directional/north, /turf/open/floor/plating, /area/station/maintenance/department/engine) -"yhE" = ( -/obj/effect/landmark/transport/nav_beacon/tram/nav/immovable_rod, -/turf/closed/wall, -/area/station/maintenance/port/aft) "yhF" = ( /obj/machinery/door/firedoor, /turf/open/floor/iron, @@ -84581,12 +84574,12 @@ vKU lPO vfc lzM -jfX -cJu -kKy -cJu -uRp -kef +iNO +xcq +ggh +xcq +mXD +jHI ieZ rtQ aJq @@ -84838,12 +84831,12 @@ dkI dLn rxu lzM -ndA -qWd -qWd -dhX -iyk -ays +eDt +bro +bro +xMM +eQC +jwZ ieZ rtQ aJq @@ -85095,12 +85088,12 @@ qBT uRJ rcg lzM -xDM -acO -kLG -bQz -rlV -wHY +iVq +hmf +dpR +bmT +uPw +umx ieZ rtQ aJq @@ -85623,11 +85616,11 @@ nlV toT kaI tlI -hUT +dlx uEI gxx gxx -oVE +xhU jYv nlV sGp @@ -85866,12 +85859,12 @@ mZc hXU hXU aFR -oaE -dyn -dyn -dyn -dyn -qOT +gFZ +xjE +xjE +xjE +xjE +vMX aFR kGC qBi @@ -85893,12 +85886,12 @@ qBi qBi ltp qBi -gTC -weV -jEX -weV -weV -jYd +aOX +awe +bUO +awe +awe +dEF qBi xAG pGR @@ -86123,12 +86116,12 @@ ccD yap lzM ezE -ius -rZk -kvb -kvb -itv -xGb +fXD +cDt +xpV +xpV +snB +sox aFR kGC qBi @@ -86150,12 +86143,12 @@ qBi qBi ltp qBi -aYO -fay -fay -fay -fay -ipn +pCC +bjZ +bjZ +bjZ +bjZ +khl qBi xAG pGR @@ -86339,7 +86332,7 @@ xRZ wAZ wXk xgN -utg +rsQ kar vnr vIh @@ -86380,39 +86373,39 @@ qXj rBE lzM aFR -hYz -gkO -iRp -aPe -kvb -jUN -kNA -uWu -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kNA -kjn -quQ -fay -fay -fay -kye -fay -fay +iVu +wNS +fTd +tyT +xpV +rbc +ral +sLS +ral +ral +ral +ral +ral +ral +ral +ral +ral +ral +ral +ral +ral +ral +ral +ral +ral +oDY +tYM +bjZ +bjZ +bjZ +lqL +bjZ +bjZ qBi iJt pGR @@ -86426,7 +86419,7 @@ eax xAG jWd lGO -ufU +cZA hyX tBm tBm @@ -86637,12 +86630,12 @@ dBr eWB lzM aFR -vNj -rZk -kvb -kvb -kSo -kyS +mnb +cDt +xpV +xpV +rhy +xnB aFR kGC qBi @@ -86664,12 +86657,12 @@ qBi qBi ltp qBi -aYO -fay -fay -fay -fay -ipn +pCC +bjZ +bjZ +bjZ +bjZ +khl qBi xAG pSd @@ -86683,7 +86676,7 @@ xAG xAG uby wCX -lvM +ruc uby wCX uby @@ -86894,12 +86887,12 @@ tRE vzY lzM aFR -ryj -eTq -cID -cID -eTq -gXd +xwJ +paI +cZC +cZC +paI +khp aFR kGC qBi @@ -86921,12 +86914,12 @@ qBi qBi ltp aFR -rVz -kLG -kLG -kLG -kLG -bUo +dHn +dpR +dpR +dpR +dpR +cRW qBi xAG pSd @@ -87151,7 +87144,7 @@ tRE dUD lzM lzM -xrh +tGv tpm jeh jeh @@ -87178,7 +87171,7 @@ mTQ qDO lzM lzM -mId +qzp tpm jeh jeh @@ -88708,7 +88701,7 @@ trp trp trp trp -yhE +akF trp trp trp @@ -88964,9 +88957,9 @@ xAR gqg hQE xAR -fos +keq xAR -fbX +vMF xAR xAR xAR @@ -89220,11 +89213,11 @@ trp trp trp trp -eVe -pxs -upR -jVX -rQM +dsU +aYv +dmG +aLv +dSV vJH xAR trp @@ -89471,17 +89464,17 @@ xAR trp kiG iVJ -coH +boI trp mPv aGU wqD trp -qVz -sdC -eEl -qfw -fuk +lbG +oJA +qYA +tnA +rDY vJH xAR trp @@ -89734,11 +89727,11 @@ sVL xul knJ fAr -oNM -qOv -eEl -oXh -fuk +oOL +khQ +qYA +qZH +rDY vJH xAR trp @@ -89991,11 +89984,11 @@ jRx knJ xul mxM -iaZ -cSD -rrB -tfY -fuk +jzg +sBm +pdf +xfy +rDY vJH xAR trp @@ -90248,11 +90241,11 @@ xIC knJ nFu mxM -gTk -cSD -jwC -tfY -fuk +kbc +sBm +rnZ +xfy +rDY vJH xAR trp @@ -90505,11 +90498,11 @@ gEe bbU knJ fAr -cwd -qOv -eEl -qfw -fuk +top +khQ +qYA +tnA +rDY vJH xAR trp @@ -90760,13 +90753,13 @@ vUf muI vUf vAU -caE +mNG trp -qVz -sdC -eEl -oXh -fuk +lbG +oJA +qYA +qZH +rDY vJH xAR trp @@ -91019,11 +91012,11 @@ xul edP xul trp -vez -isf -oGS -pNT -dBF +css +yci +gkq +tEg +dCs trp vfi trp @@ -91278,7 +91271,7 @@ xul trp vJH vJH -iBV +bRN vJH vJH trp @@ -91792,7 +91785,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -92049,7 +92042,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -92306,7 +92299,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -92563,7 +92556,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -92820,7 +92813,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -93077,7 +93070,7 @@ blb blb blb blb -pwG +wte blb blb blb @@ -93334,7 +93327,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -93591,7 +93584,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -93848,7 +93841,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -94105,7 +94098,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -94362,7 +94355,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -94619,7 +94612,7 @@ blb blb blb blb -pwG +wte blb blb blb @@ -94790,7 +94783,7 @@ tgw lqt ghD aZP -wPf +xQw mvT vrn kvT @@ -94876,7 +94869,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -95133,7 +95126,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -95304,7 +95297,7 @@ njA lqt cpT xQv -wPf +xQw mvT vrn ncL @@ -95390,7 +95383,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -95647,7 +95640,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -95904,7 +95897,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -96161,7 +96154,7 @@ blb blb blb blb -pwG +wte blb blb blb @@ -96418,7 +96411,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -96675,7 +96668,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -96932,7 +96925,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -97189,7 +97182,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -97446,7 +97439,7 @@ blb blb blb blb -pwG +wte blb blb blb @@ -97703,7 +97696,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -97960,7 +97953,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -98217,7 +98210,7 @@ blb dDB dDB dDB -pwG +wte dDB dDB bSo @@ -98474,7 +98467,7 @@ blb sSQ lMF lMF -pfY +nZz lMF lMF sSQ @@ -98731,7 +98724,7 @@ sSQ sSQ ulO ulO -ycv +qIB ulO ulO sSQ @@ -98986,11 +98979,11 @@ sSQ sqV nFy sSQ -liU -fWh -fqT -fWh -kqZ +goB +jbt +pfd +jbt +qAq sSQ rwq sSQ @@ -99241,13 +99234,13 @@ wgL tLt sSQ aTc -frB +dZT sSQ -qDD -pqf -pqf -pqf -wDu +ndp +gow +gow +gow +aEa ulO gpu sSQ @@ -99500,18 +99493,18 @@ sSQ liH uOw eBQ -qDD -pqf -pqf -pqf -wDu +ndp +gow +gow +gow +aEa ulO gpu sOj vTG -crr -cuG -ksL +pKp +ksv +pzN sSQ dDB dDB @@ -99757,18 +99750,18 @@ sSQ ewW aTc cku -qDD -pqf -pqf -pqf -wDu +ndp +gow +gow +gow +aEa ulO gpu sOj vTG -ocg -pqf -gjr +mET +gow +pje sSQ dDB dDB @@ -100014,18 +100007,18 @@ pVK oZY aTc cku -qDD -pqf -hmB -pqf -wDu +ndp +gow +aCR +gow +aEa ulO gpu sOj vTG -udE -edW -prT +pXh +mdr +klY sSQ dDB dDB @@ -100271,18 +100264,18 @@ sSQ hia ggl eBQ -qDD -pqf -pqf -pqf -wDu +ndp +gow +gow +gow +aEa ulO gpu sOj vTG -pDG -qOO -dbO +aAV +gSz +ddq sSQ dDB dDB @@ -100528,18 +100521,18 @@ sSQ fWW idW sSQ -qDD -pqf -pqf -pqf -wDu +ndp +gow +gow +gow +aEa ulO gpu sOj vTG -pNm -eFi -prT +igD +sXI +klY sSQ dDB dDB @@ -100785,18 +100778,18 @@ sSQ lQZ sSQ sSQ -ugY -gwh -gwh -gwh -wfH +lTU +nhx +nhx +nhx +twQ ulO gpu sOj vTG -nJm -pqf -prT +oTI +gow +klY sSQ dDB dDB @@ -101051,9 +101044,9 @@ ulO gpu sOj vTG -mGQ -edW -bFG +oIK +mdr +rvs sSQ dDB dDB @@ -101308,9 +101301,9 @@ ulO gpu sOj vTG -dLd -gwh -wfH +gSs +nhx +twQ sSQ blb blb @@ -107725,8 +107718,8 @@ ykn vbR vbR vbR -hzI -oBo +kms +uwI vbR vbR fnz @@ -109941,7 +109934,7 @@ tIE aJN aJN aJN -uJZ +aJN aJN doX doX @@ -112269,7 +112262,7 @@ jAV wOp kbE vgf -iLk +dJz nSu xXT cek @@ -112523,7 +112516,7 @@ kIL lao lui ssY -isW +hPq kbW nfS uLf @@ -121305,7 +121298,7 @@ qJr qJr fky lkV -tDM +whF okW kQt fUo @@ -123612,9 +123605,9 @@ rle wTJ wrv ejx -tno -qiH -mmf +bry +heT +teE qei xwQ wCH @@ -132060,7 +132053,7 @@ dDB dDB dDB dDB -dDB +wPf dDB dDB dDB diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index ad05d3cb906c63..bb4f8c4c16b49b 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -23,13 +23,6 @@ }, /turf/closed/wall/r_wall, /area/station/maintenance/solars/port/fore) -"aaj" = ( -/obj/structure/bed/dogbed/renault, -/obj/machinery/newscaster/directional/south, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/basic/pet/fox/renault, -/turf/open/floor/iron/dark, -/area/station/command/heads_quarters/captain) "aaz" = ( /obj/effect/landmark/start/hangover, /obj/structure/chair/stool/directional/east, @@ -285,6 +278,11 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/grimy, /area/station/command/bridge) +"adE" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "adF" = ( /obj/effect/turf_decal/stripes/corner{ dir = 8 @@ -376,6 +374,18 @@ }, /turf/open/floor/iron/white, /area/station/science/xenobiology) +"aeD" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment, +/obj/machinery/camera/directional/east{ + c_tag = "Cargo Bay - Delivery Office"; + name = "cargo camera" + }, +/obj/effect/turf_decal/tile/brown, +/obj/machinery/light/directional/east, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/cargo/sorting) "aeE" = ( /obj/structure/table/reinforced, /obj/item/stack/package_wrap, @@ -1280,6 +1290,14 @@ }, /turf/open/floor/iron, /area/station/maintenance/port/aft) +"apf" = ( +/obj/machinery/mech_bay_recharge_port{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "apu" = ( /obj/machinery/holopad, /obj/effect/turf_decal/bot, @@ -2187,6 +2205,16 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"azD" = ( +/obj/effect/turf_decal/tile/brown/anticorner/contrasted{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "azE" = ( /obj/effect/turf_decal/tile/red/opposingcorners, /obj/effect/turf_decal/tile/yellow/opposingcorners{ @@ -2527,17 +2555,20 @@ /obj/item/clothing/under/rank/civilian/lawyer/black/skirt, /turf/open/floor/wood, /area/station/commons/dorms) +"aFb" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/loading_area{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "aFo" = ( /obj/structure/lattice, /obj/structure/grille/broken, /turf/open/space, /area/space/nearstation) -"aFs" = ( -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 4 - }, -/turf/open/floor/iron/white, -/area/station/science/lobby) "aFv" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -2745,11 +2776,6 @@ /obj/item/toy/figure/chef, /turf/open/floor/iron/dark, /area/station/service/kitchen) -"aHw" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/plating, -/area/station/maintenance/port/aft) "aHC" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/status_display/evac/directional/east, @@ -3270,6 +3296,11 @@ /obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted, /turf/open/floor/iron/dark, /area/station/medical/morgue) +"aOd" = ( +/obj/structure/table/wood, +/obj/item/paper/fluff/jobs/engineering/frequencies, +/turf/open/floor/iron/grimy, +/area/station/tcommsat/computer) "aOf" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -3418,15 +3449,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/science/robotics/lab) -"aPD" = ( -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/door/firedoor, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "aPO" = ( /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, /obj/effect/turf_decal/tile/yellow{ @@ -3558,6 +3580,12 @@ }, /turf/open/floor/iron, /area/station/security/prison/safe) +"aRX" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/tile/red/fourcorners, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/iron, +/area/station/service/kitchen/abandoned) "aRZ" = ( /obj/structure/dresser, /obj/item/radio/intercom/directional/east, @@ -4053,6 +4081,21 @@ /obj/effect/spawner/structure/window/reinforced/plasma, /turf/open/floor/plating, /area/station/engineering/main) +"aZj" = ( +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/structure/table/reinforced, +/obj/item/clothing/glasses/welding, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/item/weldingtool/empty{ + pixel_y = 8; + pixel_x = 9 + }, +/obj/machinery/power/apc/auto_name/directional/south, +/obj/structure/cable, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "aZo" = ( /obj/structure/table/reinforced, /obj/item/electronics/airalarm, @@ -4984,13 +5027,6 @@ }, /turf/open/floor/iron/grimy, /area/station/command/heads_quarters/hos) -"bkr" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/conveyor{ - id = "cargodisposals" - }, -/turf/open/floor/plating, -/area/station/cargo/sorting) "bkD" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, @@ -5127,6 +5163,16 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"bmo" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/turf/open/floor/iron/herringbone, +/area/station/cargo/miningoffice) "bmp" = ( /obj/machinery/status_display/ai/directional/north, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -6658,6 +6704,13 @@ }, /turf/open/floor/iron/dark/corner, /area/station/maintenance/disposal/incinerator) +"bFA" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/iron/herringbone, +/area/station/cargo/miningoffice) "bFS" = ( /obj/effect/turf_decal/trimline/blue/filled/warning, /obj/structure/cable, @@ -6870,6 +6923,13 @@ }, /turf/open/floor/iron, /area/station/construction/mining/aux_base) +"bHd" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/table/wood, +/obj/item/radio/intercom/command, +/obj/item/paper/fluff/jobs/engineering/frequencies, +/turf/open/floor/carpet, +/area/station/command/meeting_room/council) "bHg" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/corner, @@ -7294,28 +7354,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/department/science) -"bLN" = ( -/obj/structure/rack, -/obj/effect/decal/cleanable/dirt, -/obj/item/storage/toolbox/emergency{ - pixel_x = -3; - pixel_y = 3 - }, -/obj/item/storage/toolbox/emergency, -/obj/item/shovel, -/obj/item/shovel, -/obj/item/pickaxe, -/obj/item/pickaxe, -/obj/effect/turf_decal/bot, -/obj/machinery/light/small/directional/south, -/obj/machinery/power/apc/auto_name/directional/west, -/obj/machinery/light_switch/directional/west{ - pixel_x = -38 - }, -/obj/machinery/airalarm/directional/south, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "bLP" = ( /obj/machinery/camera/directional/east{ c_tag = "Permabrig - Kitchen Entrance"; @@ -7389,12 +7427,6 @@ /obj/effect/turf_decal/trimline/purple/filled/warning, /turf/open/floor/iron/white, /area/station/science/lab) -"bMw" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/structure/window/reinforced/spawner/directional/west, -/turf/open/space, -/area/space/nearstation) "bMB" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -7676,6 +7708,14 @@ dir = 8 }, /area/station/science/lobby) +"bRs" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/plating, +/area/station/maintenance/port) "bRw" = ( /obj/structure/sign/warning/deathsposal/directional/east, /obj/machinery/disposal/bin, @@ -8187,17 +8227,6 @@ }, /turf/open/floor/iron, /area/station/commons/fitness/recreation) -"bWw" = ( -/obj/effect/turf_decal/tile/red{ - dir = 4 - }, -/obj/machinery/status_display/door_timer{ - id = "Isolation_Cell"; - name = "Isolation Cell"; - pixel_x = -32 - }, -/turf/open/floor/iron, -/area/station/security/execution/transfer) "bWD" = ( /obj/effect/turf_decal/siding/wood{ dir = 4 @@ -8428,6 +8457,16 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/primary/port) +"bZe" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/glass, +/obj/machinery/duct, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/mob/living/basic/cockroach, +/turf/open/floor/iron, +/area/station/medical/abandoned) "bZz" = ( /obj/structure/table/wood, /obj/item/folder, @@ -9143,6 +9182,24 @@ "cjN" = ( /turf/closed/wall/r_wall, /area/station/security/office) +"cjO" = ( +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/brown/line{ + dir = 8 + }, +/obj/effect/decal/cleanable/generic, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/landmark/start/bitrunner, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron/dark/textured_large, +/area/station/bitrunning/den) "ckb" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -10099,17 +10156,6 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron, /area/station/security/prison/safe) -"cvc" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/plating, -/area/station/maintenance/department/science) "cvo" = ( /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/cable, @@ -10150,12 +10196,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/hop) -"cwd" = ( -/obj/machinery/light/directional/south, -/obj/machinery/byteforge, -/obj/effect/turf_decal/box, -/turf/open/floor/iron/dark/smooth_large, -/area/station/bitrunning/den) "cwe" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -10207,22 +10247,6 @@ /obj/structure/sign/warning/radiation/directional/south, /turf/open/floor/iron, /area/station/engineering/supermatter/room) -"cwK" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/turf_decal/tile/brown/half/contrasted{ - dir = 4 - }, -/obj/effect/turf_decal/delivery, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/turf/open/floor/iron, -/area/station/maintenance/starboard/fore) "cwV" = ( /obj/effect/landmark/start/hangover, /obj/structure/disposalpipe/segment{ @@ -10291,14 +10315,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/engineering/storage/tech) -"cxv" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/delivery, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/maintenance/fore) "cxM" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/stripes/line, @@ -10333,11 +10349,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/medical/treatment_center) -"cyc" = ( -/obj/machinery/netpod, -/obj/machinery/airalarm/directional/east, -/turf/open/floor/catwalk_floor/iron_dark, -/area/station/bitrunning/den) "cyq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -11092,9 +11103,6 @@ /obj/item/radio/intercom/directional/north, /turf/open/floor/iron/grimy, /area/station/tcommsat/computer) -"cGV" = ( -/turf/closed/wall, -/area/station/bitrunning/den) "cHb" = ( /obj/machinery/door/firedoor/heavy, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -11653,13 +11661,6 @@ /obj/effect/spawner/random/trash/janitor_supplies, /turf/open/floor/plating, /area/station/maintenance/fore) -"cOS" = ( -/obj/structure/cable, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) "cOU" = ( /obj/structure/weightmachine/weightlifter, /obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ @@ -11890,6 +11891,13 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/plating, /area/station/maintenance/department/eva/abandoned) +"cRR" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/table, +/obj/item/storage/medkit/regular, +/obj/machinery/light/directional/west, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "cRT" = ( /turf/open/floor/iron, /area/station/medical/abandoned) @@ -12016,6 +12024,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/primary/port) +"cTv" = ( +/obj/effect/turf_decal/tile/purple/half/contrasted{ + dir = 4 + }, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "cTy" = ( /obj/machinery/atmospherics/pipe/smart/manifold/cyan/visible{ dir = 1 @@ -12733,6 +12748,18 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/plating, /area/station/service/library/abandoned) +"ddp" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, +/obj/structure/table/reinforced, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/machinery/digital_clock/directional/south, +/obj/item/mod/module/signlang_radio, +/turf/open/floor/iron, +/area/station/medical/storage) "dds" = ( /obj/machinery/camera/directional/east{ c_tag = "Virology - Break Room"; @@ -13270,6 +13297,19 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) +"dkr" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/chair/office, +/obj/machinery/status_display/supply{ + pixel_x = 32 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/cargo/sorting) "dkz" = ( /obj/structure/disposalpipe/segment, /obj/machinery/light/small/directional/west, @@ -13798,6 +13838,12 @@ dir = 4 }, /area/station/science/lobby) +"dsb" = ( +/obj/machinery/netpod, +/obj/structure/sign/poster/random/directional/north, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/turf/open/floor/catwalk_floor/iron_dark, +/area/station/bitrunning/den) "dse" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -14020,18 +14066,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/science/xenobiology) -"dux" = ( -/obj/structure/table, -/obj/effect/turf_decal/tile/brown/half{ - dir = 4 - }, -/obj/item/clipboard, -/obj/item/toy/figure/miner, -/obj/machinery/light/directional/south, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/cargo/miningoffice) "duA" = ( /turf/closed/wall/r_wall, /area/station/command/corporate_showroom) @@ -14311,6 +14345,11 @@ "dxe" = ( /turf/closed/wall, /area/station/medical/abandoned) +"dxh" = ( +/obj/structure/table/wood, +/obj/item/aquarium_kit, +/turf/open/floor/carpet/red, +/area/station/hallway/secondary/service) "dxi" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/door/window{ @@ -15250,6 +15289,17 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) +"dKR" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/plating, +/area/station/maintenance/department/science) "dLd" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -15681,18 +15731,19 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/command/gateway) +"dPv" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/cargo/storage) "dPB" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 }, /turf/open/floor/plating, /area/station/engineering/supermatter/room) -"dPC" = ( -/obj/structure/closet/secure_closet/miner, -/obj/effect/turf_decal/delivery, -/obj/structure/extinguisher_cabinet/directional/north, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "dPD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -15858,15 +15909,6 @@ /obj/effect/turf_decal/tile/brown/half/contrasted, /turf/open/floor/iron, /area/station/cargo/lobby) -"dRQ" = ( -/obj/structure/table/glass, -/obj/item/surgery_tray/full, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/item/clothing/gloves/latex, -/obj/item/clothing/suit/apron/surgical, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/medical/surgery/theatre) "dSj" = ( /obj/effect/spawner/random/engineering/tracking_beacon, /obj/effect/landmark/event_spawn, @@ -16095,6 +16137,16 @@ }, /turf/open/floor/iron, /area/station/commons/fitness/recreation) +"dVA" = ( +/obj/structure/cable, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/maintenance/fore) "dVC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -16233,14 +16285,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/maintenance/port) -"dXs" = ( -/obj/effect/turf_decal/tile/brown/half/contrasted{ - dir = 4 - }, -/obj/structure/table/reinforced, -/obj/item/flashlight/lamp, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "dXw" = ( /obj/structure/sign/painting/large/library_private{ dir = 1; @@ -16287,6 +16331,13 @@ /obj/effect/landmark/start/medical_doctor, /turf/open/floor/iron/white, /area/station/medical/medbay) +"dXX" = ( +/obj/structure/closet/secure_closet/miner, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/delivery, +/obj/machinery/light/directional/north, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "dYj" = ( /turf/closed/wall/r_wall, /area/station/engineering/atmos/hfr_room) @@ -16672,6 +16723,13 @@ /obj/machinery/light/small/directional/north, /turf/open/floor/iron, /area/station/engineering/atmos/hfr_room) +"ecX" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/conveyor{ + id = "cargodisposals" + }, +/turf/open/floor/plating, +/area/station/cargo/sorting) "eda" = ( /obj/structure/chair/sofa/bench{ dir = 8 @@ -17062,6 +17120,11 @@ /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron/dark, /area/station/service/bar) +"eit" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/mob/living/basic/cockroach, +/turf/open/floor/iron/dark, +/area/station/service/abandoned_gambling_den) "eiw" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -17153,19 +17216,6 @@ }, /turf/open/floor/iron, /area/station/command/heads_quarters/qm) -"eke" = ( -/obj/structure/cable, -/obj/structure/disposalpipe/junction/yjunction{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/maintenance/fore) "ekM" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/cobweb/cobweb2, @@ -17240,12 +17290,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/command/gateway) -"elO" = ( -/obj/effect/landmark/event_spawn, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "elP" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/yellow/fourcorners, @@ -17323,18 +17367,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/engine/atmos) -"emZ" = ( -/obj/machinery/conveyor{ - dir = 4; - id = "garbage" - }, -/obj/machinery/recycler{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/plating, -/area/station/maintenance/disposal) "enc" = ( /obj/machinery/status_display/evac/directional/east, /obj/item/kirbyplants/photosynthetic{ @@ -17647,6 +17679,12 @@ /obj/effect/turf_decal/tile/purple/opposingcorners, /turf/open/floor/iron/textured, /area/station/maintenance/port/aft) +"ero" = ( +/obj/structure/bed/dogbed/mcgriff, +/obj/effect/turf_decal/tile/red/anticorner/contrasted, +/mob/living/basic/pet/dog/pug/mcgriff, +/turf/open/floor/iron, +/area/station/security/warden) "ers" = ( /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron, @@ -18543,6 +18581,28 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/engineering/storage/tech) +"eCQ" = ( +/obj/structure/rack, +/obj/effect/decal/cleanable/dirt, +/obj/item/storage/toolbox/emergency{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/storage/toolbox/emergency, +/obj/item/shovel, +/obj/item/shovel, +/obj/item/pickaxe, +/obj/item/pickaxe, +/obj/effect/turf_decal/bot, +/obj/machinery/light/small/directional/south, +/obj/machinery/power/apc/auto_name/directional/west, +/obj/machinery/light_switch/directional/west{ + pixel_x = -38 + }, +/obj/machinery/airalarm/directional/south, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "eCR" = ( /obj/effect/turf_decal/trimline/neutral/filled/corner{ dir = 4 @@ -18668,6 +18728,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) +"eEI" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, +/obj/structure/disposalpipe/segment, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/duct, +/mob/living/basic/goat/pete, +/turf/open/floor/iron/freezer, +/area/station/service/kitchen/coldroom) "eFj" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/structure/window/reinforced/spawner/directional/north, @@ -18728,18 +18796,6 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) -"eFU" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "eGb" = ( /obj/effect/spawner/random/trash/mess, /turf/open/floor/wood, @@ -19070,6 +19126,16 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/grimy, /area/station/service/lawoffice) +"eJx" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/landmark/blobstart, +/obj/effect/turf_decal/tile/red/opposingcorners, +/obj/effect/turf_decal/tile/yellow/opposingcorners{ + dir = 1 + }, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/iron, +/area/station/service/kitchen/abandoned) "eJy" = ( /obj/effect/decal/cleanable/blood/old, /obj/effect/decal/cleanable/dirt, @@ -19708,6 +19774,14 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat_interior) +"eQG" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron/herringbone, +/area/station/cargo/miningoffice) "eQK" = ( /obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ dir = 1 @@ -20039,6 +20113,11 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/command/bridge) +"eVc" = ( +/obj/effect/landmark/blobstart, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/plating, +/area/station/maintenance/solars/starboard/aft) "eVk" = ( /obj/structure/disposalpipe/sorting/mail/flip{ dir = 4; @@ -20070,6 +20149,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/engineering/atmos) +"eVz" = ( +/obj/structure/cable, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/maintenance/fore) "eVE" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -20292,29 +20378,6 @@ }, /turf/open/floor/glass, /area/station/maintenance/space_hut/observatory) -"eYo" = ( -/obj/structure/table/reinforced, -/obj/item/gun/energy/laser/carbine/practice{ - pixel_x = 3; - pixel_y = -3 - }, -/obj/item/gun/energy/laser/practice, -/obj/item/clothing/ears/earmuffs, -/obj/item/clothing/ears/earmuffs, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/airalarm/directional/south, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/security/range) -"eYt" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/machinery/computer/order_console/mining, -/obj/item/radio/intercom/directional/west, -/obj/machinery/firealarm/directional/west{ - pixel_y = -9 - }, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "eYy" = ( /obj/structure/cable, /obj/structure/closet/secure_closet/atmospherics, @@ -20398,13 +20461,6 @@ /obj/effect/mapping_helpers/airlock/access/all/security/general, /turf/open/floor/iron, /area/station/security/checkpoint/escape) -"eYZ" = ( -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/brown/anticorner/contrasted, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/cargo/sorting) "eZe" = ( /obj/machinery/vending/wardrobe/viro_wardrobe, /obj/structure/sign/poster/official/cleanliness/directional/west, @@ -20506,10 +20562,6 @@ /obj/effect/decal/cleanable/cobweb, /turf/open/floor/iron/smooth, /area/station/maintenance/department/science/xenobiology) -"fbu" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/plating, -/area/station/bitrunning/den) "fbA" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -20946,6 +20998,18 @@ /obj/item/kirbyplants/random, /turf/open/floor/wood, /area/station/service/theater/abandoned) +"fgk" = ( +/obj/machinery/navbeacon{ + codes_txt = "patrol;next_patrol=hall12"; + location = "hall11" + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/mob/living/simple_animal/bot/secbot/beepsky/officer, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "fgq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -21100,11 +21164,6 @@ }, /turf/open/floor/wood, /area/station/service/library/abandoned) -"fiu" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/basic/cockroach, -/turf/open/floor/iron/dark, -/area/station/service/abandoned_gambling_den) "fix" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -21120,13 +21179,6 @@ /obj/effect/turf_decal/tile/purple, /turf/open/floor/iron/white, /area/station/science/robotics/lab) -"fiJ" = ( -/obj/structure/cable, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/maintenance/fore) "fiL" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -21447,6 +21499,21 @@ }, /turf/open/floor/wood, /area/station/service/library/abandoned) +"fmH" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/turf_decal/tile/brown/half/contrasted{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/maintenance/starboard/fore) "fmI" = ( /obj/machinery/bluespace_vendor/directional/south, /obj/effect/turf_decal/tile/neutral, @@ -21990,13 +22057,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/grimy, /area/station/service/library) -"ftS" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt/dust, -/turf/open/floor/iron/herringbone, -/area/station/cargo/miningoffice) "ftU" = ( /obj/structure/cable, /obj/effect/turf_decal/siding/yellow, @@ -22074,6 +22134,13 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/station/cargo/miningoffice) +"fvD" = ( +/obj/effect/turf_decal/trimline/dark_red/filled/line{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "fvE" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/engine, @@ -22247,6 +22314,10 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"fxx" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "fxP" = ( /obj/machinery/computer/security/telescreen/entertainment/directional/west, /obj/structure/table/wood, @@ -22433,16 +22504,6 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/station/engineering/storage) -"fAj" = ( -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/iron/herringbone, -/area/station/cargo/miningoffice) "fAn" = ( /obj/machinery/holopad, /obj/effect/turf_decal/bot, @@ -23017,6 +23078,12 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/security/evidence) +"fIe" = ( +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 4 + }, +/turf/open/floor/iron/white, +/area/station/science/lobby) "fIg" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -23088,6 +23155,18 @@ }, /turf/open/floor/iron, /area/station/maintenance/department/crew_quarters/bar) +"fIU" = ( +/obj/structure/rack, +/obj/item/gun/energy/laser/carbine/practice{ + pixel_x = 3; + pixel_y = -3 + }, +/obj/item/gun/energy/laser/practice, +/obj/effect/turf_decal/bot, +/obj/machinery/firealarm/directional/east, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/science/auxlab/firing_range) "fIW" = ( /obj/structure/table, /obj/structure/bedsheetbin, @@ -23620,17 +23699,6 @@ }, /turf/open/floor/iron, /area/station/command/teleporter) -"fQC" = ( -/obj/structure/table, -/obj/item/mod/module/plasma_stabilizer, -/obj/item/mod/module/thermal_regulator, -/obj/effect/turf_decal/trimline/brown/filled/line{ - dir = 5 - }, -/obj/item/radio/intercom/directional/south, -/obj/item/mod/module/signlang_radio, -/turf/open/floor/iron/dark, -/area/station/security/office) "fQF" = ( /obj/effect/mapping_helpers/airlock/access/all/command/general, /obj/structure/cable, @@ -23798,16 +23866,6 @@ "fSW" = ( /turf/closed/indestructible/opshuttle, /area/station/science/ordnance/bomb) -"fTh" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/blobstart, -/obj/effect/turf_decal/tile/red/opposingcorners, -/obj/effect/turf_decal/tile/yellow/opposingcorners{ - dir = 1 - }, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/iron, -/area/station/service/kitchen/abandoned) "fTw" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/effect/turf_decal/bot, @@ -23848,6 +23906,12 @@ /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood, /area/station/service/library) +"fTE" = ( +/obj/machinery/cryo_cell{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured_large, +/area/station/medical/cryo) "fTF" = ( /obj/machinery/atmospherics/pipe/smart/simple/green/visible, /obj/structure/window/reinforced/spawner/directional/west, @@ -23916,12 +23980,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/commons/fitness/recreation) -"fUr" = ( -/obj/machinery/cryo_cell{ - dir = 8 - }, -/turf/open/floor/iron/dark/textured_large, -/area/station/medical/cryo) "fUF" = ( /obj/structure/table/reinforced, /obj/structure/window/reinforced/spawner/directional/east, @@ -24403,27 +24461,6 @@ /obj/effect/landmark/navigate_destination, /turf/open/floor/iron, /area/station/security/courtroom) -"gan" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/newscaster/directional/east, -/obj/effect/spawner/random/structure/table_fancy, -/obj/item/reagent_containers/cup/glass/bottle/beer{ - desc = "Whatever it is, it reeks of foul, putrid froth."; - list_reagents = list(/datum/reagent/consumable/ethanol/bacchus_blessing = 15); - name = "Delta-Down"; - pixel_x = 5; - pixel_y = 5 - }, -/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{ - pixel_x = -3; - pixel_y = 6 - }, -/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{ - pixel_x = -6; - pixel_y = 3 - }, -/turf/open/floor/wood, -/area/station/commons/dorms) "gat" = ( /obj/machinery/door/poddoor/preopen{ id = "brigprison"; @@ -24608,16 +24645,6 @@ }, /turf/open/floor/iron, /area/station/service/hydroponics) -"gco" = ( -/obj/effect/turf_decal/tile/brown/anticorner/contrasted{ - dir = 8 - }, -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "gcr" = ( /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron, @@ -25039,6 +25066,11 @@ /obj/effect/turf_decal/siding/white, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) +"ggW" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable, +/turf/open/floor/plating, +/area/station/security/lockers) "gho" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -25284,6 +25316,16 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/grimy, /area/station/tcommsat/computer) +"gkt" = ( +/obj/effect/turf_decal/caution/stand_clear, +/obj/effect/turf_decal/box, +/obj/machinery/door/poddoor/shutters{ + dir = 8; + id = "secmechbay"; + name = "Security Mech Bay Shutters" + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "gku" = ( /obj/machinery/meter, /obj/machinery/door/window/right/directional/west, @@ -25607,6 +25649,18 @@ }, /turf/open/floor/iron/dark, /area/station/maintenance/port) +"goa" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/iron, +/area/station/maintenance/starboard/aft) "goc" = ( /obj/machinery/keycard_auth/directional/south{ pixel_y = -38 @@ -25731,6 +25785,18 @@ /obj/structure/reflector/single, /turf/open/floor/plating, /area/station/engineering/supermatter/room) +"gpD" = ( +/obj/item/kirbyplants/random, +/obj/effect/turf_decal/tile/brown/half{ + dir = 8 + }, +/obj/machinery/light/directional/west, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/sign/poster/official/random/directional/west, +/turf/open/floor/iron/half{ + dir = 1 + }, +/area/station/cargo/miningoffice) "gpI" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -26105,6 +26171,13 @@ /obj/item/toy/cards/deck, /turf/open/floor/iron/grimy, /area/station/service/abandoned_gambling_den) +"gty" = ( +/obj/structure/table/reinforced, +/obj/item/folder/yellow, +/obj/item/gps/mining, +/obj/effect/turf_decal/tile/brown/anticorner/contrasted, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "gtG" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -26158,14 +26231,6 @@ }, /turf/open/floor/iron, /area/station/commons/storage/primary) -"guj" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/structure/disposalpipe/trunk{ - dir = 4 - }, -/obj/machinery/disposal/bin, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "gum" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -26562,11 +26627,6 @@ /obj/effect/mapping_helpers/mail_sorting/service/law_office, /turf/open/floor/plating, /area/station/maintenance/department/security) -"gzc" = ( -/obj/structure/table/wood, -/obj/item/aquarium_kit, -/turf/open/floor/carpet/red, -/area/station/hallway/secondary/service) "gzj" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/start/prisoner, @@ -26801,6 +26861,19 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron, /area/station/commons/dorms) +"gCa" = ( +/obj/effect/turf_decal/caution/stand_clear, +/obj/effect/turf_decal/box, +/obj/machinery/door/poddoor/shutters{ + dir = 8; + id = "secmechbay"; + name = "Security Mech Bay Shutters" + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "gCn" = ( /obj/structure/sign/warning/electric_shock/directional/east, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -27231,6 +27304,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/science/research) +"gHq" = ( +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/station/bitrunning/den) "gHt" = ( /obj/item/kirbyplants/random, /obj/machinery/button/door/directional/north{ @@ -27784,11 +27861,6 @@ }, /turf/open/floor/iron, /area/station/security/prison) -"gOH" = ( -/obj/effect/landmark/blobstart, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/plating, -/area/station/maintenance/solars/starboard/fore) "gOR" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -28163,16 +28235,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/medical/cryo) -"gTH" = ( -/obj/machinery/flasher/directional/south{ - id = "Isolation_Cell" - }, -/obj/machinery/light/small/broken/directional/south, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/security/prison/safe) "gTO" = ( /obj/structure/table/wood, /obj/item/crowbar/red, @@ -28342,6 +28404,11 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/commons/storage/primary) +"gVv" = ( +/obj/machinery/netpod, +/obj/effect/decal/cleanable/robot_debris, +/turf/open/floor/catwalk_floor/iron_dark, +/area/station/bitrunning/den) "gVx" = ( /obj/structure/cable, /obj/machinery/door/window/brigdoor/right/directional/south{ @@ -29375,13 +29442,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron/white/smooth_large, /area/station/medical/medbay) -"hkn" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "hkt" = ( /obj/effect/spawner/random/engineering/tank, /turf/open/floor/plating, @@ -29847,6 +29907,28 @@ /obj/machinery/newscaster/directional/north, /turf/open/floor/wood, /area/station/maintenance/starboard/aft) +"hrz" = ( +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/brown/corner{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/brown/corner{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron/dark/textured_large, +/area/station/bitrunning/den) "hrG" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, @@ -30090,14 +30172,6 @@ /obj/effect/turf_decal/trimline/blue/filled/line, /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) -"huS" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible, -/obj/effect/spawner/random/engineering/tracking_beacon, -/obj/effect/mapping_helpers/burnt_floor, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/iron, -/area/station/maintenance/department/electrical) "huX" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/disposalpipe/segment{ @@ -30336,6 +30410,13 @@ /obj/effect/turf_decal/tile/neutral/anticorner/contrasted, /turf/open/floor/iron, /area/station/maintenance/department/chapel) +"hxP" = ( +/obj/structure/bed/dogbed/renault, +/obj/machinery/newscaster/directional/south, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/mob/living/basic/pet/fox/renault, +/turf/open/floor/iron/dark, +/area/station/command/heads_quarters/captain) "hxS" = ( /turf/open/floor/carpet/royalblack, /area/station/service/chapel/office) @@ -30379,6 +30460,20 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"hyR" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 5 + }, +/obj/machinery/vending/wardrobe/sec_wardrobe, +/obj/machinery/button/door/directional/east{ + name = "Security Mech Garage Door Controls"; + id = "secmechbay"; + req_access = list("security") + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/security/lockers) "hza" = ( /obj/effect/turf_decal/tile/yellow{ dir = 8 @@ -30399,10 +30494,6 @@ }, /turf/open/floor/glass/reinforced, /area/station/maintenance/department/science/xenobiology) -"hzs" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "hzx" = ( /obj/machinery/firealarm/directional/west, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -31277,6 +31368,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/hos) +"hMp" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 1 + }, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/plating, +/area/station/maintenance/port) "hMx" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -31395,6 +31493,11 @@ }, /turf/open/floor/iron, /area/station/engineering/main) +"hOk" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/security/lockers) "hOw" = ( /obj/structure/chair/office{ dir = 4 @@ -32095,6 +32198,9 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/maintenance/department/science) +"hXg" = ( +/turf/closed/wall, +/area/station/bitrunning/den) "hXi" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -32764,6 +32870,13 @@ /obj/structure/window/reinforced/spawner/directional/south, /turf/open/space, /area/space/nearstation) +"idX" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/loading_area{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "iee" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -33024,16 +33137,6 @@ }, /turf/open/floor/plating, /area/station/medical/virology) -"iio" = ( -/obj/effect/turf_decal/tile/brown/half/contrasted{ - dir = 8 - }, -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "iiy" = ( /obj/structure/easel, /turf/open/floor/iron, @@ -33715,6 +33818,18 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"irx" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/duct, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/iron, +/area/station/maintenance/department/chapel) "irD" = ( /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/medical/general, @@ -33854,13 +33969,6 @@ /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron, /area/station/maintenance/port/fore) -"itC" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/mapping_helpers/broken_floor, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/maintenance/starboard/aft) "itF" = ( /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ dir = 6 @@ -34283,14 +34391,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/hallway/secondary/entry) -"izj" = ( -/obj/structure/disposalpipe/segment, -/obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/iron/herringbone, -/area/station/cargo/miningoffice) "izo" = ( /obj/structure/table/wood, /obj/item/gavelblock, @@ -34332,6 +34432,14 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/command/heads_quarters/hos) +"izK" = ( +/obj/machinery/door/airlock/mining{ + name = "Mining Dock" + }, +/obj/effect/mapping_helpers/airlock/access/all/supply/mining, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "izM" = ( /obj/structure/closet/crate/trashcart/laundry, /obj/effect/spawner/random/contraband/prison, @@ -34481,11 +34589,6 @@ }, /turf/open/floor/wood, /area/station/medical/psychology) -"iBH" = ( -/obj/structure/table/wood, -/obj/item/paper/fluff/jobs/engineering/frequencies, -/turf/open/floor/iron/grimy, -/area/station/tcommsat/computer) "iBO" = ( /obj/machinery/power/turbine/inlet_compressor, /turf/open/floor/engine, @@ -34609,6 +34712,14 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/service/abandoned_gambling_den) +"iDm" = ( +/obj/machinery/status_display/evac/directional/west, +/obj/structure/filingcabinet/chestdrawer, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/newscaster/directional/north, +/mob/living/simple_animal/parrot/poly, +/turf/open/floor/iron/dark, +/area/station/command/heads_quarters/ce) "iDq" = ( /turf/closed/wall/r_wall, /area/station/security/range) @@ -34876,6 +34987,12 @@ /obj/machinery/light/floor, /turf/open/floor/iron/dark, /area/station/command/bridge) +"iGF" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible/layer4, +/obj/machinery/air_sensor/engine_chamber, +/turf/open/floor/engine, +/area/station/engineering/supermatter) "iGI" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/maintenance_hatch{ @@ -34927,6 +35044,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/security/holding_cell) +"iHn" = ( +/obj/machinery/computer/mech_bay_power_console{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "iHq" = ( /obj/effect/turf_decal/trimline/neutral/warning{ dir = 10 @@ -35744,6 +35869,25 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/medical/coldroom) +"iTM" = ( +/obj/structure/table/reinforced, +/obj/item/stack/sheet/rglass{ + amount = 50; + pixel_x = 2; + pixel_y = -2 + }, +/obj/item/stock_parts/cell/emproof{ + pixel_x = 1; + pixel_y = 3 + }, +/obj/effect/turf_decal/bot, +/obj/machinery/newscaster/directional/east, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, +/obj/item/mod/module/magboot, +/obj/item/mod/module/signlang_radio, +/turf/open/floor/iron, +/area/station/engineering/storage) "iTW" = ( /obj/structure/closet/emcloset, /obj/effect/decal/cleanable/dirt, @@ -36022,15 +36166,6 @@ }, /turf/open/floor/iron, /area/station/engineering/lobby) -"iXd" = ( -/obj/effect/turf_decal/tile/brown/half/contrasted{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/start/shaft_miner, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "iXj" = ( /obj/effect/landmark/start/hangover, /obj/effect/turf_decal/bot, @@ -36100,14 +36235,6 @@ /obj/effect/mapping_helpers/airlock/access/all/security/general, /turf/open/floor/iron, /area/station/security/checkpoint/escape) -"iXE" = ( -/obj/structure/window/reinforced/spawner/directional/east, -/obj/structure/window/reinforced/spawner/directional/east, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/ai_monitored/aisat/exterior) "iXM" = ( /obj/structure/cable, /obj/item/kirbyplants/random, @@ -36287,6 +36414,17 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/cargo/miningoffice) +"jag" = ( +/obj/effect/decal/cleanable/blood/old, +/obj/effect/decal/cleanable/dirt, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/trimline/white/warning{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/mob/living/simple_animal/hostile/retaliate/goose/vomit, +/turf/open/floor/iron/dark, +/area/station/service/abandoned_gambling_den) "jap" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -36853,13 +36991,6 @@ /obj/structure/sign/warning/secure_area/directional/west, /turf/open/floor/plating, /area/station/engineering/atmos/mix) -"jfO" = ( -/obj/structure/closet/wardrobe/miner, -/obj/effect/decal/cleanable/dirt, -/obj/item/storage/backpack/satchel/explorer, -/obj/effect/turf_decal/bot, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "jfP" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -37025,6 +37156,7 @@ /obj/effect/turf_decal/trimline/red/filled/warning{ dir = 1 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/lockers) "jhs" = ( @@ -37483,13 +37615,6 @@ /obj/effect/turf_decal/tile/neutral/anticorner/contrasted, /turf/open/floor/iron, /area/station/security/courtroom) -"jnd" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/delivery, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/cargo/storage) "jni" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/airlock/access/all/science/robotics, @@ -37637,21 +37762,6 @@ /obj/item/clothing/suit/toggle/labcoat, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"joP" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/door/airlock/maintenance_hatch{ - name = "Cargo Maintenance" - }, -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/effect/mapping_helpers/airlock/access/all/supply/general, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/maintenance/fore) "joU" = ( /obj/structure/table, /obj/item/paper_bin, @@ -38046,6 +38156,13 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/science/xenobiology) +"juz" = ( +/obj/structure/cable, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/fore) "juF" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -38098,6 +38215,16 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central/aft) +"jvp" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/segment, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/delivery, +/obj/effect/turf_decal/tile/neutral/anticorner/contrasted, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/maintenance/fore) "jvq" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -38314,6 +38441,19 @@ /obj/effect/mapping_helpers/mail_sorting/medbay/chemistry, /turf/open/floor/iron/white, /area/station/medical/medbay) +"jyL" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/junction/yjunction{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/maintenance/fore) "jyP" = ( /obj/effect/turf_decal/siding/dark_blue{ dir = 8 @@ -38352,6 +38492,11 @@ /obj/effect/turf_decal/tile/neutral/full, /turf/open/floor/iron/dark/smooth_large, /area/station/security/evidence) +"jyZ" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "jzb" = ( /obj/machinery/door/poddoor/shutters{ dir = 4; @@ -38567,11 +38712,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/science/lobby) -"jBM" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "jCb" = ( /obj/machinery/computer/records/security{ dir = 8 @@ -38655,13 +38795,6 @@ /obj/item/pen, /turf/open/floor/wood, /area/station/service/library/abandoned) -"jCu" = ( -/obj/structure/closet/secure_closet/miner, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/delivery, -/obj/machinery/light/directional/north, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "jCv" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/hydroponics/constructable, @@ -39309,18 +39442,6 @@ /obj/effect/turf_decal/tile/blue/opposingcorners, /turf/open/floor/iron/white, /area/station/command/heads_quarters/cmo) -"jKY" = ( -/obj/effect/decal/cleanable/oil/streak, -/obj/machinery/camera/directional/south, -/obj/structure/table, -/obj/item/storage/toolbox/mechanical{ - pixel_y = 7 - }, -/obj/item/reagent_containers/cup/soda_cans/space_mountain_wind{ - pixel_x = 5 - }, -/turf/open/floor/iron/dark/smooth_large, -/area/station/bitrunning/den) "jLa" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/railing{ @@ -39903,19 +40024,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/medbay) -"jRc" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/power/apc/auto_name/directional/north, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "jRg" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, @@ -40100,6 +40208,19 @@ }, /turf/open/floor/iron, /area/station/maintenance/department/eva/abandoned) +"jTH" = ( +/obj/structure/table/glass, +/obj/machinery/status_display/ai/directional/west, +/obj/machinery/newscaster/directional/north, +/obj/effect/turf_decal/siding/dark_red, +/obj/item/storage/box/bandages{ + pixel_x = -6; + pixel_y = 6 + }, +/obj/item/reagent_containers/cup/bottle/morphine, +/obj/item/reagent_containers/syringe, +/turf/open/floor/iron/dark, +/area/station/security/execution/transfer) "jTI" = ( /obj/structure/table/wood, /obj/machinery/newscaster/directional/north, @@ -41658,6 +41779,17 @@ /obj/effect/turf_decal/tile/blue/opposingcorners, /turf/open/floor/iron/white, /area/station/medical/storage) +"knp" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/table/reinforced, +/obj/item/cigbutt/cigarbutt, +/obj/item/stack/cable_coil{ + pixel_x = -10; + pixel_y = 7 + }, +/obj/machinery/airalarm/directional/south, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "knu" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/green{ @@ -41864,6 +41996,18 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/grimy, /area/station/tcommsat/computer) +"kqJ" = ( +/obj/effect/turf_decal/tile/brown/anticorner/contrasted{ + dir = 1 + }, +/obj/effect/landmark/start/shaft_miner, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "kqM" = ( /obj/effect/turf_decal/stripes/corner{ dir = 1 @@ -42069,6 +42213,17 @@ /obj/structure/cable/layer3, /turf/open/floor/circuit/green, /area/station/ai_monitored/turret_protected/ai) +"kuj" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/effect/mapping_helpers/airlock/access/any/supply/bit_den, +/obj/machinery/door/airlock/mining/glass{ + name = "Bitrunning Den" + }, +/turf/open/floor/iron/dark/textured_large, +/area/station/bitrunning/den) "kun" = ( /obj/structure/lattice/catwalk, /obj/structure/cable, @@ -42616,13 +42771,6 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) -"kBE" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/table/wood, -/obj/item/radio/intercom/command, -/obj/item/paper/fluff/jobs/engineering/frequencies, -/turf/open/floor/carpet, -/area/station/command/meeting_room/council) "kBH" = ( /obj/machinery/status_display/evac/directional/west, /obj/machinery/chem_master, @@ -42766,15 +42914,6 @@ /obj/structure/chair/pew/right, /turf/open/floor/iron/chapel, /area/station/service/chapel) -"kDv" = ( -/obj/structure/bed/dogbed/runtime, -/obj/item/radio/intercom/directional/south, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 1 - }, -/mob/living/simple_animal/pet/cat/runtime, -/turf/open/floor/iron, -/area/station/command/heads_quarters/cmo) "kDB" = ( /obj/structure/plasticflaps/opaque, /obj/machinery/navbeacon{ @@ -43218,15 +43357,6 @@ /obj/structure/sign/warning/pods, /turf/closed/wall, /area/station/hallway/secondary/entry) -"kKx" = ( -/obj/effect/turf_decal/tile/brown/half{ - dir = 4 - }, -/obj/structure/cable, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/cargo/miningoffice) "kKy" = ( /obj/machinery/airalarm/directional/east, /obj/machinery/rnd/production/techfab/department/medical, @@ -43325,6 +43455,22 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) +"kLA" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/turf_decal/tile/brown/half{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/landmark/start/bitrunner, +/turf/open/floor/iron/half{ + dir = 1 + }, +/area/station/cargo/miningoffice) "kLI" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/firealarm/directional/north{ @@ -43853,18 +43999,6 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, /area/station/engineering/main) -"kTs" = ( -/obj/effect/turf_decal/tile/brown/anticorner/contrasted{ - dir = 1 - }, -/obj/effect/landmark/start/shaft_miner, -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "kTy" = ( /obj/structure/chair/office{ dir = 8 @@ -43914,6 +44048,18 @@ }, /turf/open/floor/iron, /area/station/maintenance/port) +"kUj" = ( +/obj/effect/decal/cleanable/oil/streak, +/obj/machinery/camera/directional/south, +/obj/structure/table, +/obj/item/storage/toolbox/mechanical{ + pixel_y = 7 + }, +/obj/item/reagent_containers/cup/soda_cans/space_mountain_wind{ + pixel_x = 5 + }, +/turf/open/floor/iron/dark/smooth_large, +/area/station/bitrunning/den) "kUn" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/tile/brown{ @@ -44000,15 +44146,6 @@ }, /turf/open/floor/iron, /area/station/maintenance/port/aft) -"kVw" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red/fourcorners, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/iron, -/area/station/service/kitchen/abandoned) "kVx" = ( /obj/machinery/door/airlock/highsecurity{ name = "Emergency Access" @@ -44778,22 +44915,6 @@ /mob/living/carbon/human/species/monkey, /turf/open/floor/engine, /area/station/science/genetics) -"lfC" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/table/reinforced, -/obj/effect/turf_decal/tile/brown/half/contrasted{ - dir = 1 - }, -/obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = 4 - }, -/obj/item/storage/toolbox/mechanical, -/obj/item/storage/belt/utility, -/turf/open/floor/iron, -/area/station/cargo/storage) "lfD" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/siding/dark_red{ @@ -45169,15 +45290,6 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/general, /turf/open/floor/iron, /area/station/maintenance/solars/starboard/fore) -"ljQ" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/effect/turf_decal/loading_area{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "ljS" = ( /obj/structure/cable, /obj/effect/spawner/structure/window/reinforced, @@ -45317,16 +45429,6 @@ /obj/machinery/light/directional/west, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"llj" = ( -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/turf/open/floor/iron/herringbone, -/area/station/cargo/miningoffice) "llm" = ( /obj/structure/chair/office/tactical{ dir = 8 @@ -45479,6 +45581,16 @@ }, /turf/open/floor/iron/dark/textured_large, /area/station/engineering/atmos/storage/gas) +"lni" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/plating, +/area/station/maintenance/department/chapel) "lnm" = ( /obj/structure/closet/secure_closet/captains, /obj/effect/turf_decal/stripes/line{ @@ -45854,16 +45966,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/maintenance/department/science) -"ltg" = ( -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/plating, -/area/station/maintenance/department/chapel) "ltr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -46316,8 +46418,19 @@ dir = 1 }, /obj/machinery/light/directional/north, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/lockers) +"lyx" = ( +/obj/effect/turf_decal/tile/brown/anticorner/contrasted{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "lyE" = ( /obj/structure/cable, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -46723,6 +46836,17 @@ }, /turf/open/floor/iron/dark, /area/station/command/corporate_showroom) +"lDu" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/table, +/obj/machinery/microwave{ + desc = "Cooks and boils stuff, somehow."; + pixel_x = -3; + pixel_y = 5 + }, +/obj/structure/sign/poster/official/random/directional/west, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "lDI" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -47289,6 +47413,11 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/rd) +"lJw" = ( +/obj/machinery/computer/quantum_console, +/obj/structure/extinguisher_cabinet/directional/west, +/turf/open/floor/iron/dark/smooth_corner, +/area/station/bitrunning/den) "lJB" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/directional/west, @@ -47666,12 +47795,6 @@ /obj/machinery/newscaster/directional/east, /turf/open/floor/carpet/blue, /area/station/commons/vacant_room/office) -"lNN" = ( -/obj/structure/bed/dogbed/mcgriff, -/obj/effect/turf_decal/tile/red/anticorner/contrasted, -/mob/living/basic/pet/dog/pug/mcgriff, -/turf/open/floor/iron, -/area/station/security/warden) "lNZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -47800,6 +47923,8 @@ /obj/effect/turf_decal/trimline/red/filled/line{ dir = 4 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/security/lockers) "lPM" = ( @@ -48125,12 +48250,6 @@ /obj/effect/turf_decal/tile/neutral/full, /turf/open/floor/iron/large, /area/station/medical/paramedic) -"lUW" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/red/fourcorners, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/iron, -/area/station/service/kitchen/abandoned) "lVi" = ( /obj/structure/closet/l3closet/virology, /obj/effect/turf_decal/bot, @@ -48581,11 +48700,6 @@ dir = 4 }, /area/station/hallway/secondary/entry) -"mcF" = ( -/obj/structure/window/reinforced/spawner/directional/west, -/obj/structure/window/reinforced/spawner/directional/west, -/turf/open/space, -/area/space/nearstation) "mcG" = ( /obj/machinery/button/door/directional/east{ id = "Dorm6"; @@ -48665,6 +48779,8 @@ /obj/effect/turf_decal/trimline/red/filled/warning{ dir = 1 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/security/lockers) "mdB" = ( @@ -49090,6 +49206,27 @@ "mjz" = ( /turf/closed/wall, /area/station/maintenance/starboard/lesser) +"mjH" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor, +/obj/item/folder/yellow{ + pixel_x = -6 + }, +/obj/item/pen{ + pixel_x = -6 + }, +/obj/effect/turf_decal/delivery, +/obj/machinery/door/window/right/directional/south{ + name = "Delivery Office Desk"; + req_access = list("shipping") + }, +/obj/structure/desk_bell{ + pixel_x = 7 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/cargo/sorting) "mjK" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/trimline/green/filled/corner{ @@ -49167,6 +49304,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/wood, /area/station/service/theater) +"mlv" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/tile/brown/anticorner/contrasted, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/cargo/sorting) "mlw" = ( /obj/effect/turf_decal/stripes/line{ dir = 5 @@ -49197,11 +49341,6 @@ "mlE" = ( /turf/closed/wall/r_wall, /area/station/ai_monitored/command/storage/eva) -"mlF" = ( -/obj/machinery/computer/quantum_console, -/obj/structure/extinguisher_cabinet/directional/west, -/turf/open/floor/iron/dark/smooth_corner, -/area/station/bitrunning/den) "mlM" = ( /obj/structure/table/wood, /obj/machinery/computer/records/medical/laptop, @@ -49275,16 +49414,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/space/basic, /area/space/nearstation) -"mmA" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/glass, -/obj/machinery/duct, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/basic/cockroach, -/turf/open/floor/iron, -/area/station/medical/abandoned) "mmM" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, @@ -49748,11 +49877,6 @@ /obj/effect/turf_decal/tile/yellow/fourcorners, /turf/open/floor/iron, /area/station/engineering/storage) -"mtL" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/status_display/evac/directional/north, -/turf/open/floor/plating, -/area/station/cargo/miningoffice) "mtO" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/tile/yellow{ @@ -49996,6 +50120,19 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"mwM" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/power/apc/auto_name/directional/north, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "mwR" = ( /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/medical/general, @@ -50506,13 +50643,6 @@ /obj/structure/cable, /turf/open/floor/engine, /area/station/maintenance/disposal/incinerator) -"mDm" = ( -/obj/machinery/quantum_server, -/obj/effect/turf_decal/bot/left, -/turf/open/floor/iron/dark/smooth_corner{ - dir = 4 - }, -/area/station/bitrunning/den) "mDo" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -50657,6 +50787,19 @@ /obj/effect/turf_decal/tile/neutral/opposingcorners, /turf/open/floor/iron, /area/station/maintenance/department/security) +"mEv" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/firealarm/directional/east, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/machinery/light/small/directional/east, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central/fore) "mEx" = ( /obj/structure/table/reinforced, /obj/item/clothing/suit/hazardvest, @@ -51458,17 +51601,6 @@ /obj/machinery/light_switch/directional/north, /turf/open/floor/iron/grimy, /area/station/tcommsat/computer) -"mOh" = ( -/obj/effect/decal/cleanable/blood/old, -/obj/effect/decal/cleanable/dirt, -/obj/effect/mapping_helpers/broken_floor, -/obj/effect/turf_decal/trimline/white/warning{ - dir = 8 - }, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/simple_animal/hostile/retaliate/goose/vomit, -/turf/open/floor/iron/dark, -/area/station/service/abandoned_gambling_den) "mOo" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/simple, /turf/open/floor/circuit/green/telecomms/mainframe, @@ -51849,11 +51981,6 @@ "mTA" = ( /turf/closed/wall/r_wall, /area/station/security/holding_cell) -"mTB" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/north, -/turf/open/space, -/area/space/nearstation) "mTT" = ( /obj/machinery/holopad, /obj/structure/cable, @@ -52026,6 +52153,12 @@ /obj/effect/spawner/structure/window/reinforced/plasma, /turf/open/floor/plating, /area/station/engineering/supermatter) +"mWs" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/fore) "mWy" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/disposalpipe/segment, @@ -52596,17 +52729,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port/fore) -"neT" = ( -/obj/effect/turf_decal/trimline/neutral/mid_joiner{ - dir = 4 - }, -/obj/structure/table/reinforced, -/obj/item/surgery_tray/full/morgue, -/obj/effect/turf_decal/tile/dark_blue/half/contrasted{ - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/medical/morgue) "nfd" = ( /obj/machinery/portable_atmospherics/canister/plasma, /turf/open/floor/engine/plasma, @@ -52745,17 +52867,6 @@ /obj/effect/spawner/random/trash/hobo_squat, /turf/open/floor/plating, /area/station/maintenance/department/chapel) -"nhj" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/structure/table, -/obj/machinery/microwave{ - desc = "Cooks and boils stuff, somehow."; - pixel_x = -3; - pixel_y = 5 - }, -/obj/structure/sign/poster/official/random/directional/west, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "nhm" = ( /turf/closed/wall/r_wall, /area/station/maintenance/starboard/lesser) @@ -53024,6 +53135,22 @@ }, /turf/open/floor/iron, /area/station/commons/fitness/recreation) +"nkO" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/turf_decal/tile/brown/half/contrasted{ + dir = 4 + }, +/obj/effect/turf_decal/delivery, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/turf/open/floor/iron, +/area/station/maintenance/starboard/fore) "nkU" = ( /obj/effect/turf_decal/tile/blue/half/contrasted, /turf/open/floor/iron/dark, @@ -53525,7 +53652,12 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible, /obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible/layer4, -/obj/structure/sign/warning/secure_area/directional/west, +/obj/machinery/airalarm/directional/west, +/obj/effect/mapping_helpers/airalarm/engine_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "engine" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, /turf/open/floor/iron, /area/station/engineering/supermatter/room) "nsd" = ( @@ -53643,12 +53775,6 @@ /obj/machinery/light/small/directional/north, /turf/open/floor/iron/dark, /area/station/commons/fitness/recreation) -"ntU" = ( -/obj/structure/table/reinforced, -/obj/machinery/microwave/engineering/cell_included, -/obj/structure/sign/poster/random/directional/west, -/turf/open/floor/wood, -/area/station/engineering/break_room) "ntX" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 1 @@ -54357,6 +54483,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/science/breakroom) +"nCY" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/cargo/sorting) "nDk" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/conveyor{ @@ -54476,12 +54609,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/maintenance/port) -"nEE" = ( -/obj/machinery/netpod, -/obj/structure/sign/poster/random/directional/north, -/obj/effect/decal/cleanable/cobweb/cobweb2, -/turf/open/floor/catwalk_floor/iron_dark, -/area/station/bitrunning/den) "nEJ" = ( /obj/structure/cable, /obj/effect/turf_decal/trimline/yellow/line, @@ -54496,6 +54623,9 @@ /obj/structure/sign/warning/electric_shock/directional/east, /turf/open/space/basic, /area/space) +"nEZ" = ( +/turf/closed/wall/r_wall, +/area/station/security/mechbay) "nFb" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/generic_maintenance_landmark, @@ -54872,18 +55002,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/secondary/entry) -"nJF" = ( -/obj/machinery/navbeacon{ - codes_txt = "patrol;next_patrol=hall12"; - location = "hall11" - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/simple_animal/bot/secbot/beepsky/officer, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "nJK" = ( /obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume/incinerator_ordmix{ dir = 1 @@ -55038,6 +55156,15 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"nMi" = ( +/obj/effect/turf_decal/tile/brown/half{ + dir = 4 + }, +/obj/structure/cable, +/turf/open/floor/iron/half{ + dir = 1 + }, +/area/station/cargo/miningoffice) "nMp" = ( /obj/machinery/atmospherics/pipe/smart/manifold/yellow/visible, /obj/machinery/meter, @@ -56154,6 +56281,15 @@ }, /turf/open/floor/plating, /area/station/science/robotics/mechbay) +"occ" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/computer/order_console/mining, +/obj/item/radio/intercom/directional/west, +/obj/machinery/firealarm/directional/west{ + pixel_y = -9 + }, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "ocd" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/flora/bush/flowers_yw/style_random, @@ -56848,24 +56984,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/security/prison/garden) -"okN" = ( -/obj/effect/turf_decal/siding/thinplating_new/dark{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/trimline/brown/line{ - dir = 8 - }, -/obj/effect/decal/cleanable/generic, -/obj/effect/decal/cleanable/dirt/dust, -/obj/effect/landmark/start/bitrunner, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/iron/dark/textured_large, -/area/station/bitrunning/den) "okV" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/reagent_dispensers/plumbed{ @@ -57130,12 +57248,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) -"onA" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) "onK" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -57575,6 +57687,15 @@ /obj/machinery/light/small/red/directional/north, /turf/open/floor/iron/dark/smooth_large, /area/station/service/chapel/funeral) +"ove" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red/fourcorners, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/iron, +/area/station/service/kitchen/abandoned) "ovf" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -57676,6 +57797,14 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/command/teleporter) +"own" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible, +/obj/effect/spawner/random/engineering/tracking_beacon, +/obj/effect/mapping_helpers/burnt_floor, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/iron, +/area/station/maintenance/department/electrical) "owu" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -57716,8 +57845,12 @@ }, /obj/machinery/airalarm/directional/west, /obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnanceburn" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, /turf/open/floor/iron/dark, -/area/station/science/ordnance/burnchamber) +/area/station/science/ordnance) "owY" = ( /obj/structure/table/reinforced, /obj/item/stack/sheet/iron{ @@ -57731,13 +57864,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/maintenance/port) -"owZ" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/structure/table, -/obj/item/storage/medkit/regular, -/obj/machinery/light/directional/west, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "oxb" = ( /obj/machinery/duct, /obj/effect/turf_decal/siding/white, @@ -57981,28 +58107,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/grimy, /area/station/command/heads_quarters/captain/private) -"oAV" = ( -/obj/effect/turf_decal/siding/thinplating_new/dark{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/brown/corner{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/brown/corner{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/iron/dark/textured_large, -/area/station/bitrunning/den) "oAW" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -58188,6 +58292,12 @@ "oDE" = ( /turf/closed/wall, /area/station/medical/cryo) +"oDJ" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/delivery, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/iron, +/area/station/science/research/abandoned) "oDR" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -58308,14 +58418,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/maintenance/department/medical/morgue) -"oFk" = ( -/obj/structure/cable, -/obj/effect/decal/cleanable/dirt, -/obj/effect/spawner/random/structure/steam_vent, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) "oFr" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -58612,6 +58714,14 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/security/evidence) +"oKn" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/mob/living/basic/cockroach, +/turf/open/floor/iron/dark, +/area/station/service/abandoned_gambling_den) "oKr" = ( /turf/closed/wall, /area/station/security/checkpoint/supply) @@ -58892,6 +59002,11 @@ /obj/machinery/light/floor, /turf/open/floor/iron/dark, /area/station/ai_monitored/aisat/exterior) +"oNE" = ( +/obj/effect/landmark/blobstart, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/plating, +/area/station/maintenance/solars/starboard/fore) "oNF" = ( /obj/effect/turf_decal/siding/blue, /obj/effect/turf_decal/tile/blue/opposingcorners, @@ -59627,6 +59742,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/grimy, /area/station/command/heads_quarters/hos) +"oYr" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/door/firedoor, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "oYs" = ( /turf/closed/wall, /area/station/maintenance/port/fore) @@ -60189,6 +60313,13 @@ /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"pfs" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/plating, +/area/station/maintenance/port/fore) "pfA" = ( /obj/structure/table/reinforced, /obj/item/assembly/timer, @@ -60331,6 +60462,23 @@ /obj/machinery/newscaster/directional/south, /turf/open/floor/iron, /area/station/engineering/supermatter/room) +"pgZ" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/machinery/button/door/directional/north{ + id = "secmechbay"; + name = "Security Mech Garage Door Controls"; + req_access = list("security") + }, +/obj/effect/turf_decal/trimline/dark_red/filled/line{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "phn" = ( /obj/structure/cable, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ @@ -60424,6 +60572,7 @@ /obj/effect/turf_decal/trimline/red/filled/line{ dir = 1 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/lockers) "phX" = ( @@ -61216,16 +61365,6 @@ /obj/structure/cable, /turf/open/floor/circuit/green, /area/station/ai_monitored/turret_protected/ai_upload) -"ptA" = ( -/obj/structure/cable, -/obj/structure/table/reinforced, -/obj/effect/turf_decal/delivery, -/obj/machinery/power/apc/auto_name/directional/east, -/obj/item/mod/module/tether, -/obj/item/mod/module/tether, -/obj/item/stack/sheet/plasteel/fifty, -/turf/open/floor/iron, -/area/station/engineering/storage) "ptC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -61286,6 +61425,13 @@ }, /turf/open/floor/iron, /area/station/engineering/main) +"put" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/maintenance/starboard/aft) "puJ" = ( /obj/machinery/suit_storage_unit/standard_unit, /obj/effect/turf_decal/delivery, @@ -61568,21 +61714,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/hallway/secondary/exit/departure_lounge) -"pxS" = ( -/obj/structure/chair{ - dir = 4 - }, -/obj/effect/turf_decal/tile/brown/half{ - dir = 8 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/landmark/start/bitrunner, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/cargo/miningoffice) "pxT" = ( /obj/effect/spawner/random/structure/crate, /turf/open/floor/plating, @@ -61776,6 +61907,15 @@ }, /turf/open/floor/iron, /area/station/service/kitchen/abandoned) +"pAa" = ( +/obj/structure/chair/office{ + dir = 4 + }, +/obj/effect/turf_decal/tile/brown/half/contrasted, +/obj/effect/decal/cleanable/dirt, +/obj/effect/landmark/start/shaft_miner, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "pAd" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -61950,10 +62090,29 @@ }, /turf/open/floor/wood, /area/station/service/lawoffice) +"pBN" = ( +/obj/effect/turf_decal/tile/brown/half/contrasted{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "pBY" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/service/abandoned_gambling_den) +"pCr" = ( +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 4; + id = "chemisttop"; + name = "Pharmacy Shutters" + }, +/obj/machinery/smartfridge/chemistry/preloaded, +/obj/machinery/door/firedoor, +/turf/open/floor/iron/white, +/area/station/medical/pharmacy) "pCy" = ( /obj/structure/table, /obj/item/clipboard, @@ -62048,13 +62207,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) -"pDy" = ( -/obj/machinery/cryo_cell{ - dir = 8 +"pDz" = ( +/obj/machinery/quantum_server, +/obj/effect/turf_decal/bot/left, +/turf/open/floor/iron/dark/smooth_corner{ + dir = 4 }, -/obj/machinery/status_display/ai/directional/south, -/turf/open/floor/iron/dark/textured_large, -/area/station/medical/cryo) +/area/station/bitrunning/den) "pDE" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -62408,6 +62567,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) +"pGR" = ( +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron/herringbone, +/area/station/cargo/miningoffice) "pHa" = ( /obj/structure/lattice, /obj/structure/sign/warning/directional/west, @@ -63284,13 +63447,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/science/robotics/lab) -"pRp" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/mapping_helpers/broken_floor, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) "pRy" = ( /obj/effect/turf_decal/siding/green, /obj/structure/window/reinforced/spawner/directional/south, @@ -63498,39 +63654,6 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/grimy, /area/station/command/heads_quarters/hos) -"pTz" = ( -/obj/structure/table/reinforced, -/obj/machinery/door/firedoor, -/obj/structure/desk_bell{ - pixel_x = 7; - pixel_y = 6 - }, -/obj/item/folder/yellow{ - pixel_x = -3; - pixel_y = -6 - }, -/obj/item/pen{ - pixel_x = -3; - pixel_y = -2 - }, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 4; - id = "chemisttop"; - name = "Pharmacy Shutters" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/machinery/door/window/left/directional/west{ - name = "Pharmacy Desk"; - req_access = list("pharmacy"); - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/medical/pharmacy) "pTB" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, @@ -63651,17 +63774,6 @@ }, /turf/open/floor/iron/dark/corner, /area/station/engineering/atmos/pumproom) -"pUs" = ( -/obj/machinery/door/firedoor, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/effect/mapping_helpers/airlock/access/any/supply/bit_den, -/obj/machinery/door/airlock/mining/glass{ - name = "Bitrunning Den" - }, -/turf/open/floor/iron/dark/textured_large, -/area/station/bitrunning/den) "pUw" = ( /obj/machinery/holopad, /obj/effect/turf_decal/bot, @@ -64094,6 +64206,17 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/maintenance/port) +"pZf" = ( +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/machinery/status_display/door_timer{ + id = "Isolation_Cell"; + name = "Isolation Cell"; + pixel_x = -32 + }, +/turf/open/floor/iron, +/area/station/security/execution/transfer) "pZi" = ( /obj/structure/training_machine, /obj/item/target/alien, @@ -64250,6 +64373,21 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/iron, /area/station/commons/toilet/locker) +"qbd" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/turf_decal/tile/brown/half{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/landmark/start/bitrunner, +/turf/open/floor/iron/half{ + dir = 1 + }, +/area/station/cargo/miningoffice) "qbg" = ( /obj/machinery/duct, /obj/structure/disposalpipe/segment{ @@ -64881,18 +65019,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/command/bridge) -"qko" = ( -/obj/item/kirbyplants/random, -/obj/effect/turf_decal/tile/brown/half{ - dir = 8 - }, -/obj/machinery/light/directional/west, -/obj/effect/decal/cleanable/dirt/dust, -/obj/structure/sign/poster/official/random/directional/west, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/cargo/miningoffice) "qkv" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -65049,21 +65175,6 @@ }, /turf/open/floor/plating, /area/station/engineering/supermatter/room) -"qmT" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/turf_decal/tile/brown/half/contrasted{ - dir = 4 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/maintenance/starboard/fore) "qnc" = ( /obj/machinery/firealarm/directional/south, /obj/effect/turf_decal/tile/blue{ @@ -65235,6 +65346,14 @@ /obj/machinery/firealarm/directional/east, /turf/open/floor/iron, /area/station/commons/vacant_room/commissary) +"qpd" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/loading_area{ + dir = 1 + }, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "qpg" = ( /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -65491,22 +65610,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/science/xenobiology) -"qsF" = ( -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/brown/line, -/obj/effect/turf_decal/trimline/brown/line{ - dir = 1 - }, -/obj/machinery/power/apc/auto_name/directional/west, -/obj/structure/cable, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, -/turf/open/floor/iron/dark/textured_large, -/area/station/bitrunning/den) "qsN" = ( /obj/structure/chair{ dir = 4 @@ -65586,6 +65689,21 @@ /obj/effect/turf_decal/tile/neutral/full, /turf/open/floor/iron/dark/smooth_large, /area/station/security/detectives_office) +"quh" = ( +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/brown/line, +/obj/effect/turf_decal/trimline/brown/line{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/machinery/holopad, +/turf/open/floor/iron/dark/textured_large, +/area/station/bitrunning/den) "qul" = ( /obj/structure/chair/stool/bar/directional/south, /turf/open/floor/wood, @@ -66328,6 +66446,17 @@ /obj/item/circuitboard/machine/chem_master, /turf/open/floor/iron/grimy, /area/station/maintenance/port/fore) +"qDw" = ( +/obj/structure/table, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, +/obj/effect/turf_decal/trimline/brown/filled/line{ + dir = 5 + }, +/obj/item/radio/intercom/directional/south, +/obj/item/mod/module/signlang_radio, +/turf/open/floor/iron/dark, +/area/station/security/office) "qDI" = ( /obj/effect/turf_decal/stripes/line{ dir = 9 @@ -67415,6 +67544,14 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/fore) +"qQy" = ( +/obj/effect/turf_decal/tile/brown/half/contrasted{ + dir = 4 + }, +/obj/structure/table/reinforced, +/obj/item/flashlight/lamp, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "qQE" = ( /obj/effect/turf_decal/delivery, /turf/open/floor/iron, @@ -67678,6 +67815,27 @@ /obj/item/shovel/spade, /turf/open/floor/iron/dark, /area/station/service/hydroponics/garden/abandoned) +"qVa" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/newscaster/directional/east, +/obj/effect/spawner/random/structure/table_fancy, +/obj/item/reagent_containers/cup/glass/bottle/beer{ + desc = "Whatever it is, it reeks of foul, putrid froth."; + list_reagents = list(/datum/reagent/consumable/ethanol/bacchus_blessing = 15); + name = "Delta-Down"; + pixel_x = 5; + pixel_y = 5 + }, +/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{ + pixel_x = -3; + pixel_y = 6 + }, +/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{ + pixel_x = -6; + pixel_y = 3 + }, +/turf/open/floor/wood, +/area/station/commons/dorms) "qVf" = ( /obj/structure/chair, /obj/effect/decal/cleanable/blood/splatter, @@ -68421,13 +68579,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) -"rgC" = ( -/obj/structure/table/reinforced, -/obj/item/folder/yellow, -/obj/item/gps/mining, -/obj/effect/turf_decal/tile/brown/anticorner/contrasted, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "rgG" = ( /obj/structure/closet/secure_closet/engineering_personal, /obj/effect/decal/cleanable/dirt, @@ -68570,6 +68721,19 @@ }, /turf/open/floor/iron, /area/station/medical/virology) +"rid" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/structure/disposalpipe/segment, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/door/firedoor, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "riq" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/grille/broken, @@ -68637,16 +68801,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron/white, /area/station/medical/medbay) -"riZ" = ( -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 4; - id = "chemisttop"; - name = "Pharmacy Shutters" - }, -/obj/machinery/smartfridge/chemistry/preloaded, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/white, -/area/station/medical/pharmacy) "rjd" = ( /obj/structure/table/wood, /obj/item/flashlight/lamp/green, @@ -69061,19 +69215,6 @@ /obj/machinery/light/dim/directional/east, /turf/open/floor/iron/dark, /area/station/tcommsat/computer) -"rmH" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/door/firedoor, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "rmI" = ( /obj/structure/table/reinforced, /obj/item/electronics/apc, @@ -69353,14 +69494,6 @@ }, /turf/open/floor/iron, /area/station/science/xenobiology) -"rqN" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 8 - }, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/plating, -/area/station/maintenance/port) "rqV" = ( /obj/machinery/dna_infuser, /obj/item/infuser_book, @@ -70053,16 +70186,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/cargo/storage) -"rAl" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/obj/machinery/conveyor{ - id = "cargodisposals" - }, -/turf/open/floor/plating, -/area/station/cargo/sorting) "rAm" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/tile/yellow/half/contrasted{ @@ -70376,6 +70499,14 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/atmos/pumproom) +"rFg" = ( +/obj/structure/cable, +/obj/effect/decal/cleanable/dirt, +/obj/effect/spawner/random/structure/steam_vent, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/fore) "rFm" = ( /obj/structure/window/reinforced/spawner/directional/south, /obj/structure/bed/medical/emergency, @@ -70871,6 +71002,22 @@ /obj/effect/turf_decal/tile/neutral/full, /turf/open/floor/iron/large, /area/station/hallway/secondary/exit/departure_lounge) +"rLB" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/table/reinforced, +/obj/effect/turf_decal/tile/brown/half/contrasted{ + dir = 1 + }, +/obj/item/storage/box/bandages{ + pixel_x = 4; + pixel_y = 6 + }, +/obj/item/storage/toolbox/mechanical, +/obj/item/storage/belt/utility, +/turf/open/floor/iron, +/area/station/cargo/storage) "rLL" = ( /obj/structure/filingcabinet/chestdrawer, /obj/machinery/newscaster/directional/north, @@ -70912,6 +71059,21 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos) +"rMj" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/door/airlock/maintenance_hatch{ + name = "Cargo Maintenance" + }, +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/effect/mapping_helpers/airlock/access/all/supply/general, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/maintenance/fore) "rMn" = ( /obj/structure/table/wood, /obj/effect/spawner/random/techstorage/arcade_boards, @@ -71176,6 +71338,14 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/science/research) +"rPb" = ( +/obj/machinery/light/directional/north, +/obj/effect/turf_decal/trimline/dark_red/filled/line{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "rPc" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -71218,6 +71388,13 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/fore) +"rPi" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "rPj" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/landmark/start/hangover, @@ -71361,11 +71538,6 @@ /obj/structure/mirror/directional/west, /turf/open/floor/wood, /area/station/maintenance/port/aft) -"rQF" = ( -/obj/machinery/netpod, -/obj/effect/decal/cleanable/robot_debris, -/turf/open/floor/catwalk_floor/iron_dark, -/area/station/bitrunning/den) "rQI" = ( /obj/machinery/airlock_sensor/incinerator_atmos{ pixel_x = 24 @@ -71600,6 +71772,9 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron, /area/station/cargo/lobby) +"rTB" = ( +/turf/open/floor/iron, +/area/station/cargo/storage) "rTG" = ( /obj/structure/cable, /obj/structure/disposalpipe/sorting/mail{ @@ -71667,14 +71842,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/science/xenobiology) -"rUi" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/effect/turf_decal/loading_area{ - dir = 1 - }, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "rUj" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/preopen{ @@ -71724,16 +71891,6 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/station/maintenance/fore) -"rUV" = ( -/obj/structure/cable, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/maintenance/fore) "rUW" = ( /obj/item/kirbyplants/organic/plant21, /obj/effect/turf_decal/stripes/line{ @@ -71823,8 +71980,6 @@ /turf/open/floor/iron/white, /area/station/science/research) "rVM" = ( -/obj/machinery/airalarm/directional/north, -/obj/effect/mapping_helpers/airalarm/engine_access, /turf/open/floor/engine, /area/station/engineering/supermatter) "rVX" = ( @@ -72020,6 +72175,12 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/engineering/atmos) +"rYp" = ( +/obj/structure/closet/secure_closet/miner, +/obj/effect/turf_decal/delivery, +/obj/structure/extinguisher_cabinet/directional/north, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "rYA" = ( /turf/closed/wall, /area/station/maintenance/department/security) @@ -72356,18 +72517,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/service/chapel) -"scv" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment, -/obj/machinery/camera/directional/east{ - c_tag = "Cargo Bay - Delivery Office"; - name = "cargo camera" - }, -/obj/effect/turf_decal/tile/brown, -/obj/machinery/light/directional/east, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/cargo/sorting) "scy" = ( /obj/machinery/atmospherics/components/trinary/mixer{ dir = 4 @@ -72525,6 +72674,21 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"seX" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/sign/nanotrasen{ + pixel_y = 32 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central/fore) "sfc" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/shutters/preopen{ @@ -72675,15 +72839,6 @@ }, /turf/open/space/basic, /area/space) -"sgK" = ( -/obj/effect/turf_decal/tile/brown/half/contrasted{ - dir = 8 - }, -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "sgZ" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -73380,13 +73535,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/primary/central/aft) -"sqW" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/cargo/sorting) "sqX" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -73562,10 +73710,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/medical/pharmacy) -"stf" = ( -/obj/structure/disposalpipe/segment, -/turf/open/floor/iron/herringbone, -/area/station/cargo/miningoffice) "stp" = ( /obj/machinery/airalarm/directional/west, /obj/effect/turf_decal/trimline/brown/filled/line{ @@ -74047,6 +74191,16 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"syW" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/machinery/conveyor{ + id = "cargodisposals" + }, +/turf/open/floor/plating, +/area/station/cargo/sorting) "sze" = ( /turf/open/floor/iron/cafeteria, /area/station/security/prison/mess) @@ -74208,6 +74362,14 @@ /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron, /area/station/maintenance/department/medical/morgue) +"sAL" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/machinery/disposal/bin, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "sAU" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -74374,23 +74536,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/half, /area/station/service/hydroponics) -"sCW" = ( -/obj/machinery/door/firedoor, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/door/airlock/mining/glass{ - name = "Delivery Office" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/effect/mapping_helpers/airlock/access/any/supply/mining, -/obj/effect/mapping_helpers/airlock/access/any/supply/shipping, -/obj/effect/mapping_helpers/airlock/access/any/supply/bit_den, -/turf/open/floor/iron, -/area/station/cargo/sorting) "sCY" = ( /obj/structure/cable, /obj/machinery/power/tracker, @@ -75074,9 +75219,6 @@ /obj/structure/sign/poster/official/build/directional/north, /turf/open/floor/iron, /area/station/science/robotics/mechbay) -"sLg" = ( -/turf/open/floor/iron, -/area/station/cargo/storage) "sLx" = ( /obj/effect/decal/cleanable/generic, /turf/open/floor/iron/grimy, @@ -75163,6 +75305,16 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"sMG" = ( +/obj/machinery/flasher/directional/south{ + id = "Isolation_Cell" + }, +/obj/machinery/light/small/broken/directional/south, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/security/prison/safe) "sMN" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -75244,18 +75396,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/engineering/main) -"sNP" = ( -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/duct, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/iron, -/area/station/maintenance/department/chapel) "sOi" = ( /obj/machinery/portable_atmospherics/pump, /obj/effect/turf_decal/bot, @@ -75270,6 +75410,15 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/service/abandoned_gambling_den/gaming) +"sOp" = ( +/obj/structure/table/glass, +/obj/item/surgery_tray/full, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/item/clothing/gloves/latex, +/obj/item/clothing/suit/apron/surgical, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/medical/surgery/theatre) "sOs" = ( /obj/structure/chair/pew/left, /turf/open/floor/iron/chapel{ @@ -75592,12 +75741,6 @@ /obj/effect/spawner/random/trash/graffiti, /turf/open/floor/plating, /area/station/maintenance/port/fore) -"sSx" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/delivery, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/iron, -/area/station/science/research/abandoned) "sSH" = ( /obj/effect/turf_decal/tile/green/half/contrasted{ dir = 8 @@ -76071,6 +76214,11 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, /area/station/science/ordnance/office) +"sYn" = ( +/obj/machinery/netpod, +/obj/machinery/airalarm/directional/east, +/turf/open/floor/catwalk_floor/iron_dark, +/area/station/bitrunning/den) "sYw" = ( /obj/effect/landmark/start/hangover, /obj/effect/landmark/event_spawn, @@ -76308,6 +76456,7 @@ /obj/effect/turf_decal/trimline/red/filled/line{ dir = 1 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/lockers) "tch" = ( @@ -76348,14 +76497,6 @@ /obj/machinery/light/directional/south, /turf/open/floor/iron, /area/station/engineering/supermatter/room) -"tcB" = ( -/obj/machinery/door/airlock/mining{ - name = "Mining Dock" - }, -/obj/effect/mapping_helpers/airlock/access/all/supply/mining, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "tcG" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -76573,6 +76714,13 @@ }, /turf/open/floor/iron, /area/station/cargo/storage) +"tfJ" = ( +/obj/machinery/cryo_cell{ + dir = 8 + }, +/obj/machinery/status_display/ai/directional/south, +/turf/open/floor/iron/dark/textured_large, +/area/station/medical/cryo) "tfK" = ( /obj/item/kirbyplants/random, /obj/machinery/status_display/evac/directional/east, @@ -76585,12 +76733,6 @@ /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron/white, /area/station/medical/paramedic) -"tfO" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/east, -/turf/open/space, -/area/space/nearstation) "tgl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -76742,14 +76884,6 @@ /obj/effect/turf_decal/trimline/green/filled/corner, /turf/open/floor/iron/white, /area/station/medical/virology) -"thZ" = ( -/obj/machinery/status_display/evac/directional/west, -/obj/structure/filingcabinet/chestdrawer, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/machinery/newscaster/directional/north, -/mob/living/simple_animal/parrot/poly, -/turf/open/floor/iron/dark, -/area/station/command/heads_quarters/ce) "tip" = ( /obj/structure/rack, /obj/item/aicard, @@ -76798,6 +76932,12 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/cargo/storage) +"tjo" = ( +/obj/machinery/light/directional/south, +/obj/machinery/byteforge, +/obj/effect/turf_decal/box, +/turf/open/floor/iron/dark/smooth_large, +/area/station/bitrunning/den) "tjp" = ( /obj/structure/table/reinforced, /obj/item/storage/toolbox/mechanical, @@ -77056,13 +77196,6 @@ /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron, /area/station/hallway/primary/central/aft) -"toy" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/iron/herringbone, -/area/station/cargo/miningoffice) "toB" = ( /obj/machinery/light/directional/west, /obj/effect/turf_decal/stripes/line{ @@ -77400,14 +77533,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos) -"tsx" = ( -/obj/structure/table/glass, -/obj/item/surgery_tray/full, -/obj/item/clothing/gloves/latex, -/obj/item/clothing/suit/apron/surgical, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/medical/surgery/theatre) "tsz" = ( /turf/open/floor/plating, /area/station/service/abandoned_gambling_den/gaming) @@ -77635,6 +77760,16 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/science/xenobiology) +"tum" = ( +/obj/structure/cable, +/obj/structure/table/reinforced, +/obj/effect/turf_decal/delivery, +/obj/machinery/power/apc/auto_name/directional/east, +/obj/item/mod/module/tether, +/obj/item/mod/module/tether, +/obj/item/stack/sheet/plasteel/fifty, +/turf/open/floor/iron, +/area/station/engineering/storage) "tup" = ( /obj/machinery/door/airlock/maintenance_hatch{ name = "Theater Maintenance" @@ -78572,25 +78707,6 @@ }, /turf/open/floor/iron/dark, /area/station/medical/morgue) -"tGm" = ( -/obj/structure/table/reinforced, -/obj/item/stack/sheet/rglass{ - amount = 50; - pixel_x = 2; - pixel_y = -2 - }, -/obj/item/stock_parts/cell/emproof{ - pixel_x = 1; - pixel_y = 3 - }, -/obj/effect/turf_decal/bot, -/obj/machinery/newscaster/directional/east, -/obj/item/mod/module/plasma_stabilizer, -/obj/item/mod/module/thermal_regulator, -/obj/item/mod/module/magboot, -/obj/item/mod/module/signlang_radio, -/turf/open/floor/iron, -/area/station/engineering/storage) "tGq" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, @@ -78843,6 +78959,18 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron, /area/station/engineering/supermatter/room) +"tJp" = ( +/obj/structure/table, +/obj/effect/turf_decal/tile/brown/half{ + dir = 4 + }, +/obj/item/clipboard, +/obj/item/toy/figure/miner, +/obj/machinery/light/directional/south, +/turf/open/floor/iron/half{ + dir = 1 + }, +/area/station/cargo/miningoffice) "tJt" = ( /obj/structure/table/wood, /obj/item/paper_bin, @@ -79117,16 +79245,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/science/server) -"tNn" = ( -/obj/effect/turf_decal/tile/brown/anticorner/contrasted{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "tNq" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -79185,6 +79303,17 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"tNU" = ( +/obj/effect/turf_decal/trimline/neutral/mid_joiner{ + dir = 4 + }, +/obj/structure/table/reinforced, +/obj/item/surgery_tray/full/morgue, +/obj/effect/turf_decal/tile/dark_blue/half/contrasted{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/medical/morgue) "tNV" = ( /obj/machinery/door/firedoor, /obj/structure/cable, @@ -80090,6 +80219,22 @@ /obj/structure/window/reinforced/spawner/directional/west, /turf/open/floor/carpet/blue, /area/station/commons/vacant_room/office) +"tYI" = ( +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/brown/line, +/obj/effect/turf_decal/trimline/brown/line{ + dir = 1 + }, +/obj/machinery/power/apc/auto_name/directional/west, +/obj/structure/cable, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 4 + }, +/turf/open/floor/iron/dark/textured_large, +/area/station/bitrunning/den) "tYL" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -80170,14 +80315,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/secondary/entry) -"uao" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, -/obj/structure/disposalpipe/segment, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/duct, -/mob/living/basic/goat/pete, -/turf/open/floor/iron/freezer, -/area/station/service/kitchen/coldroom) "uaE" = ( /obj/effect/turf_decal/trimline/blue/filled/warning{ dir = 8 @@ -80425,9 +80562,11 @@ }, /area/station/service/chapel) "udb" = ( -/obj/effect/spawner/structure/window/reinforced, +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 6 + }, /obj/structure/cable, -/turf/open/floor/plating, +/turf/open/floor/iron, /area/station/security/lockers) "udd" = ( /obj/structure/cable, @@ -81267,6 +81406,18 @@ /obj/structure/sign/plaques/kiddie/library, /turf/open/floor/plating, /area/station/service/library) +"uoz" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "uoI" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 @@ -81361,18 +81512,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) -"upq" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/iron, -/area/station/maintenance/starboard/aft) "upv" = ( /obj/machinery/navbeacon{ codes_txt = "delivery;dir=4"; @@ -81627,13 +81766,6 @@ }, /turf/open/floor/wood, /area/station/command/heads_quarters/hop) -"usJ" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/effect/turf_decal/loading_area{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "usZ" = ( /obj/item/flashlight/lamp, /obj/machinery/airalarm/directional/east, @@ -81655,6 +81787,15 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/science/xenobiology) +"utz" = ( +/obj/structure/bed/dogbed/runtime, +/obj/item/radio/intercom/directional/south, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 1 + }, +/mob/living/simple_animal/pet/cat/runtime, +/turf/open/floor/iron, +/area/station/command/heads_quarters/cmo) "utK" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 8 @@ -82118,27 +82259,6 @@ /obj/effect/turf_decal/stripes/white/line, /turf/open/floor/wood, /area/station/engineering/break_room) -"uzn" = ( -/obj/structure/table/reinforced, -/obj/machinery/door/firedoor, -/obj/item/folder/yellow{ - pixel_x = -6 - }, -/obj/item/pen{ - pixel_x = -6 - }, -/obj/effect/turf_decal/delivery, -/obj/machinery/door/window/right/directional/south{ - name = "Delivery Office Desk"; - req_access = list("shipping") - }, -/obj/structure/desk_bell{ - pixel_x = 7 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/cargo/sorting) "uzo" = ( /obj/structure/chair/office/light, /obj/structure/disposalpipe/segment{ @@ -82311,21 +82431,6 @@ dir = 1 }, /area/station/medical/morgue) -"uBd" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/sign/nanotrasen{ - pixel_y = 32 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/central/fore) "uBf" = ( /obj/machinery/atmospherics/pipe/smart/manifold/purple/visible{ dir = 4 @@ -82865,6 +82970,17 @@ /obj/structure/cable, /turf/open/floor/circuit/telecomms/mainframe, /area/station/tcommsat/server) +"uHu" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/dark_red/filled/line, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 1 + }, +/obj/structure/cable, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "uHE" = ( /obj/structure/table/wood/poker, /obj/effect/decal/cleanable/dirt, @@ -83266,6 +83382,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"uMS" = ( +/obj/structure/closet/wardrobe/miner, +/obj/effect/decal/cleanable/dirt, +/obj/item/storage/backpack/satchel/explorer, +/obj/effect/turf_decal/bot, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "uMV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -83315,19 +83438,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/commons/storage/primary) -"uND" = ( -/obj/effect/turf_decal/tile/brown/half{ - dir = 4 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 8 - }, -/obj/machinery/computer/order_console/bitrunning, -/obj/effect/turf_decal/stripes/end, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/cargo/miningoffice) "uNE" = ( /obj/machinery/atmospherics/components/unary/passive_vent{ dir = 4 @@ -83374,15 +83484,6 @@ }, /turf/open/floor/iron/white, /area/station/science/ordnance/office) -"uOk" = ( -/obj/structure/chair/office{ - dir = 4 - }, -/obj/effect/turf_decal/tile/brown/half/contrasted, -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/start/shaft_miner, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "uOn" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -84154,8 +84255,12 @@ }, /obj/machinery/airalarm/directional/east, /obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnancefreezer" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, /turf/open/floor/iron/dark, -/area/station/science/ordnance/freezerchamber) +/area/station/science/ordnance) "uXU" = ( /obj/structure/disposaloutlet{ dir = 8 @@ -84507,18 +84612,6 @@ }, /turf/open/floor/iron, /area/station/maintenance/port/fore) -"vbT" = ( -/obj/structure/rack, -/obj/item/gun/energy/laser/carbine/practice{ - pixel_x = 3; - pixel_y = -3 - }, -/obj/item/gun/energy/laser/practice, -/obj/effect/turf_decal/bot, -/obj/machinery/firealarm/directional/east, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/science/auxlab/firing_range) "vbV" = ( /obj/machinery/holopad, /obj/effect/turf_decal/bot, @@ -84920,11 +85013,6 @@ /obj/structure/cable, /turf/open/floor/iron/grimy, /area/station/service/bar/backroom) -"vhK" = ( -/obj/effect/landmark/blobstart, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/plating, -/area/station/maintenance/solars/starboard/aft) "vhW" = ( /obj/item/kirbyplants/random, /obj/structure/sign/warning/pods/directional/south{ @@ -85204,19 +85292,6 @@ }, /turf/open/floor/iron/cafeteria, /area/station/service/cafeteria) -"vmo" = ( -/obj/structure/table/glass, -/obj/machinery/status_display/ai/directional/west, -/obj/machinery/newscaster/directional/north, -/obj/effect/turf_decal/siding/dark_red, -/obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = -6 - }, -/obj/item/reagent_containers/cup/bottle/morphine, -/obj/item/reagent_containers/syringe, -/turf/open/floor/iron/dark, -/area/station/security/execution/transfer) "vmr" = ( /obj/machinery/airalarm/directional/west, /obj/machinery/disposal/bin, @@ -85458,6 +85533,13 @@ }, /turf/open/floor/iron, /area/station/command/heads_quarters/cmo) +"vpI" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "vpJ" = ( /obj/effect/turf_decal/tile/neutral{ dir = 8 @@ -85683,6 +85765,16 @@ }, /turf/open/floor/iron, /area/station/cargo/lobby) +"vsR" = ( +/obj/effect/turf_decal/tile/brown/half/contrasted{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "vsV" = ( /obj/machinery/duct, /turf/open/floor/plating, @@ -86077,19 +86169,6 @@ "vxs" = ( /turf/closed/wall/r_wall, /area/station/security/prison/visit) -"vxt" = ( -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/obj/effect/decal/cleanable/dirt, -/obj/structure/chair/office, -/obj/machinery/status_display/supply{ - pixel_x = 32 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/cargo/sorting) "vxu" = ( /obj/effect/turf_decal/siding/green{ dir = 1 @@ -86592,10 +86671,7 @@ /area/station/construction/mining/aux_base) "vCQ" = ( /obj/machinery/newscaster/directional/south, -/obj/machinery/vending/wardrobe/sec_wardrobe, -/obj/effect/turf_decal/trimline/red/filled/line{ - dir = 6 - }, +/obj/effect/turf_decal/trimline/red/filled/line, /turf/open/floor/iron, /area/station/security/lockers) "vCU" = ( @@ -86609,21 +86685,6 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron, /area/station/command/heads_quarters/hos) -"vDj" = ( -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/brown/line, -/obj/effect/turf_decal/trimline/brown/line{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/holopad, -/turf/open/floor/iron/dark/textured_large, -/area/station/bitrunning/den) "vDm" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -86802,6 +86863,13 @@ }, /turf/open/floor/iron, /area/station/commons/dorms) +"vFg" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron/herringbone, +/area/station/cargo/miningoffice) "vFh" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -87008,23 +87076,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/department/security) -"vId" = ( -/obj/effect/turf_decal/siding/thinplating_new/dark{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/trimline/brown/line{ - dir = 8 - }, -/obj/item/radio/intercom/directional/south, -/obj/effect/decal/cleanable/oil, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 1 - }, -/turf/open/floor/iron/dark/textured_large, -/area/station/bitrunning/den) "vIq" = ( /obj/structure/cable, /obj/structure/disposalpipe/junction{ @@ -87159,16 +87210,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/pharmacy) -"vKx" = ( -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/delivery, -/obj/effect/turf_decal/tile/neutral/anticorner/contrasted, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/maintenance/fore) "vKI" = ( /obj/item/radio/intercom/directional/west, /obj/effect/turf_decal/trimline/blue/filled/line{ @@ -87278,6 +87319,11 @@ "vMp" = ( /turf/closed/wall/r_wall, /area/station/medical/chemistry) +"vMq" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/status_display/evac/directional/north, +/turf/open/floor/plating, +/area/station/cargo/miningoffice) "vMx" = ( /obj/item/kirbyplants/random, /obj/machinery/firealarm/directional/north, @@ -87364,22 +87410,6 @@ }, /turf/open/floor/iron, /area/station/security/checkpoint/engineering) -"vNV" = ( -/obj/structure/chair{ - dir = 4 - }, -/obj/effect/turf_decal/tile/brown/half{ - dir = 8 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt/dust, -/obj/effect/landmark/start/bitrunner, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/cargo/miningoffice) "vOh" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -87663,6 +87693,23 @@ }, /turf/open/floor/iron, /area/station/security/courtroom) +"vSm" = ( +/obj/machinery/door/firedoor, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/door/airlock/mining/glass{ + name = "Delivery Office" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/mapping_helpers/airlock/access/any/supply/mining, +/obj/effect/mapping_helpers/airlock/access/any/supply/shipping, +/obj/effect/mapping_helpers/airlock/access/any/supply/bit_den, +/turf/open/floor/iron, +/area/station/cargo/sorting) "vSo" = ( /obj/structure/table/wood, /obj/item/clipboard, @@ -87793,6 +87840,39 @@ }, /turf/open/floor/iron, /area/station/science/research) +"vUf" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/desk_bell{ + pixel_x = 7; + pixel_y = 6 + }, +/obj/item/folder/yellow{ + pixel_x = -3; + pixel_y = -6 + }, +/obj/item/pen{ + pixel_x = -3; + pixel_y = -2 + }, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 4; + id = "chemisttop"; + name = "Pharmacy Shutters" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/door/window/left/directional/west{ + dir = 4; + name = "Pharmacy Desk"; + req_access = list("pharmacy") + }, +/turf/open/floor/iron/dark, +/area/station/medical/pharmacy) "vUk" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/components/binary/pump{ @@ -88015,6 +88095,16 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark/corner, /area/station/hallway/secondary/entry) +"vXy" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron/herringbone, +/area/station/cargo/miningoffice) "vXH" = ( /obj/structure/chair/office{ dir = 8 @@ -88106,8 +88196,10 @@ /area/station/solars/port/fore) "vYw" = ( /obj/effect/turf_decal/trimline/red/filled/line{ - dir = 5 + dir = 1 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/security/lockers) "vYG" = ( @@ -88720,24 +88812,6 @@ /obj/effect/landmark/start/depsec/medical, /turf/open/floor/iron/large, /area/station/security/checkpoint/medical/medsci) -"whb" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/obj/machinery/door/firedoor, -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/door/airlock/mining/glass{ - name = "Delivery Office" - }, -/obj/effect/mapping_helpers/airlock/access/any/supply/shipping, -/obj/effect/mapping_helpers/airlock/access/any/supply/mining, -/obj/effect/mapping_helpers/airlock/access/any/supply/bit_den, -/turf/open/floor/iron, -/area/station/cargo/sorting) "whc" = ( /obj/structure/sign/poster/official/fruit_bowl/directional/west, /obj/effect/turf_decal/stripes/line{ @@ -89023,6 +89097,20 @@ }, /turf/open/floor/iron/dark, /area/station/command/bridge) +"wlc" = ( +/obj/structure/table/reinforced, +/obj/item/gun/energy/laser/carbine/practice{ + pixel_x = 3; + pixel_y = -3 + }, +/obj/item/gun/energy/laser/practice, +/obj/item/clothing/ears/earmuffs, +/obj/item/clothing/ears/earmuffs, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/airalarm/directional/south, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/security/range) "wld" = ( /obj/machinery/door/window/right/directional/south, /turf/open/floor/plating, @@ -89778,6 +89866,12 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/science/server) +"wsT" = ( +/obj/structure/table/reinforced, +/obj/machinery/microwave/engineering/cell_included, +/obj/structure/sign/poster/random/directional/west, +/turf/open/floor/wood, +/area/station/engineering/break_room) "wsU" = ( /obj/docking_port/stationary/escape_pod, /turf/open/space/basic, @@ -89931,19 +90025,6 @@ }, /turf/open/floor/iron/white, /area/station/science/ordnance/storage) -"wuU" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/firealarm/directional/east, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/machinery/light/small/directional/east, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/central/fore) "wuV" = ( /obj/structure/fireaxecabinet/directional/south, /obj/effect/turf_decal/tile/blue/half/contrasted, @@ -90172,6 +90253,24 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"wxX" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/door/airlock/mining/glass{ + name = "Delivery Office" + }, +/obj/effect/mapping_helpers/airlock/access/any/supply/shipping, +/obj/effect/mapping_helpers/airlock/access/any/supply/mining, +/obj/effect/mapping_helpers/airlock/access/any/supply/bit_den, +/turf/open/floor/iron, +/area/station/cargo/sorting) "wyh" = ( /obj/structure/disposalpipe/segment{ dir = 10 @@ -91775,6 +91874,23 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/maintenance/port) +"wTL" = ( +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/brown/line{ + dir = 8 + }, +/obj/item/radio/intercom/directional/south, +/obj/effect/decal/cleanable/oil, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 1 + }, +/turf/open/floor/iron/dark/textured_large, +/area/station/bitrunning/den) "wTN" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -92294,6 +92410,13 @@ /obj/structure/lattice/catwalk, /turf/open/space, /area/station/solars/starboard/fore) +"xce" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/cargo/sorting) "xcm" = ( /obj/machinery/door/firedoor, /obj/machinery/door/poddoor/shutters/window/preopen{ @@ -92401,6 +92524,19 @@ }, /turf/open/floor/iron/dark, /area/station/command/bridge) +"xdZ" = ( +/obj/effect/turf_decal/tile/brown/half{ + dir = 4 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/obj/machinery/computer/order_console/bitrunning, +/obj/effect/turf_decal/stripes/end, +/turf/open/floor/iron/half{ + dir = 1 + }, +/area/station/cargo/miningoffice) "xef" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/disposalpipe/segment, @@ -92731,6 +92867,14 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/command/heads_quarters/qm) +"xhO" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/maintenance/fore) "xhR" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -93390,6 +93534,10 @@ /obj/machinery/duct, /turf/open/floor/iron/white, /area/station/medical/virology) +"xqp" = ( +/obj/vehicle/sealed/mecha/ripley/paddy/preset, +/turf/open/floor/iron/recharge_floor, +/area/station/security/mechbay) "xqM" = ( /obj/effect/turf_decal/stripes/line{ dir = 10 @@ -93439,6 +93587,15 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/engineering/main) +"xrl" = ( +/obj/effect/turf_decal/tile/brown/half/contrasted{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/landmark/start/shaft_miner, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "xrr" = ( /turf/closed/wall/r_wall, /area/station/maintenance/solars/starboard/fore) @@ -93685,18 +93842,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/maintenance/fore) -"xtS" = ( -/obj/structure/window/reinforced/spawner/directional/west, -/obj/item/mod/module/plasma_stabilizer, -/obj/item/mod/module/thermal_regulator, -/obj/structure/table/reinforced, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/machinery/digital_clock/directional/south, -/obj/item/mod/module/signlang_radio, -/turf/open/floor/iron, -/area/station/medical/storage) "xtZ" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/delivery, @@ -94165,13 +94310,6 @@ "xzJ" = ( /turf/open/floor/iron, /area/station/security/execution/transfer) -"xzL" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/plating, -/area/station/maintenance/port) "xzO" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/medical/glass{ @@ -94584,6 +94722,14 @@ /obj/structure/plasticflaps, /turf/open/floor/plating, /area/station/cargo/storage) +"xES" = ( +/obj/structure/table/glass, +/obj/item/surgery_tray/full, +/obj/item/clothing/gloves/latex, +/obj/item/clothing/suit/apron/surgical, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/medical/surgery/theatre) "xEV" = ( /obj/item/target, /obj/effect/decal/cleanable/dirt, @@ -95259,13 +95405,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) -"xMZ" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/cargo/sorting) "xNe" = ( /obj/structure/lattice, /obj/structure/grille/broken, @@ -95418,17 +95557,6 @@ "xPc" = ( /turf/closed/wall, /area/station/medical/virology) -"xPf" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/basic/sloth/citrus, -/turf/open/floor/iron, -/area/station/command/heads_quarters/qm) "xPo" = ( /obj/machinery/camera/directional/north{ c_tag = "Security - Prison Port" @@ -95477,14 +95605,6 @@ /obj/machinery/incident_display/delam/directional/south, /turf/open/floor/iron, /area/station/engineering/supermatter/room) -"xQq" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/basic/cockroach, -/turf/open/floor/iron/dark, -/area/station/service/abandoned_gambling_den) "xQr" = ( /obj/machinery/atmospherics/pipe/smart/simple/orange/visible{ dir = 6 @@ -95685,6 +95805,17 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron/dark, /area/station/engineering/atmos/storage) +"xTD" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/mob/living/basic/sloth/citrus, +/turf/open/floor/iron, +/area/station/command/heads_quarters/qm) "xTJ" = ( /obj/structure/cable, /obj/effect/turf_decal/stripes/line{ @@ -95815,13 +95946,6 @@ /obj/structure/barricade/wooden, /turf/open/floor/plating, /area/station/service/abandoned_gambling_den) -"xVv" = ( -/obj/effect/turf_decal/tile/purple/half/contrasted{ - dir = 4 - }, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/cargo/miningoffice) "xVI" = ( /obj/structure/rack, /obj/item/analyzer, @@ -96043,6 +96167,12 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/transit_tube) +"xYM" = ( +/obj/effect/landmark/event_spawn, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/cargo/miningoffice) "xYN" = ( /obj/machinery/newscaster/directional/north, /obj/effect/turf_decal/siding/white/corner{ @@ -96123,6 +96253,12 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/command/heads_quarters/qm) +"xZP" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/camera/directional/south, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "yah" = ( /obj/machinery/computer/bank_machine, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -96696,6 +96832,18 @@ /obj/machinery/photocopier, /turf/open/floor/iron/white, /area/station/science/research) +"yhW" = ( +/obj/machinery/conveyor{ + dir = 4; + id = "garbage" + }, +/obj/machinery/recycler{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plating, +/area/station/maintenance/disposal) "yhY" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -103262,7 +103410,7 @@ nOy smV smV nOy -mcF +smV aaa bPC bRz @@ -103273,7 +103421,7 @@ caa bPC pYJ ePZ -tfO +nCB cVr bAU cVr @@ -107385,7 +107533,7 @@ pGJ bPC pYJ ePZ -bMw +qpQ smV aOl smV @@ -107628,7 +107776,7 @@ pSa chU chU chU -iXE +chU chU chU iIm @@ -108413,7 +108561,7 @@ chU chU chU aaQ -mTB +pzp qYo qYo qYo @@ -118444,7 +118592,7 @@ aVW lbl sHT msB -kXR +iGF owf fUY jjw @@ -118993,7 +119141,7 @@ gpd cXL bMd eJy -mOh +jag jtC ibp pxb @@ -119188,14 +119336,14 @@ uiP vkg wlS vQj -ntU +wsT cJX fhr kTd wwr rSZ bAR -thZ +iDm viB pOz hEL @@ -120272,7 +120420,7 @@ sfN rnS mAt mSP -xQq +oKn bfz bsY vOk @@ -120282,7 +120430,7 @@ tuq grz urh pxb -fiu +eit egk nCI nCI @@ -121797,7 +121945,7 @@ lAs trG fnq uKY -xzL +hMp mYM pTC eSu @@ -121819,7 +121967,7 @@ vSX nEc tFP oMV -sSx +oDJ cHU eKz qel @@ -124362,8 +124510,8 @@ iqz kgi hps hkJ -ptA -tGm +tum +iTM abO pTC sNd @@ -124906,7 +125054,7 @@ aJX fSw fTA jkC -cvc +dKR jUx wEI qYo @@ -126439,7 +126587,7 @@ ddn wMi sIX qCb -vbT +fIU ljC gmE omw @@ -126670,7 +126818,7 @@ ikf vcB vcB jPf -rqN +bRs sIe bTe jTw @@ -127744,7 +127892,7 @@ bvd wJJ wEI dnV -aHw +adE gFO qQM isR @@ -128140,7 +128288,7 @@ azA oYs bEs bEs -pRp +pfs tQY ltr qRN @@ -128174,7 +128322,7 @@ hXw btc hFP xAt -uao +eEI oTB sqM oYs @@ -132080,7 +132228,7 @@ whK rcW dJa oRz -aFs +fIe bgL mfI fvi @@ -133589,7 +133737,7 @@ mGE qGW nHu lgQ -kBE +bHd mxU xJh pRS @@ -134577,7 +134725,7 @@ ptC maV rgK gmh -gzc +dxh nUG kVP kVP @@ -134673,7 +134821,7 @@ rEO uLn pMF jDq -kDv +utz loe eoE jbc @@ -135133,7 +135281,7 @@ eVl cGR vBA aPW -iBH +aOd lkL jDi dZD @@ -136965,8 +137113,8 @@ uNY squ pEU cwh -riZ -pTz +pCr +vUf cwh cwh udd @@ -137445,7 +137593,7 @@ gOU gOU vDo eBw -aaj +hxP gOU fOw ilI @@ -137505,10 +137653,10 @@ pdl fOJ kuU tOS -tsx +xES jqJ jqJ -dRQ +sOp qYL jNY llm @@ -138025,7 +138173,7 @@ uue jdf qYL qpU -neT +tNU aNV hvf vid @@ -138270,7 +138418,7 @@ nFO tqw kKy xhT -xtS +ddp ako ako gMX @@ -138681,8 +138829,8 @@ pKn vsA fsl elS -eke -vKx +jyL +jvp cCb wQv oDR @@ -138939,7 +139087,7 @@ sPo vxL jdL jdL -fiJ +eVz jdL mDP szg @@ -138967,7 +139115,7 @@ hoC yfI bGf kGo -sCW +vSm xhW ygL xhW @@ -139196,7 +139344,7 @@ hEQ weX iLF jdL -rUV +dVA jdL gJI ttP @@ -139453,7 +139601,7 @@ vyG dRo tpI jdL -onA +mWs jdL lgc dfk @@ -139679,7 +139827,7 @@ aad aad csz jSE -gOH +oNE wFz xrr aaa @@ -139710,7 +139858,7 @@ uTB wak xor jdL -oFk +rFg jdL lDi lHC @@ -139720,7 +139868,7 @@ kRn kjl lDi lDi -sLg +rTB bqv hDZ bfT @@ -139808,9 +139956,9 @@ cwe ltS cwe oDE -fUr +fTE bcj -pDy +tfJ oDE ajY tJh @@ -139967,7 +140115,7 @@ nmb kYn djn jdL -cOS +juz jdL aix wHa @@ -139984,21 +140132,21 @@ oSv ueU cNf wqo -lfC +rLB oSv mOe yhh liD mZU -whb +wxX uBZ pso -sqW -sqW -scv -eYZ -vxt -uzn +nCY +nCY +aeD +mlv +dkr +mjH eUH dvy lSl @@ -140224,7 +140372,7 @@ xwO liM xGK jdL -cOS +juz jdL ncT hTl @@ -140481,9 +140629,9 @@ sma tyU kvK sKC -cxv -joP -jnd +xhO +rMj +dPv udk uyt iRP @@ -140507,8 +140655,8 @@ gLz xhW axz fOz -rAl -bkr +syW +ecX yfo qLp pcx @@ -140764,14 +140912,14 @@ ohH xhW xhW nPo -xMZ -cGV -cGV -cGV -cGV -cGV -uBd -wuU +xce +hXg +hXg +hXg +hXg +hXg +seX +mEv vPp tJT qzY @@ -141019,14 +141167,14 @@ uSp oSv cFz rWo -qko -vNV -pxS -fbu -mlF -qsF -jKY -cGV +gpD +kLA +qbd +gHq +lJw +tYI +kUj +hXg lDY tpZ kOj @@ -141238,11 +141386,11 @@ aeF vno nNs ffk -fTh +eJx egs vno rJN -lUW +aRX pGy vno kvs @@ -141275,16 +141423,16 @@ qaF tQW hQj uzM -aPD -stf -llj -ftS -fbu -mDm -vDj -cwd -cGV -qmT +oYr +pGR +bmo +bFA +gHq +pDz +quh +tjo +hXg +fmH tpZ aaa aad @@ -141532,16 +141680,16 @@ rbV qLg uTu tQP -rmH -toy -izj -fAj -pUs -okN -oAV -vId -cGV -eFU +rid +vFg +eQG +vXy +kuj +cjO +hrz +wTL +hXg +uoz tpZ aaa lhY @@ -141790,15 +141938,15 @@ fya cSK pok rWo -uND -kKx -dux -cGV -nEE -cyc -rQF -cGV -eFU +xdZ +nMi +tJp +hXg +dsb +sYn +gVv +hXg +uoz tpZ aad lhY @@ -141861,7 +142009,7 @@ bRZ qMf jfW gUF -ltg +lni xeX qkj qMf @@ -142047,15 +142195,15 @@ fKA krp krp aJE -mtL -tcB +vMq +izK rWo -cGV -cGV -cGV -cGV -cGV -jRc +hXg +hXg +hXg +hXg +hXg +mwM tpZ aaa lhY @@ -142305,14 +142453,14 @@ iWR gkP krp llJ -ljQ -guj -eYt -nhj -owZ -bLN +aFb +sAL +occ +lDu +cRR +eCQ tpZ -eFU +uoz tpZ aaa lhY @@ -142557,19 +142705,19 @@ aDg krp cAF qqx -xPf +xTD xZC aiF aJE -jCu -rUi -kTs -sgK -iio -gco -hkn +dXX +qpd +kqJ +pBN +vsR +lyx +rPi qyX -cwK +nkO tpZ aaa lhY @@ -142784,7 +142932,7 @@ aad aad vno iJj -kVw +ove acU vno aad @@ -142818,12 +142966,12 @@ osw qZD qrG aJE -dPC -usJ -iXd -elO -hzs -uOk +rYp +idX +xrl +xYM +fxx +pAa bhJ tpZ tpZ @@ -142889,7 +143037,7 @@ pPl vPf qMf rPf -sNP +irx ovf qkj ygf @@ -143075,12 +143223,12 @@ uQZ xhJ vMd tgX -jfO -jBM -tNn -xVv -dXs -rgC +uMS +jyZ +azD +cTv +qQy +gty tDD rWo aad @@ -143564,7 +143712,7 @@ gdM lbu jtm ikR -emZ +yhW akS oeX aaa @@ -144178,7 +144326,7 @@ xPK wZE eSU haQ -huS +own pdb hnH nvM @@ -146443,7 +146591,7 @@ lYY lYY lYY pdY -nJF +fgk fvn rNx uPH @@ -146923,7 +147071,7 @@ mSe mSe mSe mSe -vmo +jTH lQj xBD mXg @@ -147178,7 +147326,7 @@ qYo qYo mSe prB -gTH +sMG mSe iiR log @@ -147948,7 +148096,7 @@ hlr wDX biI iZG -bWw +pZf kxj wDX xNU @@ -148284,7 +148432,7 @@ wEM uen iYg klE -mmA +bZe tHd ujU ehy @@ -149305,7 +149453,7 @@ ouy geH nXH gWF -upq +goa jix nmD gQK @@ -149516,7 +149664,7 @@ anY dql eBE gIV -eYo +wlc vgK ryB jlV @@ -149529,7 +149677,7 @@ rIa rIa rIa aVz -lNN +ero lra cgZ qiM @@ -149801,7 +149949,7 @@ aaa aad vop qqe -gan +qVa yaI fNn uEo @@ -150082,7 +150230,7 @@ nXH aad nXH uFH -itC +put udQ cun kOR @@ -150350,7 +150498,7 @@ hrt wZV vNa cPU -vhK +eVc oBM pWe aad @@ -150540,7 +150688,7 @@ bzi sWa gDY tKw -fQC +qDw vgK eOv tLx @@ -151074,7 +151222,7 @@ dwU wtB qBw vYw -lPH +hOk vCQ hEF hEF @@ -151330,10 +151478,10 @@ teo pKD pbN bLs -hEF -udb +hyR +lPH udb -hEF +ggW aad aad efQ @@ -151587,11 +151735,11 @@ lIy uro bLs bLs -aaa -aad -aaa -aKU -aaa +nEZ +gCa +gkt +nEZ +nEZ aad aaa aaa @@ -151844,11 +151992,11 @@ bLs bLs bLs ptN -efQ -qYo -efQ -efQ -qYo +nEZ +pgZ +uHu +aZj +nEZ qYo efQ qYo @@ -152101,11 +152249,11 @@ mfO aaa aaa aaa -aaa -qYo -aaa -aaa -aaa +nEZ +rPb +fvD +knp +nEZ qYo aaa aaa @@ -152358,12 +152506,12 @@ efQ efQ efQ efQ +nEZ +xqp +vpI +xZP +nEZ qYo -efQ -efQ -efQ -qYo -efQ lvw qYo efQ @@ -152615,14 +152763,14 @@ qYo aaa aaa qYo +nEZ +apf +iHn +nEZ +nEZ qYo aaa aaa -aaa -aaa -aaa -aaa -aaa efQ aaa uKw @@ -152872,12 +153020,12 @@ efQ efQ efQ qYo +nEZ +nEZ +nEZ +nEZ aaa -aaa -aaa -aaa -aaa -aaa +qYo aaa aaa efQ @@ -153128,15 +153276,15 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +qYo +qYo +lvw +qYo +qYo +uHd +qYo +uHd +qYo aad dTS uKw @@ -153386,13 +153534,13 @@ aaa aaa aaa aaa +lvw aaa +uHd aaa +lvw aaa -aaa -aaa -aaa -aaa +uHd aaa efQ aad @@ -153643,13 +153791,13 @@ aaa aaa aaa aaa +uHd aaa +lvw aaa +uHd aaa -aaa -aaa -aaa -aaa +lvw aaa efQ aaa diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 4de6c4c210e9cf..db261f9b2b9a38 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -1392,8 +1392,8 @@ /area/station/security/courtroom) "awR" = ( /obj/machinery/conveyor{ - id = "garbage"; - dir = 1 + dir = 1; + id = "garbage" }, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line{ @@ -1677,6 +1677,12 @@ }, /turf/open/floor/circuit/red, /area/station/ai_monitored/turret_protected/ai_upload) +"aAl" = ( +/obj/machinery/computer/mech_bay_power_console{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/security/mechbay) "aAv" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -2815,8 +2821,8 @@ "aUi" = ( /obj/structure/table, /obj/item/storage/briefcase{ - pixel_y = 3; - pixel_x = 2 + pixel_x = 2; + pixel_y = 3 }, /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/item/storage/wallet, @@ -3181,8 +3187,8 @@ pixel_x = 7 }, /obj/item/reagent_containers/cup/soda_cans/sol_dry{ - pixel_y = 4; - pixel_x = -7 + pixel_x = -7; + pixel_y = 4 }, /turf/open/floor/iron/white/corner, /area/station/hallway/secondary/entry) @@ -3446,6 +3452,13 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai_upload) +"bdL" = ( +/obj/machinery/atmospherics/pipe/smart/manifold/purple/visible{ + dir = 4 + }, +/obj/machinery/meter, +/turf/open/floor/iron/dark, +/area/station/science/ordnance) "bdQ" = ( /obj/structure/table, /obj/item/assembly/signaler{ @@ -3533,7 +3546,6 @@ /turf/open/floor/plating, /area/mine/eva/lower) "bfB" = ( -/obj/item/kirbyplants/random, /obj/machinery/firealarm/directional/east, /turf/open/floor/iron/dark/textured, /area/station/security/office) @@ -5312,8 +5324,8 @@ dir = 8; id = "garbage"; name = "disposal conveyor"; - pixel_y = 5; - pixel_x = -5 + pixel_x = -5; + pixel_y = 5 }, /obj/structure/railing/corner, /obj/effect/turf_decal/box/corners{ @@ -5915,12 +5927,6 @@ }, /turf/open/floor/iron/dark, /area/station/service/chapel) -"bMr" = ( -/obj/item/flashlight/lantern{ - start_on = 1 - }, -/turf/open/misc/asteroid/snow/icemoon, -/area/icemoon/underground/explored) "bMu" = ( /obj/structure/table/reinforced, /obj/machinery/door/window/left/directional/north{ @@ -7155,8 +7161,8 @@ name = "Disposal Exit Vent" }, /obj/machinery/conveyor{ - id = "garbage"; - dir = 1 + dir = 1; + id = "garbage" }, /obj/effect/turf_decal/stripes/red/box, /turf/open/floor/plating, @@ -7838,8 +7844,8 @@ /obj/structure/table, /obj/item/storage/wallet, /obj/item/storage/wallet{ - pixel_y = 3; - pixel_x = 4 + pixel_x = 4; + pixel_y = 3 }, /turf/open/floor/plastic, /area/station/commons/dorms/laundry) @@ -12094,7 +12100,6 @@ dir = 4 }, /obj/machinery/firealarm/directional/south, -/obj/machinery/firealarm/directional/south, /turf/open/floor/iron/dark, /area/station/engineering/atmos/storage/gas) "dBQ" = ( @@ -15378,35 +15383,6 @@ /obj/structure/bookcase/random/fiction, /turf/open/floor/iron/dark, /area/station/commons/lounge) -"eDW" = ( -/obj/machinery/camera/directional/west{ - c_tag = "Security - HoS Office" - }, -/obj/item/flashlight/lamp/green{ - pixel_x = -6; - pixel_y = 16; - start_on = 0 - }, -/obj/structure/table/wood, -/obj/item/paper_bin{ - pixel_x = 8; - pixel_y = 3 - }, -/obj/item/stamp/head/hos{ - pixel_x = 10; - pixel_y = 6 - }, -/obj/machinery/recharger{ - pixel_x = -4; - pixel_y = -1 - }, -/obj/machinery/airalarm/directional/west, -/obj/item/phone{ - pixel_x = -9; - pixel_y = 7 - }, -/turf/open/floor/wood/large, -/area/station/command/heads_quarters/hos) "eEh" = ( /obj/structure/table/reinforced, /obj/item/storage/toolbox/mechanical, @@ -16732,6 +16708,35 @@ /obj/structure/cable, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"fad" = ( +/obj/machinery/camera/directional/west{ + c_tag = "Security - HoS Office" + }, +/obj/item/flashlight/lamp/green{ + pixel_x = -6; + pixel_y = 16; + start_on = 0 + }, +/obj/structure/table/wood, +/obj/item/paper_bin{ + pixel_x = 8; + pixel_y = 3 + }, +/obj/item/stamp/head/hos{ + pixel_x = 10; + pixel_y = 6 + }, +/obj/machinery/recharger{ + pixel_x = -4; + pixel_y = -1 + }, +/obj/machinery/airalarm/directional/west, +/obj/item/phone{ + pixel_x = -9; + pixel_y = 7 + }, +/turf/open/floor/wood/large, +/area/station/command/heads_quarters/hos) "faf" = ( /obj/structure/tank_holder/extinguisher, /turf/open/floor/plating, @@ -16896,8 +16901,8 @@ /area/icemoon/underground/explored) "fdX" = ( /obj/item/toy/cards/deck{ - pixel_y = 13; - pixel_x = -9 + pixel_x = -9; + pixel_y = 13 }, /obj/effect/decal/cleanable/dirt/dust, /obj/effect/decal/cleanable/generic, @@ -18195,6 +18200,13 @@ /obj/item/reagent_containers/cup/glass/waterbottle, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"fAH" = ( +/obj/effect/turf_decal/tile/red/anticorner/contrasted, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "fAV" = ( /obj/item/kirbyplants/random, /turf/open/floor/iron, @@ -19486,9 +19498,9 @@ }, /obj/effect/turf_decal/tile/yellow/fourcorners, /obj/machinery/door/poddoor/shutters/preopen{ + dir = 4; id = "pharmacy_shutters2"; - name = "Pharmacy Shutters"; - dir = 4 + name = "Pharmacy Shutters" }, /turf/open/floor/iron, /area/station/medical/pharmacy) @@ -21048,6 +21060,18 @@ /obj/effect/spawner/random/vending/colavend, /turf/open/floor/iron, /area/station/commons/locker) +"guh" = ( +/obj/machinery/atmospherics/components/binary/pump{ + dir = 8 + }, +/obj/machinery/airalarm/directional/south, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnancefreezer" + }, +/obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/iron/dark, +/area/station/science/ordnance) "guS" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -21088,8 +21112,8 @@ /area/station/security/prison/workout) "gvp" = ( /obj/item/chair/stool{ - pixel_y = -3; - pixel_x = -1 + pixel_x = -1; + pixel_y = -3 }, /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/dim/directional/west, @@ -22472,17 +22496,6 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/iron, /area/station/security/prison/visit) -"gSr" = ( -/obj/structure/table/reinforced, -/obj/item/clothing/suit/utility/radiation, -/obj/item/clothing/head/utility/radiation, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/item/geiger_counter, -/obj/item/clothing/glasses/meson, -/turf/open/floor/engine, -/area/station/engineering/supermatter/room) "gSy" = ( /turf/open/floor/iron, /area/station/security/prison/workout) @@ -22650,13 +22663,13 @@ /area/station/science/breakroom) "gVm" = ( /obj/item/coin/silver{ - pixel_y = -3; - pixel_x = -5 + pixel_x = -5; + pixel_y = -3 }, /obj/item/toy/plush/moth{ - pixel_y = 5; + name = "Marcellus"; pixel_x = 5; - name = "Marcellus" + pixel_y = 5 }, /turf/open/floor/plating, /area/station/commons/dorms/laundry) @@ -24729,17 +24742,17 @@ "hCY" = ( /obj/structure/table/wood, /obj/item/folder/yellow{ - pixel_y = 8; - pixel_x = 3 + pixel_x = 3; + pixel_y = 8 }, /obj/item/folder/white{ - pixel_y = 12; - pixel_x = -3 + pixel_x = -3; + pixel_y = 12 }, /obj/structure/sign/poster/contraband/random/directional/south, /obj/item/folder/blue{ - pixel_y = 3; - pixel_x = -3 + pixel_x = -3; + pixel_y = 3 }, /obj/item/folder/red{ pixel_x = 5; @@ -26550,18 +26563,6 @@ /obj/structure/chair/stool/directional/south, /turf/open/floor/iron, /area/station/commons/locker) -"ihr" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/door/poddoor/shutters/preopen{ - id = "pharmacy_shutters2"; - name = "Pharmacy Shutters" - }, -/obj/machinery/door/poddoor/shutters/preopen{ - id = "pharmacy_shutters2"; - name = "Pharmacy Shutters" - }, -/turf/open/floor/plating, -/area/station/medical/pharmacy) "ihu" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, @@ -26616,7 +26617,6 @@ dir = 8 }, /obj/machinery/airalarm/directional/east, -/obj/machinery/airalarm/directional/east, /obj/machinery/camera/directional/east{ c_tag = "Cargo Bay Office - Access" }, @@ -27535,8 +27535,8 @@ "ixb" = ( /obj/machinery/button/door/directional/south{ id = "vacantofficemaintshutter"; - pixel_x = 4; name = "Privacy Shutters"; + pixel_x = 4; pixel_y = -28 }, /turf/open/floor/iron/grimy, @@ -30656,12 +30656,6 @@ /obj/machinery/atmospherics/pipe/smart/simple/purple/visible, /turf/open/floor/iron, /area/station/engineering/atmos) -"jwj" = ( -/obj/machinery/atmospherics/components/binary/pump{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/station/science/ordnance) "jwl" = ( /obj/machinery/airalarm/directional/south, /turf/open/floor/iron, @@ -31302,8 +31296,8 @@ /area/station/engineering/atmos) "jHV" = ( /obj/machinery/mineral/stacking_machine{ - stack_amt = 10; - output_dir = 2 + output_dir = 2; + stack_amt = 10 }, /obj/effect/turf_decal/stripes/line{ dir = 9 @@ -32566,6 +32560,12 @@ /obj/item/clothing/shoes/workboots, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"kbm" = ( +/obj/machinery/mech_bay_recharge_port{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/security/mechbay) "kbn" = ( /obj/effect/decal/cleanable/food/pie_smudge, /turf/open/floor/iron, @@ -32577,8 +32577,8 @@ /area/icemoon/surface/outdoors/nospawn) "kbq" = ( /obj/machinery/conveyor{ - id = "garbage"; - dir = 1 + dir = 1; + id = "garbage" }, /obj/effect/turf_decal/stripes/line{ dir = 5 @@ -32721,6 +32721,16 @@ /obj/structure/sign/warning/test_chamber/directional/south, /turf/open/floor/iron, /area/station/science/ordnance/testlab) +"kdy" = ( +/obj/machinery/door/poddoor/shutters{ + id = "secmechbay"; + name = "Security Mech Bay Shutters" + }, +/obj/structure/cable, +/obj/effect/turf_decal/caution/stand_clear, +/obj/effect/turf_decal/box, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "kdD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -33719,6 +33729,16 @@ /obj/machinery/power/apc/auto_name/directional/east, /turf/open/floor/iron/kitchen/diagonal, /area/station/service/kitchen) +"kqG" = ( +/obj/structure/table/reinforced, +/obj/machinery/light/small/directional/east, +/obj/effect/spawner/random/engineering/tool{ + pixel_x = 1; + pixel_y = 3 + }, +/obj/machinery/airalarm/directional/east, +/turf/open/floor/iron, +/area/station/security/mechbay) "kqK" = ( /obj/effect/spawner/random/trash/mess, /obj/effect/decal/cleanable/dirt, @@ -33952,17 +33972,6 @@ /obj/structure/sign/warning/electric_shock, /turf/closed/wall/r_wall, /area/station/security/prison/work) -"ktw" = ( -/obj/effect/turf_decal/stripes/line, -/obj/machinery/firealarm/directional/south, -/obj/machinery/camera/directional/south{ - c_tag = "Engineering Supermatter Fore"; - network = list("ss13","engine"); - pixel_x = 23 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible, -/turf/open/floor/engine, -/area/station/engineering/supermatter/room) "ktx" = ( /obj/effect/turf_decal/tile/yellow/half/contrasted{ dir = 1 @@ -34111,6 +34120,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 }, +/obj/item/kirbyplants/random, /turf/open/floor/iron/dark/textured, /area/station/security/office) "kvR" = ( @@ -34598,8 +34608,8 @@ pixel_y = 2 }, /obj/item/clothing/suit/hooded/wintercoat/eva{ - pixel_y = 5; - pixel_x = 1 + pixel_x = 1; + pixel_y = 5 }, /obj/machinery/light/small/directional/east, /obj/machinery/mining_weather_monitor/directional/north, @@ -36910,6 +36920,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/mine/laborcamp) +"lmM" = ( +/obj/structure/cable, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "lmY" = ( /obj/machinery/newscaster/directional/west, /obj/machinery/camera{ @@ -37043,8 +37062,14 @@ /turf/open/floor/iron, /area/station/construction) "loy" = ( -/obj/item/kirbyplants/random, /obj/effect/turf_decal/tile/red/anticorner/contrasted, +/obj/machinery/button/door/directional/east{ + id = "secmechbay"; + name = "Security Mech Garage Door Controls"; + req_access = list("security") + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/brig/upper) "loG" = ( @@ -38267,6 +38292,19 @@ }, /turf/open/floor/iron/dark/corner, /area/station/engineering/atmos/storage/gas) +"lHL" = ( +/obj/structure/cable, +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/machinery/button/door/directional/north{ + id = "secmechbay"; + name = "Security Mech Garage Door Controls"; + req_access = list("security") + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "lIk" = ( /obj/effect/spawner/structure/window, /turf/open/floor/plating, @@ -38460,8 +38498,8 @@ /obj/structure/table, /obj/effect/turf_decal/tile/brown/half/contrasted, /obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = -6 + pixel_x = -6; + pixel_y = 6 }, /obj/item/food/cheesiehonkers, /turf/open/floor/iron, @@ -38816,6 +38854,11 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron, /area/station/commons/fitness) +"lRc" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable, +/turf/open/floor/plating, +/area/station/security/mechbay) "lRd" = ( /obj/structure/chair, /obj/effect/turf_decal/stripes/line{ @@ -40621,9 +40664,9 @@ "mwF" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/shutters/preopen{ + dir = 4; id = "pharmacy_shutters"; - name = "Pharmacy Shutters"; - dir = 4 + name = "Pharmacy Shutters" }, /turf/open/floor/plating, /area/station/medical/pharmacy) @@ -41038,6 +41081,10 @@ /obj/item/stamp/head/ce, /turf/open/floor/iron, /area/station/command/heads_quarters/ce) +"mDA" = ( +/obj/machinery/air_sensor/engine_chamber, +/turf/open/floor/engine, +/area/station/engineering/supermatter) "mDX" = ( /turf/open/floor/engine/n2, /area/station/engineering/atmos) @@ -43181,6 +43228,19 @@ }, /turf/open/floor/iron, /area/station/commons/dorms) +"nmq" = ( +/obj/machinery/power/apc/auto_name/directional/north, +/obj/structure/cable, +/obj/structure/table/reinforced, +/obj/effect/spawner/random/engineering/tool{ + pixel_x = -11 + }, +/obj/effect/spawner/random/engineering/tool{ + pixel_x = 5; + pixel_y = 8 + }, +/turf/open/floor/iron, +/area/station/security/mechbay) "nmr" = ( /obj/machinery/hydroponics/soil, /obj/item/cultivator, @@ -43844,8 +43904,8 @@ dir = 4 }, /obj/machinery/door/airlock/multi_tile/public/glass{ - name = "Arrivals Dock"; - dir = 4 + dir = 4; + name = "Arrivals Dock" }, /turf/open/floor/iron/dark/textured, /area/station/hallway/secondary/entry) @@ -45505,6 +45565,18 @@ /obj/machinery/atmospherics/pipe/smart/simple/orange/visible, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"nTk" = ( +/obj/structure/table/reinforced, +/obj/item/clothing/suit/utility/radiation, +/obj/item/clothing/head/utility/radiation, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/item/geiger_counter, +/obj/item/clothing/glasses/meson, +/obj/machinery/firealarm/directional/north, +/turf/open/floor/engine, +/area/station/engineering/supermatter/room) "nTp" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -46015,15 +46087,6 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/station/science/xenobiology) -"odf" = ( -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ - dir = 1 - }, -/obj/effect/turf_decal/box/red, -/obj/machinery/airalarm/directional/east, -/obj/effect/mapping_helpers/airalarm/mixingchamber_access, -/turf/open/floor/iron/dark, -/area/station/science/ordnance/burnchamber) "odi" = ( /obj/item/toy/snowball{ pixel_x = 5; @@ -46739,8 +46802,8 @@ dir = 4 }, /obj/machinery/door/airlock/multi_tile/public/glass{ - name = "Arrivals Dock"; - dir = 4 + dir = 4; + name = "Arrivals Dock" }, /turf/open/floor/iron/dark/textured, /area/station/hallway/secondary/entry) @@ -47143,8 +47206,8 @@ /obj/structure/rack, /obj/machinery/light/cold/directional/north, /obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = -6 + pixel_x = -6; + pixel_y = 6 }, /obj/item/healthanalyzer, /turf/open/floor/iron/white/textured, @@ -47446,6 +47509,13 @@ /obj/structure/sign/poster/contraband/random/directional/north, /turf/open/floor/plating, /area/station/security/prison/safe) +"oyL" = ( +/obj/effect/turf_decal/tile/red/half/contrasted, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "oyV" = ( /obj/effect/turf_decal/tile/neutral/diagonal_edge, /obj/structure/cable, @@ -49349,12 +49419,12 @@ /area/station/medical/medbay/central) "pcc" = ( /obj/item/stack/spacecash/c10{ - pixel_y = 4; - pixel_x = 4 + pixel_x = 4; + pixel_y = 4 }, /obj/item/toy/plush/beeplushie{ - pixel_y = -6; - name = "Coolidge" + name = "Coolidge"; + pixel_y = -6 }, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/plating, @@ -50414,6 +50484,17 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/cargo/office) +"psY" = ( +/obj/machinery/door/poddoor/shutters{ + id = "secmechbay"; + name = "Security Mech Bay Shutters" + }, +/obj/effect/turf_decal/caution/stand_clear, +/obj/effect/turf_decal/box, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "ptd" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -52294,6 +52375,9 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/engineering/main) +"pVL" = ( +/turf/closed/wall/r_wall, +/area/station/security/mechbay) "pVN" = ( /obj/structure/cable, /turf/open/floor/plating, @@ -54293,16 +54377,6 @@ /obj/effect/mapping_helpers/airlock/access/all/supply/mining, /turf/open/floor/iron/large, /area/mine/mechbay) -"qDj" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/binary/pump{ - dir = 1; - name = "Gas to Filter" - }, -/obj/effect/mapping_helpers/airalarm/engine_access, -/obj/machinery/airalarm/directional/west, -/turf/open/floor/engine, -/area/station/engineering/supermatter) "qDD" = ( /obj/machinery/washing_machine, /obj/effect/decal/cleanable/dirt, @@ -55814,9 +55888,9 @@ /obj/machinery/smartfridge/chemistry/preloaded, /obj/machinery/door/firedoor, /obj/machinery/door/poddoor/shutters/preopen{ + dir = 4; id = "pharmacy_shutters"; - name = "Pharmacy Shutters"; - dir = 4 + name = "Pharmacy Shutters" }, /turf/open/floor/iron/white, /area/station/medical/pharmacy) @@ -56902,8 +56976,8 @@ pixel_y = 3 }, /obj/item/assembly/flash/handheld{ - pixel_y = 3; - pixel_x = -19 + pixel_x = -19; + pixel_y = 3 }, /obj/structure/table, /obj/effect/turf_decal/tile/red/anticorner/contrasted, @@ -57938,9 +58012,9 @@ /obj/machinery/smartfridge/chemistry/preloaded, /obj/machinery/door/firedoor, /obj/machinery/door/poddoor/shutters/preopen{ + dir = 4; id = "pharmacy_shutters2"; - name = "Pharmacy Shutters"; - dir = 4 + name = "Pharmacy Shutters" }, /turf/open/floor/iron/white, /area/station/medical/pharmacy) @@ -58621,6 +58695,14 @@ }, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) +"rTp" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/components/binary/pump{ + dir = 1; + name = "Gas to Filter" + }, +/turf/open/floor/engine, +/area/station/engineering/supermatter) "rTs" = ( /obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden, /turf/open/floor/plating, @@ -59119,9 +59201,9 @@ }, /obj/effect/turf_decal/tile/yellow/fourcorners, /obj/machinery/door/poddoor/shutters/preopen{ + dir = 4; id = "pharmacy_shutters"; - name = "Pharmacy Shutters"; - dir = 4 + name = "Pharmacy Shutters" }, /turf/open/floor/iron, /area/station/medical/pharmacy) @@ -59531,6 +59613,22 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"shJ" = ( +/obj/effect/turf_decal/stripes/line, +/obj/machinery/camera/directional/south{ + c_tag = "Engineering Supermatter Fore"; + network = list("ss13","engine"); + pixel_x = 23 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible, +/obj/machinery/airalarm/directional/south, +/obj/effect/mapping_helpers/airalarm/engine_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "engine" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/engine, +/area/station/engineering/supermatter/room) "shT" = ( /obj/effect/turf_decal/tile/blue{ dir = 1 @@ -59966,14 +60064,6 @@ /obj/effect/turf_decal/tile/blue/half/contrasted, /turf/open/floor/iron, /area/station/engineering/atmos) -"soi" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/table, -/obj/item/flashlight/lamp{ - start_on = 0 - }, -/turf/open/floor/wood, -/area/station/maintenance/aft/greater) "sok" = ( /obj/machinery/door/airlock/security/glass{ name = "Security Office" @@ -60104,13 +60194,13 @@ pixel_y = -5 }, /obj/item/coin/plasma{ - pixel_y = -2; - pixel_x = 3 + pixel_x = 3; + pixel_y = -2 }, /obj/item/toy/plush/lizard_plushie{ + name = "Cassius"; pixel_x = 11; - pixel_y = -4; - name = "Cassius" + pixel_y = -4 }, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/plating, @@ -61655,8 +61745,8 @@ /area/station/medical/chemistry) "sLR" = ( /obj/machinery/conveyor{ - id = "garbage"; - dir = 1 + dir = 1; + id = "garbage" }, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line{ @@ -62440,6 +62530,14 @@ /obj/effect/mapping_helpers/airlock/access/all/medical/chemistry, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"taj" = ( +/obj/structure/cable, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/light/small/directional/west, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "tak" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -62626,9 +62724,9 @@ "teE" = ( /obj/effect/spawner/structure/window, /obj/machinery/door/poddoor/shutters{ + dir = 8; id = "vacantofficemaintshutter"; - name = "Privacy Shutters"; - dir = 8 + name = "Privacy Shutters" }, /turf/open/floor/plating, /area/station/commons/vacant_room/office) @@ -62950,8 +63048,8 @@ dir = 4 }, /obj/machinery/door/airlock/multi_tile/public/glass{ - name = "Auxiliary Dock"; - dir = 4 + dir = 4; + name = "Auxiliary Dock" }, /turf/open/floor/iron/dark/textured, /area/station/hallway/secondary/entry) @@ -65023,6 +65121,12 @@ /obj/machinery/suit_storage_unit/security, /turf/open/floor/iron/smooth, /area/station/security/brig/upper) +"tSs" = ( +/obj/item/flashlight/lantern{ + start_on = 1 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "tSt" = ( /obj/structure/sign/painting/library, /turf/closed/wall, @@ -68054,15 +68158,6 @@ dir = 1 }, /area/station/engineering/main) -"uSq" = ( -/obj/machinery/atmospherics/pipe/smart/manifold/purple/visible{ - dir = 4 - }, -/obj/machinery/meter, -/obj/machinery/airalarm/directional/east, -/obj/effect/mapping_helpers/airalarm/mixingchamber_access, -/turf/open/floor/iron/dark, -/area/station/science/ordnance/freezerchamber) "uSS" = ( /obj/machinery/recharge_station, /obj/effect/turf_decal/stripes/box, @@ -69413,6 +69508,11 @@ /obj/structure/sign/warning/gas_mask/directional/west, /turf/open/floor/iron, /area/station/cargo/drone_bay) +"vpn" = ( +/obj/vehicle/sealed/mecha/ripley/paddy/preset, +/obj/structure/cable, +/turf/open/floor/iron/recharge_floor, +/area/station/security/mechbay) "vpR" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark, @@ -69566,6 +69666,16 @@ /obj/structure/marker_beacon/burgundy, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"vsL" = ( +/obj/structure/cable, +/obj/effect/turf_decal/tile/red/anticorner/contrasted{ + dir = 8 + }, +/obj/machinery/camera/directional/west{ + c_tag = "Security - Office - Port" + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "vsM" = ( /obj/structure/cable, /obj/machinery/power/apc/auto_name/directional/west, @@ -70790,6 +70900,14 @@ /obj/structure/cable/layer3, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat_interior) +"vMN" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/table, +/obj/item/flashlight/lamp{ + start_on = 0 + }, +/turf/open/floor/wood, +/area/station/maintenance/aft/greater) "vMR" = ( /obj/structure/table/glass, /obj/item/seeds/glowshroom, @@ -73358,6 +73476,8 @@ "wAT" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/red/half/contrasted, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/brig/upper) "wAW" = ( @@ -75567,8 +75687,8 @@ "xgX" = ( /obj/structure/table/wood, /obj/effect/spawner/random/entertainment/deck{ - pixel_y = 15; - pixel_x = -2 + pixel_x = -2; + pixel_y = 15 }, /obj/effect/spawner/random/food_or_drink/snack{ pixel_x = 5; @@ -76239,6 +76359,19 @@ /obj/item/food/grown/carrot, /turf/open/misc/asteroid/snow/standard_air, /area/station/science/research) +"xsR" = ( +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 1 + }, +/obj/effect/turf_decal/box/red, +/obj/machinery/airalarm/directional/east, +/obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnanceburn" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/iron/dark, +/area/station/science/ordnance) "xtc" = ( /obj/effect/turf_decal/trimline/blue/filled/warning{ dir = 1 @@ -186529,7 +186662,7 @@ thA thA thA rcY -bMr +tSs iDt scw scw @@ -194033,7 +194166,7 @@ qSk sbd rEh qSk -jwj +guh qZN dJy pNB @@ -194286,11 +194419,11 @@ nBV iao hKj iao -odf +xsR sbd jaY rhY -uSq +bdL pjc gmb hac @@ -238670,7 +238803,7 @@ nbp mgU nbt ioi -eDW +fad azx tDw rhf @@ -238779,9 +238912,9 @@ sSJ oSR glc fab -ktw +shJ bny -qDj +rTp xBp bYw bYw @@ -239040,7 +239173,7 @@ tfR iNa tLW seR -esE +mDA uey esE uLe @@ -239805,7 +239938,7 @@ sIp uif wRd gka -gSr +nTk fab iag loc @@ -240740,7 +240873,7 @@ jNp jNp jNp jNp -sDl +pVL sDl sDl sDl @@ -240993,11 +241126,11 @@ law eqI ewM wAT -lbk -bln -bln -bln -sDl +kdy +taj +vsL +vpn +lRc sDl sDl sDl @@ -241250,11 +241383,11 @@ eyb hAQ ksC loy -lbk -bln -bln -bln -sDl +psY +lmM +oyL +kbm +lRc sDl sDl sDl @@ -241508,10 +241641,10 @@ mfH cIY mfH mfH -ntK -bln -sDl -sDl +lHL +fAH +aAl +lRc sDl sDl sDl @@ -241764,11 +241897,11 @@ ykw tSi kfc dcX -lbk -bln -bln -sDl -sDl +mfH +nmq +kqG +pVL +pVL sDl sDl sDl @@ -242022,9 +242155,9 @@ nOQ cqx sQB mfH -bln -sDl -sDl +pVL +pVL +pVL sDl sDl tOq @@ -245155,7 +245288,7 @@ aMP dQo oQD hHI -ihr +tdE fBR fKi tHr @@ -249561,7 +249694,7 @@ bPY rwe wGO npD -soi +vMN hRe ves dFA diff --git a/_maps/map_files/Mafia/mafia_ayylmao.dmm b/_maps/map_files/Mafia/mafia_ayylmao.dmm index b9d8582f3b0101..6fdc04e3d0954f 100644 --- a/_maps/map_files/Mafia/mafia_ayylmao.dmm +++ b/_maps/map_files/Mafia/mafia_ayylmao.dmm @@ -9,6 +9,10 @@ /obj/effect/landmark/mafia, /turf/open/floor/plating/abductor, /area/centcom/mafia) +"f" = ( +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/turf/closed/indestructible/alien, +/area/centcom/mafia) "g" = ( /obj/mafia_game_board, /obj/effect/mapping_helpers/broken_floor, @@ -48,15 +52,6 @@ /obj/item/abductor/gizmo, /turf/open/floor/plating/abductor2, /area/centcom/mafia) -"p" = ( -/obj/machinery/door/poddoor/preopen{ - desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; - id = "mafia"; - max_integrity = 99999; - name = "Station Night Shutters" - }, -/turf/closed/indestructible/fakeglass, -/area/centcom/mafia) "q" = ( /turf/open/floor/plating/abductor, /area/centcom/mafia) @@ -83,8 +78,8 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/obj/structure/window/reinforced/plasma/plastitanium, -/turf/open/floor/plating/abductor2, +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/turf/open/space/basic, /area/centcom/mafia) "z" = ( /obj/structure/grille/indestructible, @@ -350,7 +345,7 @@ i N o r -p +x m q x @@ -578,7 +573,7 @@ q b b r -b +f q b b diff --git a/_maps/map_files/Mafia/mafia_ball.dmm b/_maps/map_files/Mafia/mafia_ball.dmm index fb4dc490d367f7..e642cc78783e27 100644 --- a/_maps/map_files/Mafia/mafia_ball.dmm +++ b/_maps/map_files/Mafia/mafia_ball.dmm @@ -67,7 +67,8 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/turf/closed/indestructible/fakeglass, +/obj/effect/spawner/structure/window/reinforced/indestructible, +/turf/open/space/basic, /area/centcom/mafia) "q" = ( /turf/open/floor/iron/dark, @@ -91,8 +92,12 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/centcom/mafia) +"E" = ( +/turf/template_noop, +/area/template_noop) (1,1,1) = {" +E a a a @@ -114,10 +119,10 @@ a a a a -a -a +E "} (2,1,1) = {" +E a b b @@ -138,14 +143,13 @@ b b b b -b -b a +E "} (3,1,1) = {" +E a b -b c c c @@ -164,13 +168,13 @@ c c c b -b a +E "} (4,1,1) = {" +E a b -b c g h @@ -189,12 +193,12 @@ h k c b -b a +E "} (5,1,1) = {" a -b +a b c h @@ -214,7 +218,7 @@ i h c b -b +a a "} (6,1,1) = {" @@ -544,7 +548,7 @@ a "} (19,1,1) = {" a -b +a b c h @@ -564,13 +568,13 @@ d h c b -b +a a "} (20,1,1) = {" +E a b -b c k h @@ -589,13 +593,13 @@ h v c b -b a +E "} (21,1,1) = {" +E a b -b c c c @@ -614,10 +618,11 @@ c c c b -b a +E "} (22,1,1) = {" +E a b b @@ -638,11 +643,11 @@ b b b b -b -b a +E "} (23,1,1) = {" +E a a a @@ -664,6 +669,5 @@ a a a a -a -a +E "} diff --git a/_maps/map_files/Mafia/mafia_gothic.dmm b/_maps/map_files/Mafia/mafia_gothic.dmm index 817e145d111035..5dadad3d2c1794 100644 --- a/_maps/map_files/Mafia/mafia_gothic.dmm +++ b/_maps/map_files/Mafia/mafia_gothic.dmm @@ -62,7 +62,8 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/turf/closed/indestructible/opsglass, +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/turf/open/space/basic, /area/centcom/mafia) "q" = ( /turf/open/floor/carpet/red, @@ -85,6 +86,9 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/centcom/mafia) +"y" = ( +/turf/template_noop, +/area/template_noop) "D" = ( /obj/effect/landmark/mafia, /turf/open/floor/iron/chapel{ @@ -131,6 +135,9 @@ dir = 8 }, /area/centcom/mafia) +"U" = ( +/turf/closed/wall/r_wall, +/area/centcom/mafia) "X" = ( /turf/open/floor/iron/chapel{ dir = 1 @@ -138,6 +145,7 @@ /area/centcom/mafia) (1,1,1) = {" +y a a a @@ -159,38 +167,37 @@ a a a a -a -a +y "} (2,1,1) = {" -a -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -a +y +a +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +a +y "} (3,1,1) = {" +y a -b -b +U c c c @@ -208,14 +215,14 @@ c c c c -b -b +U a +y "} (4,1,1) = {" +y a -b -b +U c g h @@ -233,14 +240,14 @@ d h k c -b -b +U a +y "} (5,1,1) = {" a -b -b +a +U c h d @@ -258,14 +265,14 @@ d i h c -b -b +U +a a "} (6,1,1) = {" a -b -b +U +U c i b @@ -283,13 +290,13 @@ b b d c -b -b +U +U a "} (7,1,1) = {" a -b +U c c d @@ -309,12 +316,12 @@ b d c c -b +U a "} (8,1,1) = {" a -b +U c d d @@ -334,12 +341,12 @@ b d d c -b +U a "} (9,1,1) = {" a -b +U c d b @@ -359,12 +366,12 @@ b b d c -b +U a "} (10,1,1) = {" a -b +U c d b @@ -384,12 +391,12 @@ Q b d c -b +U a "} (11,1,1) = {" a -b +U c d j @@ -409,12 +416,12 @@ O j i c -b +U a "} (12,1,1) = {" a -b +U c i b @@ -434,12 +441,12 @@ b b d c -b +U a "} (13,1,1) = {" a -b +U c d j @@ -459,12 +466,12 @@ q j d c -b +U a "} (14,1,1) = {" a -b +U c d b @@ -484,12 +491,12 @@ l b i c -b +U a "} (15,1,1) = {" a -b +U c d b @@ -509,12 +516,12 @@ b b d c -b +U a "} (16,1,1) = {" a -b +U c f d @@ -534,12 +541,12 @@ b d d c -b +U a "} (17,1,1) = {" a -b +U c c d @@ -559,13 +566,13 @@ b d c c -b +U a "} (18,1,1) = {" a -b -b +U +U c d b @@ -583,14 +590,14 @@ b b d c -b -b +U +U a "} (19,1,1) = {" a -b -b +a +U c h i @@ -608,14 +615,14 @@ i d h c -b -b +U +a a "} (20,1,1) = {" +y a -b -b +U c k h @@ -633,14 +640,14 @@ d h v c -b -b +U a +y "} (21,1,1) = {" +y a -b -b +U c c c @@ -658,36 +665,37 @@ c c c c -b -b +U a +y "} (22,1,1) = {" -a -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -a +y +a +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +a +y "} (23,1,1) = {" +y a a a @@ -709,6 +717,5 @@ a a a a -a -a +y "} diff --git a/_maps/map_files/Mafia/mafia_lavaland.dmm b/_maps/map_files/Mafia/mafia_lavaland.dmm index 96ddef90b5cebf..c6189750b0aabd 100644 --- a/_maps/map_files/Mafia/mafia_lavaland.dmm +++ b/_maps/map_files/Mafia/mafia_lavaland.dmm @@ -82,7 +82,8 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/turf/closed/indestructible/fakeglass, +/obj/effect/spawner/structure/window/reinforced/indestructible, +/turf/open/space/basic, /area/centcom/mafia) "aq" = ( /turf/open/floor/fakebasalt, @@ -282,12 +283,16 @@ }, /turf/open/floor/iron/dark, /area/centcom/mafia) +"qp" = ( +/turf/template_noop, +/area/template_noop) "GL" = ( /obj/effect/turf_decal/tile/red/half/contrasted, /turf/open/floor/iron/dark, /area/centcom/mafia) (1,1,1) = {" +qp aa aa aa @@ -309,10 +314,10 @@ aa aa aa aa -aa -aa +qp "} (2,1,1) = {" +qp aa aY aY @@ -333,14 +338,13 @@ aY aY aY aY -aY -aY aa +qp "} (3,1,1) = {" +qp aa aY -aY ac ac ac @@ -359,13 +363,13 @@ ac ac ac aY -aY aa +qp "} (4,1,1) = {" +qp aa aY -aY ac ag ah @@ -384,12 +388,12 @@ ah ak ac aY -aY aa +qp "} (5,1,1) = {" aa -aY +aa aY ac ah @@ -409,7 +413,7 @@ ai ah ac aY -aY +aa aa "} (6,1,1) = {" @@ -739,7 +743,7 @@ aa "} (19,1,1) = {" aa -aY +aa aY ac ah @@ -759,13 +763,13 @@ ad ah ac aY -aY +aa aa "} (20,1,1) = {" +qp aa aY -aY ac ak ah @@ -784,13 +788,13 @@ ah av ac aY -aY aa +qp "} (21,1,1) = {" +qp aa aY -aY ac ac ac @@ -809,10 +813,11 @@ ac ac ac aY -aY aa +qp "} (22,1,1) = {" +qp aa aY aY @@ -833,11 +838,11 @@ aY aY aY aY -aY -aY aa +qp "} (23,1,1) = {" +qp aa aa aa @@ -859,6 +864,5 @@ aa aa aa aa -aa -aa +qp "} diff --git a/_maps/map_files/Mafia/mafia_snow.dmm b/_maps/map_files/Mafia/mafia_snow.dmm index b8fbc0650b4cb8..bbc5f958d75abd 100644 --- a/_maps/map_files/Mafia/mafia_snow.dmm +++ b/_maps/map_files/Mafia/mafia_snow.dmm @@ -71,7 +71,8 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/turf/closed/indestructible/fakeglass, +/obj/effect/spawner/structure/window/ice, +/turf/open/space/basic, /area/centcom/mafia) "q" = ( /turf/open/floor/iron/dark, @@ -176,6 +177,9 @@ "K" = ( /turf/closed/indestructible/rock/snow, /area/centcom/mafia) +"L" = ( +/turf/template_noop, +/area/template_noop) "R" = ( /obj/effect/landmark/mafia, /turf/open/floor/iron, @@ -187,7 +191,7 @@ /area/centcom/mafia) (1,1,1) = {" -a +L a a a @@ -212,6 +216,7 @@ a a "} (2,1,1) = {" +L a b b @@ -222,7 +227,6 @@ b b b b -b s K K @@ -237,9 +241,9 @@ K a "} (3,1,1) = {" +L a b -b s s s @@ -262,9 +266,9 @@ K a "} (4,1,1) = {" +L a b -b s g h @@ -288,7 +292,7 @@ a "} (5,1,1) = {" a -b +a b s h @@ -375,8 +379,8 @@ s q s t -p -p +s +s z z p @@ -427,7 +431,7 @@ p p p p -p +s p D p @@ -467,7 +471,7 @@ b s i s -b +s p s p @@ -477,10 +481,10 @@ v t p p +s p -p -p -p +s +s w w K @@ -527,7 +531,7 @@ p p p p -p +s p D p @@ -575,8 +579,8 @@ s r s t -p -p +s +s z z p @@ -638,7 +642,7 @@ a "} (19,1,1) = {" a -b +a b s h @@ -662,9 +666,9 @@ K a "} (20,1,1) = {" +L a b -b s k h @@ -687,9 +691,9 @@ K a "} (21,1,1) = {" +L a b -b s s s @@ -712,6 +716,7 @@ K a "} (22,1,1) = {" +L a b b @@ -722,7 +727,6 @@ b b b b -b s K K @@ -737,7 +741,7 @@ K a "} (23,1,1) = {" -a +L a a a diff --git a/_maps/map_files/Mafia/mafia_spiderclan.dmm b/_maps/map_files/Mafia/mafia_spiderclan.dmm index ff83f8de3ec40e..a00e373c1a4c5a 100644 --- a/_maps/map_files/Mafia/mafia_spiderclan.dmm +++ b/_maps/map_files/Mafia/mafia_spiderclan.dmm @@ -94,11 +94,15 @@ /obj/structure/showcase/katana, /turf/open/misc/beach/sand, /area/centcom/mafia) +"Q" = ( +/turf/template_noop, +/area/template_noop) "S" = ( /turf/closed/wall/mineral/wood, /area/centcom/mafia) (1,1,1) = {" +Q a a a @@ -120,10 +124,10 @@ a a a a -a -a +Q "} (2,1,1) = {" +Q a S S @@ -144,14 +148,13 @@ S S S S -S -S a +Q "} (3,1,1) = {" +Q a S -S c c c @@ -170,13 +173,13 @@ c c c S -S a +Q "} (4,1,1) = {" +Q a S -S c g h @@ -195,12 +198,12 @@ h k c S -S a +Q "} (5,1,1) = {" a -S +a S c h @@ -220,7 +223,7 @@ i h c S -S +a a "} (6,1,1) = {" @@ -550,7 +553,7 @@ a "} (19,1,1) = {" a -S +a S c h @@ -570,13 +573,13 @@ d h c S -S +a a "} (20,1,1) = {" +Q a S -S c k h @@ -595,13 +598,13 @@ h v c S -S a +Q "} (21,1,1) = {" +Q a S -S c c c @@ -620,10 +623,11 @@ c c c S -S a +Q "} (22,1,1) = {" +Q a S S @@ -644,11 +648,11 @@ S S S S -S -S a +Q "} (23,1,1) = {" +Q a a a @@ -670,6 +674,5 @@ a a a a -a -a +Q "} diff --git a/_maps/map_files/Mafia/mafia_syndie.dmm b/_maps/map_files/Mafia/mafia_syndie.dmm index 12287245828d5d..4c275e2ef3237f 100644 --- a/_maps/map_files/Mafia/mafia_syndie.dmm +++ b/_maps/map_files/Mafia/mafia_syndie.dmm @@ -46,7 +46,6 @@ /turf/open/floor/plating, /area/centcom/mafia) "o" = ( -/obj/effect/turf_decal/tile/red/fourcorners, /turf/open/floor/iron/dark, /area/centcom/mafia) "p" = ( @@ -56,14 +55,14 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/turf/closed/indestructible/opsglass, +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/turf/open/space/basic, /area/centcom/mafia) "q" = ( /obj/structure/chair/office{ dir = 1; name = "tactical swivel chair" }, -/obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/landmark/mafia, /turf/open/floor/iron/dark, /area/centcom/mafia) @@ -82,14 +81,13 @@ /turf/open/floor/plating, /area/centcom/mafia) "w" = ( -/turf/closed/indestructible/syndicate, +/turf/closed/wall/r_wall, /area/centcom/mafia) "x" = ( /obj/structure/chair/office{ dir = 4; name = "tactical swivel chair" }, -/obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/landmark/mafia, /turf/open/floor/iron/dark, /area/centcom/mafia) @@ -104,7 +102,6 @@ /obj/structure/chair/office{ name = "tactical swivel chair" }, -/obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/landmark/mafia, /turf/open/floor/iron/dark, /area/centcom/mafia) @@ -129,7 +126,6 @@ dir = 8; name = "tactical swivel chair" }, -/obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/landmark/mafia, /turf/open/floor/iron/dark, /area/centcom/mafia) @@ -146,7 +142,6 @@ desc = "A storage closet for syndicate conflict resolution operatives."; name = "red closet" }, -/obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/spawner/random/clothing/syndie, /turf/open/floor/iron/dark, /area/centcom/mafia) @@ -156,8 +151,15 @@ "S" = ( /turf/open/floor/mineral/plastitanium/red, /area/centcom/mafia) +"W" = ( +/turf/closed/wall/mineral/plastitanium, +/area/centcom/mafia) +"Y" = ( +/turf/template_noop, +/area/template_noop) (1,1,1) = {" +Y a a a @@ -179,10 +181,10 @@ a a a a -a -a +Y "} (2,1,1) = {" +Y a w w @@ -203,14 +205,13 @@ w w w w -w -w a +Y "} (3,1,1) = {" +Y a w -w c c c @@ -229,13 +230,13 @@ c c c w -w a +Y "} (4,1,1) = {" +Y a w -w c g h @@ -254,32 +255,32 @@ h k c w -w a +Y "} (5,1,1) = {" a -w +a w c h d d i -w -w +W +W j -w +W j -w -w +W +W d d i h c w -w +a a "} (6,1,1) = {" @@ -288,19 +289,19 @@ w w c i -w -w +W +W j -w +W b r -w +W o G -w +W j -w -w +W +W d c w @@ -313,7 +314,7 @@ w c c d -w +W G o p @@ -325,7 +326,7 @@ o p r b -w +W d c c @@ -338,19 +339,19 @@ w c d d -w +W o o -w -w +W +W r -w +W o -w -w +W +W r r -w +W d d c @@ -362,8 +363,8 @@ a w c d -w -w +W +W p o x @@ -375,8 +376,8 @@ p B r p -w -w +W +W d c w @@ -387,10 +388,10 @@ a w c d -w +W b p -w +W p p p @@ -398,10 +399,10 @@ p p p p -w +W p G -w +W d c w @@ -437,10 +438,10 @@ a w c i -w -w +W +W p -w +W p p Q @@ -448,10 +449,10 @@ u Q p p -w +W p -w -w +W +W d c w @@ -487,10 +488,10 @@ a w c d -w +W G p -w +W p p p @@ -498,10 +499,10 @@ p p p p -w +W p b -w +W i c w @@ -512,8 +513,8 @@ a w c d -w -w +W +W p r A @@ -525,8 +526,8 @@ p C o p -w -w +W +W d c w @@ -538,19 +539,19 @@ w c f d -w +W r r -w -w +W +W o -w +W r -w -w +W +W o o -w +W d d c @@ -563,7 +564,7 @@ w c c d -w +W b r p @@ -575,7 +576,7 @@ r p o G -w +W d c c @@ -588,19 +589,19 @@ w w c d -w -w +W +W j -w +W G o -w +W r b -w +W j -w -w +W +W d c w @@ -609,33 +610,33 @@ a "} (19,1,1) = {" a -w +a w c h i d d -w -w +W +W j -w +W j -w -w +W +W d i d h c w -w +a a "} (20,1,1) = {" +Y a w -w c k h @@ -654,13 +655,13 @@ h v c w -w a +Y "} (21,1,1) = {" +Y a w -w c c c @@ -679,10 +680,11 @@ c c c w -w a +Y "} (22,1,1) = {" +Y a w w @@ -703,11 +705,11 @@ w w w w -w -w a +Y "} (23,1,1) = {" +Y a a a @@ -729,6 +731,5 @@ a a a a -a -a +Y "} diff --git a/_maps/map_files/Mafia/mafia_unit_test.dmm b/_maps/map_files/Mafia/mafia_unit_test.dmm new file mode 100644 index 00000000000000..93fd1d176ee57e --- /dev/null +++ b/_maps/map_files/Mafia/mafia_unit_test.dmm @@ -0,0 +1,598 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"c" = ( +/turf/open/floor/iron, +/area/centcom/mafia) +"i" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/iron, +/area/centcom/mafia) +"E" = ( +/obj/effect/landmark/mafia/town_center, +/turf/open/floor/iron, +/area/centcom/mafia) +"G" = ( +/turf/closed/indestructible, +/area/centcom/mafia) +"W" = ( +/obj/mafia_game_board, +/turf/open/floor/iron, +/area/centcom/mafia) +"Y" = ( +/turf/template_noop, +/area/template_noop) + +(1,1,1) = {" +G +G +G +G +G +G +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(2,1,1) = {" +G +W +i +i +i +W +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(3,1,1) = {" +G +i +c +c +c +i +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(4,1,1) = {" +G +i +c +E +c +i +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(5,1,1) = {" +G +i +c +c +c +i +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(6,1,1) = {" +G +W +i +i +i +W +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(7,1,1) = {" +G +G +G +G +G +G +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(8,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(9,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(10,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(11,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(12,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(13,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(14,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(15,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(16,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(17,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(18,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(19,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(20,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(21,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(22,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(23,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 9b8acb43075cfb..687ded631f7dee 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -589,6 +589,12 @@ "alE" = ( /turf/open/floor/iron, /area/station/security/courtroom) +"alF" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "alI" = ( /obj/machinery/door/window/left/directional/west{ dir = 4; @@ -2915,6 +2921,23 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/hallway/primary/central) +"bar" = ( +/obj/structure/table, +/obj/item/reagent_containers/cup/beaker{ + pixel_x = 10 + }, +/obj/item/flashlight/lamp{ + pixel_x = -7; + pixel_y = 18; + start_on = 0 + }, +/obj/item/kitchen/rollingpin{ + pixel_x = -4 + }, +/obj/effect/mapping_helpers/broken_floor, +/obj/machinery/light/small/dim/directional/west, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "bas" = ( /obj/machinery/airalarm/directional/west, /turf/open/floor/iron/chapel, @@ -4398,7 +4421,6 @@ /area/station/commons/dorms) "bAI" = ( /obj/machinery/disposal/bin, -/obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk, /obj/effect/turf_decal/bot, /obj/effect/decal/cleanable/cobweb/cobweb2, @@ -7652,6 +7674,13 @@ /obj/effect/mapping_helpers/airlock/access/any/supply/maintenance, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"cQn" = ( +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "cQx" = ( /obj/machinery/computer/atmos_control/nitrous_tank{ dir = 1 @@ -9871,17 +9900,6 @@ /obj/machinery/door/window/right/directional/west, /turf/open/floor/wood, /area/station/command/heads_quarters/captain/private) -"dIW" = ( -/obj/effect/turf_decal/siding/purple{ - dir = 8 - }, -/obj/machinery/atmospherics/components/binary/pump{ - dir = 1 - }, -/obj/effect/mapping_helpers/airalarm/mixingchamber_access, -/obj/machinery/airalarm/directional/west, -/turf/open/floor/iron/dark, -/area/station/science/ordnance/freezerchamber) "dJk" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -10074,6 +10092,24 @@ /obj/structure/reagent_dispensers/beerkeg, /turf/open/floor/wood, /area/station/maintenance/port/aft) +"dMt" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/camera/directional/east{ + c_tag = "Engineering Supermatter Port"; + network = list("ss13","engine") + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible, +/obj/machinery/airalarm/directional/east, +/obj/effect/mapping_helpers/airalarm/engine_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "engine" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/engine, +/area/station/engineering/supermatter/room) "dMv" = ( /obj/machinery/holopad, /obj/structure/cable, @@ -12525,6 +12561,10 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/atmos, /turf/open/floor/iron/dark, /area/station/engineering/atmospherics_engine) +"eDd" = ( +/obj/machinery/air_sensor/engine_chamber, +/turf/open/floor/engine, +/area/station/engineering/supermatter) "eDC" = ( /obj/structure/table/wood, /obj/effect/spawner/random/entertainment/deck, @@ -13144,6 +13184,13 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai_upload) +"eQr" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/machinery/light_switch/directional/south, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "eQs" = ( /obj/machinery/air_sensor/air_tank, /turf/open/floor/engine/air, @@ -13685,6 +13732,16 @@ /obj/item/food/pizzaslice/moldy/bacteria, /turf/open/floor/iron/white, /area/station/medical/abandoned) +"faW" = ( +/obj/machinery/power/apc/auto_name/directional/north, +/obj/structure/table, +/obj/structure/cable, +/obj/item/poster/random_official, +/obj/item/poster/random_official{ + pixel_y = 10 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "fbf" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -16207,6 +16264,10 @@ /obj/structure/table, /obj/structure/cable, /obj/effect/turf_decal/tile/red/half/contrasted, +/obj/machinery/fax{ + fax_name = "Security Office"; + name = "Security Office Fax Machine" + }, /turf/open/floor/iron/dark, /area/station/security/office) "fYq" = ( @@ -16222,6 +16283,9 @@ /obj/structure/cable, /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron/white, /area/station/medical/medbay/central) "fYC" = ( @@ -16385,6 +16449,18 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron, /area/station/hallway/primary/port) +"gcL" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/stripes/corner, +/obj/structure/cable, +/obj/machinery/button/door/directional/east{ + name = "Security Mech Garage Door Controls"; + id = "secmechbay"; + req_access = list("security") + }, +/turf/open/floor/iron, +/area/station/security/office) "gcU" = ( /obj/structure/disposalpipe/segment, /obj/effect/mapping_helpers/airlock/access/all/science/robotics, @@ -18193,6 +18269,15 @@ /obj/machinery/firealarm/directional/west, /turf/open/floor/iron/white, /area/station/science/xenobiology) +"gKH" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 1 + }, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/security/office) "gKK" = ( /obj/effect/turf_decal/stripes/white/line{ dir = 1 @@ -18450,6 +18535,11 @@ }, /turf/open/floor/iron/white, /area/station/medical/virology) +"gOT" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable, +/turf/open/floor/plating, +/area/station/security/mechbay) "gOY" = ( /obj/structure/chair{ dir = 8 @@ -20264,7 +20354,6 @@ "hyn" = ( /obj/machinery/airalarm/directional/west, /obj/effect/spawner/random/vending/snackvend, -/obj/machinery/airalarm/directional/west, /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/tile/neutral/opposingcorners{ dir = 1 @@ -20314,6 +20403,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) +"hza" = ( +/obj/vehicle/sealed/mecha/ripley/paddy/preset, +/turf/open/floor/iron/recharge_floor, +/area/station/security/mechbay) "hzt" = ( /obj/structure/transit_tube/curved/flipped, /obj/effect/turf_decal/tile/blue{ @@ -23037,6 +23130,10 @@ /obj/item/clothing/glasses/welding, /turf/open/floor/iron, /area/station/science/robotics/lab) +"iwH" = ( +/obj/machinery/atmospherics/pipe/smart/simple/dark/visible, +/turf/closed/wall/r_wall, +/area/station/science/ordnance) "iwL" = ( /obj/effect/spawner/structure/window/reinforced/tinted, /obj/structure/disposalpipe/segment{ @@ -24593,6 +24690,13 @@ }, /turf/open/floor/iron, /area/station/command/gateway) +"iVJ" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "iVN" = ( /obj/effect/spawner/structure/window/reinforced/tinted, /turf/open/floor/plating, @@ -24769,15 +24873,6 @@ }, /turf/open/floor/plating/airless, /area/station/science/ordnance/bomb) -"iYE" = ( -/obj/machinery/atmospherics/pipe/smart/simple/dark/visible, -/obj/effect/turf_decal/siding/purple{ - dir = 6 - }, -/obj/machinery/airalarm/directional/east, -/obj/effect/mapping_helpers/airalarm/mixingchamber_access, -/turf/open/floor/iron/dark, -/area/station/science/ordnance/burnchamber) "iYG" = ( /obj/effect/landmark/event_spawn, /obj/effect/turf_decal/tile/neutral{ @@ -26419,7 +26514,6 @@ /area/station/service/kitchen) "jAd" = ( /obj/machinery/door/airlock/maintenance, -/obj/structure/disposalpipe/segment, /obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance, /obj/effect/mapping_helpers/airlock/unres{ dir = 1 @@ -26595,8 +26689,8 @@ dir = 8 }, /obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = -6 + pixel_x = -6; + pixel_y = 6 }, /obj/item/storage/medkit/regular, /obj/item/reagent_containers/cup/bottle/multiver, @@ -28150,6 +28244,12 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/hallway/primary/central) +"kdy" = ( +/obj/structure/frame/computer{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/security/mechbay) "kdA" = ( /obj/machinery/door/airlock/mining{ name = "Warehouse" @@ -28798,6 +28898,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) +"kqM" = ( +/obj/effect/turf_decal/stripes/corner, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "kqZ" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, @@ -29714,20 +29821,6 @@ /obj/structure/sign/poster/official/help_others/directional/south, /turf/open/floor/iron/white, /area/station/medical/medbay/central) -"kKk" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/machinery/camera/directional/east{ - c_tag = "Engineering Supermatter Port"; - network = list("ss13","engine") - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible, -/obj/machinery/airalarm/directional/east, -/obj/effect/mapping_helpers/airalarm/engine_access, -/turf/open/floor/engine, -/area/station/engineering/supermatter) "kKp" = ( /obj/structure/rack, /obj/item/gun/energy/laser/carbine/practice{ @@ -30968,12 +31061,10 @@ /obj/structure/bed/medical{ dir = 8 }, -/obj/item/clothing/suit/jacket/straight_jacket, -/obj/item/clothing/glasses/blindfold, -/obj/item/clothing/mask/muzzle, /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 8 }, +/obj/machinery/iv_drip, /turf/open/floor/iron/white, /area/station/security/execution/transfer) "lgl" = ( @@ -31214,6 +31305,12 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/glass/reinforced, /area/station/science/research) +"llU" = ( +/obj/effect/turf_decal/stripes/line, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "lma" = ( /obj/structure/chair/stool/directional/north, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -33317,6 +33414,21 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/engineering/atmos) +"mcu" = ( +/obj/machinery/door/poddoor/shutters{ + dir = 8; + id = "secmechbay"; + name = "Security Mech Bay Shutters" + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/caution/stand_clear{ + dir = 4 + }, +/obj/effect/turf_decal/box, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "mcF" = ( /obj/structure/table, /obj/machinery/button/door{ @@ -35019,8 +35131,8 @@ dir = 1 }, /obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = 4 + pixel_x = 4; + pixel_y = 6 }, /turf/open/floor/iron, /area/station/cargo/miningoffice) @@ -36740,6 +36852,10 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) +"nkA" = ( +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, +/turf/closed/wall/r_wall, +/area/station/science/ordnance) "nkG" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible, /obj/machinery/meter, @@ -36910,7 +37026,6 @@ /turf/open/floor/iron, /area/station/commons/vacant_room/commissary) "nnt" = ( -/obj/vehicle/ridden/secway, /obj/effect/turf_decal/bot, /obj/structure/cable, /turf/open/floor/iron/dark, @@ -38183,23 +38298,6 @@ }, /turf/open/floor/iron/dark, /area/station/security/lockers) -"nJA" = ( -/obj/machinery/door/airlock/research/glass/incinerator/ordmix_interior, -/obj/effect/mapping_helpers/airlock/locked, -/obj/machinery/airlock_controller/incinerator_ordmix{ - pixel_x = -24 - }, -/obj/machinery/button/ignition/incinerator/ordmix{ - pixel_x = 24; - pixel_y = -6 - }, -/obj/machinery/button/door/incinerator_vent_ordmix{ - pixel_x = 24; - pixel_y = 8 - }, -/obj/effect/mapping_helpers/airlock/access/all/science/ordnance, -/turf/open/floor/engine, -/area/station/science/ordnance/burnchamber) "nJG" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -39650,6 +39748,12 @@ /obj/machinery/duct, /turf/open/floor/plating, /area/station/maintenance/port/aft) +"omA" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "omF" = ( /obj/machinery/teleport/station, /obj/machinery/status_display/evac/directional/north, @@ -39768,6 +39872,9 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) +"ope" = ( +/turf/closed/wall, +/area/station/security/mechbay) "oph" = ( /obj/structure/chair/wood/wings{ dir = 8 @@ -40049,11 +40156,15 @@ "ouj" = ( /obj/structure/bed/medical/emergency, /obj/structure/bed/medical/emergency, -/obj/machinery/iv_drip, -/obj/machinery/iv_drip, /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 6 }, +/obj/item/clothing/suit/jacket/straight_jacket, +/obj/item/clothing/suit/jacket/straight_jacket, +/obj/item/clothing/mask/muzzle, +/obj/item/clothing/mask/muzzle, +/obj/item/clothing/glasses/blindfold, +/obj/item/clothing/glasses/blindfold, /turf/open/floor/iron/white, /area/station/security/execution/transfer) "ouk" = ( @@ -41897,6 +42008,7 @@ /obj/effect/mapping_helpers/airlock/access/all/medical/coroner, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment, /turf/open/floor/iron/dark, /area/station/medical/morgue) "pdX" = ( @@ -42994,9 +43106,6 @@ /turf/open/floor/iron, /area/station/security/courtroom) "pyh" = ( -/obj/effect/turf_decal/trimline/red/filled/line{ - dir = 1 - }, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -43190,14 +43299,9 @@ /turf/open/floor/iron, /area/station/security/checkpoint/customs) "pBL" = ( -/obj/effect/turf_decal/trimline/red/filled/line{ - dir = 9 - }, /obj/machinery/newscaster/directional/west, -/obj/structure/table, -/obj/machinery/fax{ - fax_name = "Security Office"; - name = "Security Office Fax Machine" +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 8 }, /turf/open/floor/iron, /area/station/security/office) @@ -44615,13 +44719,11 @@ /obj/structure/bed/medical{ dir = 4 }, -/obj/item/clothing/suit/jacket/straight_jacket, -/obj/item/clothing/glasses/blindfold, -/obj/item/clothing/mask/muzzle, /obj/structure/cable, /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 4 }, +/obj/machinery/iv_drip, /turf/open/floor/iron/white, /area/station/security/execution/transfer) "qby" = ( @@ -50281,6 +50383,26 @@ /obj/effect/turf_decal/tile/blue/fourcorners, /turf/open/floor/iron/white, /area/station/medical/storage) +"saa" = ( +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/structure/cable, +/obj/structure/table, +/obj/machinery/camera/directional/west{ + c_tag = "Security - Office - Port" + }, +/obj/machinery/button/door/directional/west{ + id = "secmechbay"; + name = "Security Mech Garage Door Controls"; + req_access = list("security") + }, +/obj/item/circuitboard/computer/mech_bay_power_console, +/obj/item/stack/sheet/glass{ + pixel_y = 14 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "sab" = ( /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plating, @@ -52490,6 +52612,23 @@ /obj/machinery/light_switch/directional/north, /turf/open/floor/iron/white, /area/station/science/explab) +"sPH" = ( +/obj/machinery/door/airlock/research/glass/incinerator/ordmix_interior, +/obj/effect/mapping_helpers/airlock/locked, +/obj/machinery/airlock_controller/incinerator_ordmix{ + pixel_x = -24 + }, +/obj/machinery/button/ignition/incinerator/ordmix{ + pixel_x = 24; + pixel_y = -6 + }, +/obj/machinery/button/door/incinerator_vent_ordmix{ + pixel_x = 24; + pixel_y = 8 + }, +/obj/effect/mapping_helpers/airlock/access/all/science/ordnance, +/turf/open/floor/engine, +/area/station/science/ordnance) "sPV" = ( /obj/structure/closet/secure_closet/captains, /obj/structure/window/reinforced/spawner/directional/north, @@ -52534,6 +52673,18 @@ /obj/structure/window/reinforced/spawner/directional/east, /turf/open/floor/plating, /area/station/maintenance/port/aft) +"sQz" = ( +/obj/machinery/door/poddoor/shutters{ + dir = 8; + id = "secmechbay"; + name = "Security Mech Bay Shutters" + }, +/obj/effect/turf_decal/caution/stand_clear{ + dir = 4 + }, +/obj/effect/turf_decal/box, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "sQB" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -55133,23 +55284,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"tLG" = ( -/obj/structure/table, -/obj/item/reagent_containers/cup/beaker{ - pixel_x = 10 - }, -/obj/item/flashlight/lamp{ - pixel_x = -7; - pixel_y = 18; - start_on = 0 - }, -/obj/item/kitchen/rollingpin{ - pixel_x = -4 - }, -/obj/effect/mapping_helpers/broken_floor, -/obj/machinery/light/small/dim/directional/west, -/turf/open/floor/plating, -/area/station/maintenance/port/aft) "tLN" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk{ @@ -57137,6 +57271,19 @@ /obj/machinery/firealarm/directional/east, /turf/open/floor/iron, /area/station/service/bar) +"utV" = ( +/obj/machinery/atmospherics/pipe/smart/simple/dark/visible, +/obj/effect/turf_decal/siding/purple{ + dir = 6 + }, +/obj/machinery/airalarm/directional/east, +/obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnanceburn" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/iron/dark, +/area/station/science/ordnance) "uuc" = ( /obj/structure/chair/pew/left, /turf/open/floor/iron/chapel{ @@ -57165,6 +57312,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"uuO" = ( +/obj/machinery/mech_bay_recharge_port{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/security/mechbay) "uvw" = ( /obj/machinery/status_display/supply{ pixel_y = 32 @@ -57681,6 +57834,15 @@ /obj/structure/extinguisher_cabinet/directional/north, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"uEW" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "uFf" = ( /obj/machinery/holopad, /obj/effect/spawner/random/engineering/tracking_beacon, @@ -58731,6 +58893,12 @@ /obj/effect/turf_decal/trimline/red/filled/corner, /turf/open/floor/iron, /area/station/security/brig) +"uWs" = ( +/obj/machinery/computer/mech_bay_power_console{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/security/mechbay) "uWt" = ( /obj/structure/rack, /obj/item/stack/medical/mesh, @@ -61009,6 +61177,21 @@ /obj/structure/lattice, /turf/open/space/basic, /area/space/nearstation) +"vIL" = ( +/obj/effect/turf_decal/siding/purple{ + dir = 8 + }, +/obj/machinery/atmospherics/components/binary/pump{ + dir = 1 + }, +/obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/machinery/airalarm/directional/west, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnancefreezer" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/iron/dark, +/area/station/science/ordnance) "vIM" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -61676,6 +61859,16 @@ "vTX" = ( /turf/open/floor/iron/dark, /area/station/engineering/atmospherics_engine) +"vUa" = ( +/obj/structure/table, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/airalarm/directional/north, +/obj/item/stack/rods/two, +/obj/item/stack/cable_coil/five, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "vUx" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -61871,6 +62064,13 @@ }, /turf/open/floor/circuit/green/off, /area/station/science/research) +"vXj" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 9 + }, +/obj/machinery/light/small/directional/west, +/turf/open/floor/iron, +/area/station/security/office) "vXt" = ( /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible{ dir = 9 @@ -62669,6 +62869,9 @@ dir = 1 }, /area/station/engineering/storage_shared) +"wlz" = ( +/turf/closed/wall/r_wall, +/area/station/security/mechbay) "wlL" = ( /obj/effect/turf_decal/tile/yellow/half/contrasted{ dir = 4 @@ -62696,6 +62899,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/science/robotics/lab) +"wmr" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 8 + }, +/obj/vehicle/ridden/secway, +/turf/open/floor/iron, +/area/station/security/office) "wmz" = ( /obj/machinery/atmospherics/pipe/smart/simple/dark/visible, /turf/open/floor/iron, @@ -63388,6 +63598,15 @@ /obj/item/flashlight/lamp, /turf/open/floor/iron/dark, /area/station/security/execution/education) +"wzq" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/security/office) "wzy" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -64568,9 +64787,9 @@ /turf/open/floor/iron, /area/station/hallway/primary/aft) "wVt" = ( -/obj/item/storage/box/deputy, /obj/structure/table, /obj/item/radio/intercom/directional/west, +/obj/item/storage/box/deputy, /turf/open/floor/iron/dark, /area/station/security/office) "wVy" = ( @@ -64910,6 +65129,13 @@ /obj/structure/cable, /turf/open/floor/iron/white/smooth_large, /area/station/command/heads_quarters/cmo) +"xcv" = ( +/obj/effect/turf_decal/stripes/line, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "xcz" = ( /obj/effect/turf_decal/stripes/corner, /obj/structure/reagent_dispensers/watertank, @@ -65344,6 +65570,15 @@ }, /turf/open/floor/iron, /area/station/commons/storage/tools) +"xkq" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/security/office) "xkr" = ( /obj/effect/turf_decal/plaque{ icon_state = "L13" @@ -66761,6 +66996,10 @@ }, /turf/open/floor/iron/dark, /area/station/command/bridge) +"xJv" = ( +/obj/machinery/light/directional/north, +/turf/open/floor/iron/recharge_floor, +/area/station/security/mechbay) "xJA" = ( /obj/structure/sign/warning/docking, /turf/closed/wall, @@ -84638,7 +84877,7 @@ pOa uOH jUb xIK -tLG +bar nBp dqN pqz @@ -97158,11 +97397,11 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa +gdb +gdb +gdb +gdb +gdb iTZ ahj ahj @@ -97413,11 +97652,6 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa rrt lMJ gdb @@ -97425,12 +97659,17 @@ rDE fOw nQC ikZ +vXj +iGj +iGj +iGj +iGj pBL iGj iGj iGj vdi -iGj +wmr ljf kYg nnt @@ -97670,11 +97909,6 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa rrt aaa vaB @@ -97682,6 +97916,11 @@ kKp iDq mPT fCn +gKH +gcL +wzq +wzq +xkq pyh aja lyF @@ -97927,11 +98166,6 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa rrt lMJ gdb @@ -97939,6 +98173,11 @@ hhl fOf eZI dgD +ope +ope +mcu +sQz +ope kYg vGt fYb @@ -98186,16 +98425,16 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa gdb nMV luV rqs dgD +faW +saa +uEW +eQr +ope jGl kxA wxj @@ -98443,16 +98682,16 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa gdb ksg aGM rpz dgD +vUa +cQn +kqM +omA +ope jGl kxA xXh @@ -98698,11 +98937,6 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa rrt lMJ gdb @@ -98710,6 +98944,11 @@ ksg aGM rpz dgD +xJv +alF +xcv +hza +ope rtI kxA kAT @@ -98808,7 +99047,7 @@ raK dOA gyQ qSP -dIW +vIL iTc qfQ cLk @@ -98955,11 +99194,6 @@ aaa aav aaa aaa -aaa -aaa -aaa -aaa -aaa rrt aaa ikZ @@ -98967,6 +99201,11 @@ ksg vuP rpz dgD +uuO +alF +xcv +uuO +ope jGl kxA qmu @@ -99212,11 +99451,6 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa rrt lMJ gdb @@ -99224,6 +99458,11 @@ dhN nuI qJa dgD +kdy +iVJ +llU +uWs +ope kYg jAN wxj @@ -99470,17 +99709,17 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa tLb gdb ikZ gdb ikZ gdb +wlz +gOT +gOT +wlz +wlz hYd olD mLx @@ -99584,7 +99823,7 @@ fhi fhi uEo fiS -hqj +gyQ eRn hqj hqj @@ -99841,7 +100080,7 @@ huj fhi xEU iqx -deY +nkA gil deY oet @@ -100098,7 +100337,7 @@ fhi fhi fhi twy -nJA +sPH nZL bEv cgP @@ -100354,8 +100593,8 @@ jwj ujk jvo aHH -iYE -pCa +utV +iwH dEF pCa cOT @@ -110299,7 +110538,7 @@ otn dRN wdB oET -kKk +dMt qLw vQt qLw @@ -111326,7 +111565,7 @@ wBE oNs eyD qZB -oNs +eDd hRl jWE auc diff --git a/_maps/map_files/NSVBlueshift/Blueshift.dmm b/_maps/map_files/NSVBlueshift/Blueshift.dmm index 30af5242388c37..1c57902b587e29 100644 --- a/_maps/map_files/NSVBlueshift/Blueshift.dmm +++ b/_maps/map_files/NSVBlueshift/Blueshift.dmm @@ -471,6 +471,9 @@ /turf/open/floor/plating, /area/station/maintenance/department/eva) "aey" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/interrogation) "aeM" = ( @@ -7467,6 +7470,8 @@ dir = 4 }, /obj/effect/mapping_helpers/airlock/access/all/security/general, +/obj/structure/cable, +/obj/machinery/door/firedoor, /turf/open/floor/iron, /area/station/security/interrogation) "bnZ" = ( @@ -7548,10 +7553,6 @@ }, /obj/effect/mapping_helpers/requests_console/information, /obj/effect/mapping_helpers/requests_console/assistance, -/obj/machinery/requests_console/directional/west{ - department = "Toxins Lab"; - name = "Toxins Requests Console" - }, /obj/effect/mapping_helpers/requests_console/information, /obj/effect/mapping_helpers/requests_console/assistance, /obj/effect/turf_decal/bot, @@ -7572,12 +7573,23 @@ /turf/open/floor/iron, /area/station/science/ordnance) "bop" = ( -/obj/effect/decal/cleanable/dirt{ - icon_state = "dirt-flat-1" +/obj/effect/turf_decal/tile/dark_blue/half/contrasted{ + dir = 1 }, -/obj/effect/spawner/random/trash/graffiti, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) +/obj/effect/turf_decal/stripes{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 1 + }, +/obj/structure/table, +/obj/item/poster/random_official{ + pixel_y = 10 + }, +/obj/item/poster/random_official, +/obj/machinery/firealarm/directional/north, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "bos" = ( /obj/structure/table, /obj/effect/decal/cleanable/dirt{ @@ -8991,10 +9003,17 @@ /turf/open/floor/wood, /area/station/medical/exam_room) "bAo" = ( -/obj/structure/rack, -/obj/effect/spawner/random/maintenance, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) +/obj/effect/turf_decal/tile/dark_blue/half/contrasted{ + dir = 4 + }, +/obj/effect/turf_decal/stripes{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "bAt" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -13830,7 +13849,7 @@ /obj/structure/disposalpipe/segment{ dir = 10 }, -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /turf/open/floor/iron, @@ -17255,6 +17274,7 @@ /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2{ dir = 9 }, +/obj/structure/cable, /turf/open/floor/iron, /area/station/security/interrogation) "cOS" = ( @@ -17935,7 +17955,7 @@ /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2{ dir = 10 }, -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /turf/open/floor/iron, @@ -18553,6 +18573,9 @@ /obj/machinery/duct, /turf/open/floor/iron/freezer, /area/station/command/heads_quarters/captain/private) +"cZT" = ( +/turf/closed/wall/r_wall, +/area/station/security/mechbay) "cZU" = ( /obj/effect/turf_decal/trimline/purple/filled/line, /obj/structure/cable, @@ -21275,6 +21298,15 @@ /obj/effect/turf_decal/stripes/box, /turf/open/floor/plating/airless, /area/station/engineering/atmos/upper) +"dyS" = ( +/obj/effect/turf_decal/tile/dark_blue/half/contrasted, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2, +/obj/effect/turf_decal/stripes, +/obj/effect/turf_decal/stripes/blue/line, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "dyT" = ( /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/stripes/line{ @@ -23590,11 +23622,10 @@ /turf/open/floor/plating, /area/station/maintenance/fore/upper) "dTy" = ( -/obj/machinery/door/airlock/maintenance_hatch{ - name = "Security Maintenance" - }, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "dTz" = ( /obj/structure/extinguisher_cabinet/directional/west, /obj/machinery/light/directional/south, @@ -27214,7 +27245,7 @@ /area/station/commons/dorms/room2) "ezm" = ( /obj/effect/turf_decal/siding/wood/corner, -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -28080,6 +28111,16 @@ }, /turf/open/floor/iron, /area/station/maintenance/port/upper) +"eGr" = ( +/obj/effect/turf_decal/tile/dark_blue/half/contrasted, +/obj/machinery/computer/mech_bay_power_console{ + dir = 1 + }, +/obj/effect/turf_decal/bot_blue, +/obj/effect/turf_decal/stripes, +/obj/effect/turf_decal/stripes/blue/line, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "eGt" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold/scrubbers/hidden/layer2{ @@ -29646,6 +29687,21 @@ /obj/item/trash/energybar, /turf/open/floor/plating, /area/station/maintenance/fore/upper) +"eSi" = ( +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/stripes{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/security/brig) "eSj" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4{ @@ -30646,7 +30702,6 @@ "fax" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/engine, /area/station/science/xenobiology) "faz" = ( @@ -33230,7 +33285,6 @@ "fwI" = ( /obj/effect/turf_decal/stripes/line, /obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/plating, /area/station/cargo/drone_bay) "fwM" = ( @@ -34776,7 +34830,6 @@ /area/station/service/theater/abandoned) "fLn" = ( /obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/south, /obj/structure/window/reinforced/spawner/directional/west, /turf/open/floor/engine, /area/station/science/xenobiology) @@ -36166,6 +36219,10 @@ dir = 4 }, /area/station/maintenance/disposal/incinerator) +"fYr" = ( +/obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4, +/turf/open/floor/circuit, +/area/station/security/mechbay) "fYz" = ( /obj/structure/closet/emcloset, /obj/effect/turf_decal/bot, @@ -36941,6 +36998,14 @@ /obj/machinery/duct, /turf/open/floor/wood, /area/station/command/heads_quarters/captain/private) +"geL" = ( +/obj/effect/turf_decal/stripes/box, +/obj/effect/turf_decal/stripes/blue/box, +/obj/machinery/camera/directional/west{ + c_tag = "Security - Mechbay" + }, +/turf/open/floor/iron/recharge_floor, +/area/station/security/mechbay) "geQ" = ( /obj/structure/lattice/catwalk, /obj/structure/cable, @@ -38548,7 +38613,7 @@ /turf/open/floor/iron, /area/station/commons/vacant_room/commissary) "gsK" = ( -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /turf/open/floor/iron/white, @@ -39449,6 +39514,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold/scrubbers/hidden/layer2{ dir = 1 }, +/obj/structure/cable, /turf/open/floor/iron, /area/station/security/interrogation) "gAC" = ( @@ -41577,8 +41643,12 @@ /turf/open/floor/iron, /area/station/hallway/primary/central) "gTF" = ( -/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2{ - dir = 6 +/obj/machinery/atmospherics/pipe/smart/manifold/scrubbers/hidden/layer2{ + dir = 8 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4{ + dir = 5 }, /turf/open/floor/iron, /area/station/security/interrogation) @@ -41714,8 +41784,6 @@ dir = 1 }, /obj/structure/window/reinforced/spawner/directional/east, -/obj/structure/window/reinforced/spawner/directional/east, -/obj/structure/window/reinforced/spawner/directional/south, /obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/engine, /area/station/science/xenobiology) @@ -42119,14 +42187,8 @@ "gZm" = ( /turf/open/floor/wood, /area/station/service/library) -"gZp" = ( -/obj/structure/window/reinforced/spawner/directional/east, -/obj/structure/window/reinforced/spawner/directional/east, -/turf/open/floor/engine, -/area/station/science/xenobiology) "gZu" = ( -/obj/machinery/computer/atmos_control/noreconnect{ - atmos_chambers = list("ordnancegas1"="Burn Chamber","ordnancegas2"="Freezer Chamber"); +/obj/machinery/computer/atmos_control/ordnancemix{ dir = 8 }, /turf/open/floor/engine{ @@ -43466,6 +43528,10 @@ /obj/machinery/duct, /turf/open/floor/wood, /area/station/commons/dorms/vacantroom) +"hlw" = ( +/obj/machinery/air_sensor/engine_chamber, +/turf/open/floor/engine, +/area/station/engineering/supermatter) "hlC" = ( /obj/effect/turf_decal/box, /obj/machinery/holopad, @@ -43960,6 +44026,15 @@ /obj/machinery/duct, /turf/open/floor/iron/white, /area/station/medical/virology) +"hpF" = ( +/obj/effect/turf_decal/tile/dark_blue/half/contrasted, +/obj/machinery/power/apc/auto_name/directional/south, +/obj/structure/cable, +/obj/effect/turf_decal/stripes, +/obj/effect/turf_decal/stripes/blue/line, +/obj/machinery/light/directional/south, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "hpS" = ( /obj/effect/decal/cleanable/dirt{ icon_state = "dirt-flat-1" @@ -45004,6 +45079,26 @@ }, /turf/open/floor/wood/parquet, /area/station/common/night_club) +"hAz" = ( +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes{ + dir = 4 + }, +/obj/effect/turf_decal/stripes{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 8 + }, +/obj/machinery/door/poddoor/shutters/window{ + id = "SecMech"; + name = "Security Mechbay Shutters" + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "hAB" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -46143,7 +46238,7 @@ /turf/open/floor/engine, /area/station/science/ordnance) "hJF" = ( -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /obj/effect/turf_decal/trimline/purple/filled/line{ @@ -53353,7 +53448,7 @@ /obj/structure/railing/corner/end/flip{ dir = 8 }, -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /turf/open/floor/iron, @@ -54290,7 +54385,6 @@ "jcw" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/north, /obj/structure/disposalpipe/trunk{ dir = 1 }, @@ -54661,7 +54755,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /turf/open/floor/iron, @@ -57506,6 +57600,24 @@ dir = 4 }, /area/station/cargo/miningoffice) +"jEw" = ( +/obj/effect/turf_decal/tile/dark_blue/half/contrasted{ + dir = 8 + }, +/obj/machinery/cell_charger_multi/wall_mounted/directional/west, +/obj/effect/turf_decal/stripes{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 8 + }, +/obj/structure/table, +/obj/item/circuitboard/computer/mech_bay_power_console, +/obj/item/stack/sheet/glass{ + pixel_y = 14 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "jEz" = ( /turf/open/floor/iron/dark, /area/station/security/prison/garden) @@ -58900,8 +59012,6 @@ dir = 1 }, /obj/structure/window/reinforced/spawner/directional/west, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/structure/window/reinforced/spawner/directional/south, /obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/engine, /area/station/science/xenobiology) @@ -60799,10 +60909,14 @@ /obj/structure/table, /obj/machinery/airalarm/directional/east, /obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnanceburn" + }, /turf/open/floor/engine{ icon_state = "floor" }, -/area/station/science/ordnance/burnchamber) +/area/station/science/ordnance) "kfv" = ( /obj/effect/decal/cleanable/dirt{ icon_state = "dirt-flat-1" @@ -61301,7 +61415,7 @@ }, /obj/structure/window/reinforced/spawner/directional/west, /obj/effect/turf_decal/stripes/blue/line{ - dir = 4 + dir = 1 }, /obj/structure/closet/secure_closet/personal, /turf/open/floor/iron/dark, @@ -63117,6 +63231,14 @@ /obj/item/stack/cable_coil/five, /turf/open/floor/iron, /area/station/commons/vacant_room/commissary) +"kxe" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2{ + dir = 10 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "kxk" = ( /obj/structure/chair/comfy/shuttle{ dir = 8 @@ -63533,7 +63655,7 @@ "kAi" = ( /obj/machinery/door/firedoor, /obj/machinery/firealarm/directional/south, -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /obj/structure/railing/corner/end/flip{ @@ -64073,7 +64195,6 @@ /area/station/cargo/miningoffice) "kFe" = ( /obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/engine, /area/station/science/xenobiology) "kFn" = ( @@ -67126,7 +67247,7 @@ /obj/structure/railing{ dir = 8 }, -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /turf/open/floor/iron, @@ -68045,26 +68166,14 @@ /obj/machinery/suit_storage_unit/standard_unit, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/storage/eva) -"lpP" = ( -/obj/structure/disposalpipe/trunk{ - dir = 2 - }, -/obj/structure/disposaloutlet{ - dir = 1 - }, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/south, -/turf/open/floor/engine, -/area/station/science/xenobiology) "lpQ" = ( /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/science/power_station) "lpR" = ( -/obj/machinery/doppler_array, /obj/effect/turf_decal/bot_red, +/obj/machinery/doppler_array, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) "lpV" = ( @@ -69905,6 +70014,10 @@ /obj/machinery/atmospherics/components/binary/pump{ name = "Gas to Chamber" }, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "engine" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, /turf/open/floor/engine, /area/station/engineering/supermatter) "lGz" = ( @@ -70071,10 +70184,17 @@ /turf/open/floor/plating, /area/station/maintenance/port/fore) "lHT" = ( -/obj/structure/closet/crate/trashcart/filled, -/obj/effect/spawner/random/contraband/cannabis, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) +/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted, +/obj/machinery/recharge_station, +/obj/effect/turf_decal/stripes{ + dir = 6 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 9 + }, +/obj/machinery/light_switch/directional/south, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "lHV" = ( /obj/structure/railing/corner{ dir = 8 @@ -73615,6 +73735,23 @@ /obj/machinery/duct, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"mmu" = ( +/obj/effect/turf_decal/tile/dark_blue/half/contrasted{ + dir = 1 + }, +/obj/machinery/airalarm/directional/north, +/obj/effect/turf_decal/stripes{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 1 + }, +/obj/structure/table, +/obj/item/stack/rods/two, +/obj/item/stack/cable_coil/five, +/obj/machinery/light/directional/north, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "mmz" = ( /obj/effect/turf_decal/stripes{ dir = 4 @@ -75161,7 +75298,7 @@ /area/station/science/xenobiology) "mBe" = ( /obj/structure/window/reinforced/spawner/directional/west, -/obj/structure/window/reinforced/spawner/directional/west, +/obj/structure/window/reinforced/spawner/directional/north, /turf/open/floor/engine, /area/station/science/xenobiology) "mBt" = ( @@ -75179,6 +75316,21 @@ }, /turf/open/floor/iron/cafeteria, /area/station/service/kitchen) +"mBw" = ( +/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{ + dir = 1 + }, +/obj/machinery/mech_bay_recharge_port{ + dir = 2 + }, +/obj/effect/turf_decal/stripes{ + dir = 9 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 6 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "mBC" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2{ @@ -81322,6 +81474,29 @@ /obj/machinery/space_heater, /turf/open/floor/plating, /area/station/maintenance/fore/upper) +"nDO" = ( +/obj/effect/turf_decal/caution/stand_clear/blue{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes{ + dir = 4 + }, +/obj/effect/turf_decal/stripes{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 8 + }, +/obj/machinery/door/poddoor/shutters/window{ + id = "SecMech"; + name = "Security Mechbay Shutters" + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "nDT" = ( /obj/effect/turf_decal/tile/red, /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2{ @@ -83101,7 +83276,6 @@ /area/station/hallway/secondary/entry) "nSZ" = ( /obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/north, /turf/open/floor/engine, /area/station/science/xenobiology) "nTd" = ( @@ -86614,7 +86788,7 @@ /obj/structure/railing/corner/end{ dir = 8 }, -/obj/structure/railing/corner/end{ +/obj/structure/railing/corner/end/flip{ dir = 4 }, /turf/open/floor/iron/dark, @@ -88814,7 +88988,7 @@ color = "#DE3A3A"; dir = 1 }, -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /obj/structure/railing/corner/end/flip{ @@ -91797,7 +91971,6 @@ "pnj" = ( /obj/machinery/hydroponics/constructable, /obj/structure/flora/bush/sparsegrass, -/obj/machinery/hydroponics/constructable, /turf/open/floor/grass, /area/station/security/prison/garden) "pnk" = ( @@ -96937,6 +97110,26 @@ /obj/structure/railing/corner/end/flip, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"qgJ" = ( +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/machinery/button/door/directional/south{ + name = "Security Mech Garage Door Controls"; + id = "SecMech"; + req_access = list("security") + }, +/obj/effect/turf_decal/stripes{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/security/brig) "qgM" = ( /obj/machinery/chem_master/condimaster{ name = "HoochMaster 2000" @@ -97609,9 +97802,7 @@ /turf/open/floor/iron, /area/station/hallway/primary/upper) "qmn" = ( -/obj/machinery/air_sensor{ - chamber_id = "ordnancegas1" - }, +/obj/machinery/air_sensor/ordnance_burn_chamber, /turf/open/floor/engine, /area/station/science/ordnance/burnchamber) "qmr" = ( @@ -99924,12 +100115,11 @@ }, /area/station/hallway/primary/central) "qDO" = ( -/obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4{ - dir = 5 - }, +/obj/machinery/atmospherics/pipe/smart/manifold/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2{ dir = 4 }, +/obj/structure/cable, /turf/open/floor/iron, /area/station/security/interrogation) "qDP" = ( @@ -108312,13 +108502,11 @@ }, /area/station/engineering/gravity_generator) "rZq" = ( -/obj/machinery/portable_atmospherics/scrubber, -/obj/effect/turf_decal/bot, -/obj/effect/decal/cleanable/dirt{ - icon_state = "dirt-flat-1" - }, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) +/obj/effect/turf_decal/stripes/box, +/obj/effect/turf_decal/stripes/blue/box, +/obj/vehicle/sealed/mecha/ripley/paddy/preset, +/turf/open/floor/iron/recharge_floor, +/area/station/security/mechbay) "rZu" = ( /obj/item/storage/crayons{ pixel_x = 2; @@ -112164,12 +112352,6 @@ /obj/effect/decal/remains/human, /turf/open/floor/plating, /area/station/security/courtroom) -"sFT" = ( -/obj/structure/window/reinforced/spawner/directional/west, -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/north, -/turf/open/floor/engine, -/area/station/science/xenobiology) "sFU" = ( /obj/machinery/light/small/directional/north, /turf/open/floor/plating, @@ -113662,7 +113844,7 @@ /area/station/maintenance/department/chapel) "sSF" = ( /obj/structure/lattice/catwalk, -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /obj/structure/railing/corner/end/flip{ @@ -119954,10 +120136,20 @@ /turf/open/floor/iron, /area/station/engineering/storage) "tUd" = ( -/obj/machinery/portable_atmospherics/pump, -/obj/effect/turf_decal/bot, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) +/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{ + dir = 8 + }, +/obj/machinery/mech_bay_recharge_port{ + dir = 1 + }, +/obj/effect/turf_decal/stripes{ + dir = 10 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 5 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "tUg" = ( /obj/machinery/door/airlock/security{ name = "Interrogation Monitoring" @@ -119968,8 +120160,12 @@ /obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4, /obj/structure/disposalpipe/segment, /obj/effect/mapping_helpers/airlock/access/all/security/general, +/obj/machinery/door/firedoor, /turf/open/floor/iron/dark, /area/station/security/interrogation) +"tUj" = ( +/turf/open/floor/circuit, +/area/station/security/mechbay) "tUm" = ( /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4, @@ -121667,10 +121863,14 @@ }, /obj/machinery/airalarm/directional/south, /obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnancefreezer" + }, /turf/open/floor/engine{ icon_state = "darkfull" }, -/area/station/science/ordnance/freezerchamber) +/area/station/science/ordnance) "uja" = ( /obj/effect/turf_decal/tile/red, /obj/effect/turf_decal/tile/red{ @@ -123093,6 +123293,13 @@ }, /turf/open/floor/wood, /area/station/service/hydroponics/garden/abandoned) +"uut" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "uuu" = ( /obj/effect/spawner/random/trash/cigbutt, /obj/effect/decal/cleanable/dirt{ @@ -123381,7 +123588,7 @@ }, /obj/structure/window/reinforced/spawner/directional/east, /obj/effect/turf_decal/stripes/blue/line{ - dir = 8 + dir = 1 }, /turf/open/floor/iron/dark, /area/station/security/lockers) @@ -128168,12 +128375,12 @@ /area/station/commons/dorms) "vof" = ( /obj/docking_port/stationary{ - dheight = 43; dir = 4; height = 19; name = "Deprecated Port Dock"; shuttle_id = "whiteship_home"; - width = 55 + width = 55; + dwidth = 43 }, /turf/open/space/basic, /area/space) @@ -128299,10 +128506,9 @@ /turf/open/floor/iron/cafeteria, /area/station/service/kitchen) "vpe" = ( -/obj/structure/trash_pile, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "vpn" = ( /obj/structure/extinguisher_cabinet/directional/south, /turf/open/floor/iron/dark/side{ @@ -132851,7 +133057,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 1 }, -/obj/structure/railing/corner/end{ +/obj/structure/railing/corner/end/flip{ dir = 4 }, /turf/open/floor/iron, @@ -132879,7 +133085,6 @@ "wbW" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/north, /obj/structure/disposalpipe/trunk{ dir = 1 }, @@ -133018,9 +133223,7 @@ /obj/machinery/atmospherics/pipe/heat_exchanging/simple/layer4{ dir = 4 }, -/obj/machinery/air_sensor{ - chamber_id = "ordnancegas2" - }, +/obj/machinery/air_sensor/ordnance_freezer_chamber, /turf/open/floor/engine, /area/station/science/ordnance/freezerchamber) "wcJ" = ( @@ -133037,6 +133240,12 @@ }, /turf/open/floor/grass, /area/station/science/research) +"wcZ" = ( +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2{ + dir = 4 + }, +/turf/open/floor/circuit, +/area/station/security/mechbay) "wdb" = ( /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ dir = 4 @@ -135005,7 +135214,6 @@ /obj/effect/turf_decal/box/white{ color = "#52B4E9" }, -/obj/machinery/portable_atmospherics/canister/anesthetic_mix, /obj/effect/turf_decal/tile/blue{ dir = 4 }, @@ -135592,7 +135800,7 @@ dir = 8 }, /obj/effect/landmark/generic_maintenance_landmark, -/obj/structure/railing/corner/end/flip{ +/obj/structure/railing/corner/end{ dir = 4 }, /turf/open/floor/iron, @@ -138925,9 +139133,23 @@ /turf/open/floor/iron/white/telecomms, /area/station/tcommsat/server) "wZT" = ( -/obj/effect/spawner/random/structure/chair_maintenance, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) +/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{ + dir = 4 + }, +/obj/machinery/button/door/directional/east{ + name = "Security Mech Garage Door Controls"; + id = "SecMech"; + req_access = list("security") + }, +/obj/machinery/recharge_station, +/obj/effect/turf_decal/stripes{ + dir = 5 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 10 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "wZU" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt{ @@ -140031,12 +140253,16 @@ /obj/effect/turf_decal/trimline/blue/filled/warning{ dir = 1 }, -/obj/machinery/door/airlock/maintenance_hatch{ - name = "Security Maintenance" - }, /obj/effect/mapping_helpers/airlock/access/all/security/general, +/obj/structure/cable, +/obj/machinery/door/airlock/security{ + name = "Security Mechbay" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2, /turf/open/floor/iron, -/area/station/maintenance/port/fore) +/area/station/security/mechbay) "xkf" = ( /obj/machinery/door/airlock/wood{ name = "Sauna" @@ -144293,7 +144519,6 @@ dir = 1 }, /obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/south, /obj/structure/window/reinforced/spawner/directional/east, /turf/open/floor/engine, /area/station/science/xenobiology) @@ -144323,7 +144548,6 @@ "xXm" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/north, /turf/open/floor/engine, /area/station/science/xenobiology) "xXo" = ( @@ -145946,6 +146170,20 @@ "yjE" = ( /turf/closed/wall, /area/station/maintenance/thruster_room/central) +"yjN" = ( +/obj/effect/turf_decal/tile/dark_blue/half/contrasted{ + dir = 1 + }, +/obj/machinery/computer/mech_bay_power_console, +/obj/effect/turf_decal/bot_blue, +/obj/effect/turf_decal/stripes{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/blue/line{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "yjO" = ( /obj/structure/rack, /obj/effect/spawner/random/maintenance/two, @@ -146119,6 +146357,7 @@ }, /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/simple/supply/hidden/layer4, +/obj/structure/cable, /turf/open/floor/iron, /area/station/security/interrogation) "ylw" = ( @@ -170936,13 +171175,13 @@ lCn rKn war nbK -rKn -rKn -ttc -rKn -rKn -rKn -rKn +tNz +tNz +tNz +tNz +tNz +tNz +tNz aQk fbq wZU @@ -171193,13 +171432,13 @@ rKn rKn plI nWK -rKn -ufv -mjK -rKn +tNz +mBw +geL +jEw rZq tUd -rKn +tNz ggF wMc mWp @@ -171450,13 +171689,13 @@ etj rKn xrJ ejO -rKn -ttc -rKn -rKn -kbf -kbf tNz +yjN +vpe +tUj +uut +eGr +cZT fAw fAw fAw @@ -171707,13 +171946,13 @@ rKn rKn rKn rKn -rKn -tcI -rKn -vpe -kbf -wZT tNz +mmu +tUj +vpe +wcZ +hpF +cZT bbn dqw eBG @@ -171964,12 +172203,12 @@ mjK kbf ttc ttc -kbf +tNz bop dTy -ttc -kbf -mjK +fYr +kxe +dyS xkc aey gTF @@ -172037,9 +172276,9 @@ xNW tvB waa uYL -cvi -sGN dty +sGN +cvi ckv lKd vDU @@ -172221,13 +172460,13 @@ rKn kif tPT ufv -mjK +tNz wZT -rKn -hHH +bAo +bAo bAo lHT -tNz +cZT lSs qDO uro @@ -172479,12 +172718,12 @@ tNz tNz cue tNz -tNz -tNz -tNz -tNz -tNz -tNz +cZT +hAz +nDO +hAz +fAw +fAw fAw bnX fAw @@ -172737,9 +172976,9 @@ kcW cAi bVB yiK -wYY -wYY -tbW +eSi +eSi +qgJ fAw uNk pre @@ -177752,7 +177991,7 @@ jbe nxi tBq kQu -qax +hlw mdF qax pTu @@ -242241,7 +242480,7 @@ lcM bOU mya pWp -sFT +mBe tyf tyf fDT @@ -242748,8 +242987,8 @@ rPB ttS beQ dfM -gZp -gZp +dNw +dNw gUs rJh dfF @@ -243012,7 +243251,7 @@ iai lAF tvg ono -sFT +mBe tyf tyf fDT @@ -243776,8 +244015,8 @@ rPB ajP xep dfM -mBe -mBe +tyf +tyf jQj lRC bgt @@ -244549,7 +244788,7 @@ tzR gDN tyf tyf -lpP +jQj plv eUV kzI diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 62ef5d9b6481b2..9faf41aca0f409 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -1600,9 +1600,9 @@ dir = 8 }, /obj/machinery/atmospherics/components/unary/outlet_injector/on{ - volume_rate = 200; dir = 8; - initialize_directions = 8 + initialize_directions = 8; + volume_rate = 200 }, /turf/open/floor/engine, /area/station/science/cytology) @@ -3259,6 +3259,9 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/exit) +"aRU" = ( +/turf/closed/wall, +/area/station/security/mechbay) "aRX" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -13011,15 +13014,9 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/railing{ - dir = 8 - }, -/obj/machinery/door/firedoor/border_only{ - dir = 8 - }, /obj/machinery/duct, /turf/open/floor/catwalk_floor, -/area/station/maintenance/floor4/port) +/area/station/security/mechbay) "dqB" = ( /obj/item/clothing/mask/breath{ pixel_x = -4 @@ -18416,13 +18413,8 @@ /turf/open/floor/pod/light, /area/station/maintenance/floor3/starboard/aft) "eNj" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/closet/emcloset/anchored, -/obj/machinery/door/firedoor/border_only{ - dir = 1 - }, -/turf/open/floor/pod/light, -/area/station/maintenance/floor4/port) +/turf/closed/wall/r_wall, +/area/station/security/mechbay) "eNk" = ( /obj/machinery/door/firedoor/heavy, /obj/effect/turf_decal/stripes/line{ @@ -18532,6 +18524,17 @@ dir = 1 }, /area/station/commons/locker) +"ePC" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/orange/visible, +/obj/structure/cable, +/obj/machinery/airalarm/directional/east, +/obj/effect/mapping_helpers/airalarm/engine_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "engine" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/engine, +/area/station/engineering/supermatter/room) "ePH" = ( /obj/structure/railing{ dir = 4 @@ -20470,6 +20473,21 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/service/hydroponics) +"ftt" = ( +/obj/structure/table, +/obj/structure/cable, +/obj/machinery/power/apc/auto_name/directional/north, +/obj/item/radio/intercom/directional/west, +/obj/effect/spawner/random/engineering/tool{ + pixel_x = 1; + pixel_y = 3 + }, +/obj/effect/spawner/random/engineering/tool{ + pixel_x = 1; + pixel_y = 3 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "ftu" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, @@ -23318,6 +23336,10 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/cargo/miningdock) +"ghe" = ( +/obj/effect/baseturf_helper/reinforced_plating/ceiling, +/turf/open/floor/engine, +/area/station/engineering/supermatter) "ghg" = ( /obj/effect/turf_decal/trimline/yellow/warning{ dir = 10 @@ -23654,6 +23676,13 @@ }, /turf/open/floor/iron, /area/station/security/brig) +"glU" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/machinery/air_sensor/engine_chamber, +/turf/open/floor/engine, +/area/station/engineering/supermatter) "glW" = ( /obj/structure/table, /obj/item/toy/cards/deck, @@ -26034,12 +26063,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/treatment_center) -"gSd" = ( -/obj/effect/baseturf_helper/reinforced_plating/ceiling, -/obj/machinery/airalarm/directional/south, -/obj/effect/mapping_helpers/airalarm/engine_access, -/turf/open/floor/engine, -/area/station/engineering/supermatter) "gSj" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -28165,6 +28188,14 @@ }, /turf/open/floor/pod/light, /area/station/maintenance/floor3/starboard/fore) +"hvb" = ( +/obj/machinery/mech_bay_recharge_port{ + dir = 2 + }, +/obj/effect/turf_decal/tile/red/anticorner, +/obj/machinery/light/directional/east, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "hvc" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -34766,8 +34797,8 @@ /obj/structure/table/glass, /obj/item/radio/intercom/directional/south, /obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = -6 + pixel_x = -6; + pixel_y = 6 }, /obj/item/storage/medkit/regular, /turf/open/floor/iron/white, @@ -35539,6 +35570,10 @@ dir = 1 }, /area/station/security/brig) +"jsL" = ( +/obj/effect/turf_decal/tile/red/opposingcorners, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "jsP" = ( /obj/effect/turf_decal/tile/yellow/half/contrasted{ dir = 4 @@ -35638,6 +35673,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/orange/visible, /turf/open/floor/plating, /area/station/engineering/supermatter) +"jun" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/obj/machinery/airalarm/directional/west, +/turf/open/floor/catwalk_floor, +/area/station/security/mechbay) "juq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -38218,6 +38261,19 @@ /obj/effect/turf_decal/tile/red/fourcorners, /turf/open/floor/iron/dark, /area/station/security/evidence) +"kcw" = ( +/obj/machinery/computer/mech_bay_power_console{ + dir = 8 + }, +/obj/machinery/button/door/directional/north{ + id = "secmechbay"; + name = "Security Mech Garage Door Controls"; + req_access = list("security") + }, +/obj/effect/turf_decal/tile/red/opposingcorners, +/obj/machinery/light_switch/directional/east, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "kcy" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -42961,7 +43017,12 @@ /obj/machinery/computer/department_orders/security{ dir = 8 }, -/obj/item/radio/intercom/directional/south, +/obj/item/radio/intercom/directional/east, +/obj/machinery/button/door/directional/south{ + id = "secmechbay"; + name = "Security Mech Garage Door Controls"; + req_access = list("security") + }, /turf/open/floor/iron, /area/station/security/office) "lkB" = ( @@ -43415,8 +43476,8 @@ "lqD" = ( /obj/structure/table, /obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = -6 + pixel_x = -6; + pixel_y = 6 }, /obj/item/storage/box/donkpockets{ pixel_x = 6 @@ -44372,12 +44433,6 @@ /obj/effect/spawner/random/structure/crate, /turf/open/floor/pod/light, /area/station/maintenance/floor1/port/aft) -"lET" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/turf/open/floor/engine, -/area/station/engineering/supermatter) "lFa" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -44993,14 +45048,6 @@ /obj/machinery/light/red/dim/directional/east, /turf/open/openspace, /area/station/maintenance/floor3/port/fore) -"lNx" = ( -/obj/machinery/atmospherics/pipe/smart/simple/purple/visible{ - dir = 4 - }, -/obj/machinery/airalarm/directional/north, -/obj/effect/mapping_helpers/airalarm/mixingchamber_access, -/turf/open/floor/iron/dark, -/area/station/science/ordnance/freezerchamber) "lNA" = ( /obj/effect/turf_decal/trimline/green/warning{ dir = 8 @@ -45731,6 +45778,24 @@ }, /turf/open/floor/wood, /area/station/medical/psychology) +"lVT" = ( +/obj/machinery/button/ignition/incinerator/ordmix{ + pixel_x = 8; + pixel_y = 32 + }, +/obj/machinery/button/door/incinerator_vent_ordmix{ + pixel_x = -8; + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, +/obj/machinery/airalarm/directional/west, +/obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnanceburn" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/iron/dark, +/area/station/science/ordnance/testlab) "lVU" = ( /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ dir = 4 @@ -47940,6 +48005,13 @@ dir = 4 }, /area/station/hallway/secondary/exit/departure_lounge) +"myp" = ( +/obj/effect/turf_decal/tile/red/anticorner, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "myr" = ( /turf/open/floor/iron/textured_large, /area/station/hallway/secondary/entry) @@ -53295,9 +53367,6 @@ /turf/open/floor/iron/dark/textured, /area/station/medical/pharmacy) "nPN" = ( -/obj/machinery/computer/message_monitor{ - dir = 4 - }, /obj/machinery/computer/message_monitor{ dir = 4 }, @@ -54083,7 +54152,6 @@ "oad" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/portable_atmospherics/pump, -/obj/machinery/portable_atmospherics/pump, /turf/open/floor/pod/light, /area/station/maintenance/floor4/port/fore) "oar" = ( @@ -54303,6 +54371,13 @@ }, /turf/open/floor/iron/white, /area/station/command/heads_quarters/rd) +"odH" = ( +/obj/effect/turf_decal/tile/red/opposingcorners, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "odJ" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 6 @@ -57066,6 +57141,15 @@ dir = 8 }, /area/station/security/brig) +"oQu" = ( +/obj/effect/turf_decal/caution/stand_clear, +/obj/effect/turf_decal/box, +/obj/machinery/door/poddoor/shutters{ + id = "secmechbay"; + name = "Security Mech Bay Shutters" + }, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "oQv" = ( /obj/structure/flora/bush/sparsegrass/style_random, /obj/machinery/light/directional/west, @@ -59236,7 +59320,6 @@ /turf/open/floor/iron/dark/corner, /area/station/commons/storage/primary) "pvO" = ( -/obj/item/kirbyplants/organic/plant10, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/tile/red/fourcorners, /turf/open/floor/iron/dark, @@ -60149,8 +60232,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/duct, +/obj/machinery/door/airlock/hatch{ + name = "Maintenance Bulkhead" + }, +/obj/effect/mapping_helpers/airlock/access/all/security/general, /turf/open/floor/catwalk_floor, -/area/station/maintenance/floor4/port) +/area/station/security/mechbay) "pIS" = ( /obj/machinery/requests_console/directional/east{ department = "Captain's Desk"; @@ -60331,6 +60418,18 @@ /obj/structure/reagent_dispensers/watertank, /turf/open/floor/pod/light, /area/station/maintenance/floor1/port) +"pLh" = ( +/obj/machinery/atmospherics/pipe/smart/simple/purple/visible{ + dir = 4 + }, +/obj/machinery/airalarm/directional/north, +/obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnancefreezer" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/iron/dark, +/area/station/science/ordnance/testlab) "pLy" = ( /obj/effect/spawner/random/trash/cigbutt, /obj/machinery/shower/directional/west, @@ -60883,20 +60982,6 @@ dir = 8 }, /area/station/hallway/floor1/fore) -"pSI" = ( -/obj/machinery/button/ignition/incinerator/ordmix{ - pixel_x = 8; - pixel_y = 32 - }, -/obj/machinery/button/door/incinerator_vent_ordmix{ - pixel_x = -8; - pixel_y = 32 - }, -/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, -/obj/machinery/airalarm/directional/west, -/obj/effect/mapping_helpers/airalarm/mixingchamber_access, -/turf/open/floor/iron/dark, -/area/station/science/ordnance/burnchamber) "pSV" = ( /obj/machinery/griddle, /turf/open/floor/iron/kitchen, @@ -69027,9 +69112,6 @@ "scn" = ( /obj/machinery/netpod, /obj/machinery/airalarm/directional/east, -/obj/machinery/airalarm/directional/east, -/obj/machinery/airalarm/directional/east, -/obj/machinery/airalarm/directional/east, /turf/open/floor/catwalk_floor/iron_dark, /area/station/bitrunning/den) "sct" = ( @@ -73481,16 +73563,18 @@ /turf/open/floor/catwalk_floor, /area/station/maintenance/floor2/port/fore) "tlx" = ( -/obj/effect/mapping_helpers/airlock/access/any/security/brig, /obj/structure/cable, -/obj/machinery/door/airlock/hatch{ - name = "Maintenance Access" - }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/duct, -/turf/open/floor/plating, -/area/station/maintenance/floor4/port) +/obj/machinery/door/poddoor/shutters{ + id = "secmechbay"; + name = "Security Mech Bay Shutters" + }, +/obj/effect/turf_decal/caution/stand_clear, +/obj/effect/turf_decal/box, +/turf/open/floor/iron/dark, +/area/station/security/mechbay) "tlJ" = ( /obj/machinery/camera/autoname/directional/east, /turf/open/space/openspace, @@ -76780,6 +76864,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, /obj/effect/turf_decal/tile/red/fourcorners, +/obj/item/kirbyplants/organic/plant10, /turf/open/floor/iron/dark, /area/station/security/office) "ufL" = ( @@ -79144,9 +79229,9 @@ /area/station/maintenance/floor2/port/aft) "uLB" = ( /obj/machinery/atmospherics/components/unary/outlet_injector/on{ - volume_rate = 200; dir = 8; - initialize_directions = 8 + initialize_directions = 8; + volume_rate = 200 }, /obj/machinery/atmospherics/pipe/heat_exchanging/manifold/layer2{ dir = 8 @@ -83533,6 +83618,10 @@ /obj/structure/disposalpipe/trunk/multiz, /turf/open/floor/plating, /area/station/maintenance/floor3/port/fore) +"vRF" = ( +/obj/vehicle/sealed/mecha/ripley/paddy/preset, +/turf/open/floor/iron/recharge_floor, +/area/station/security/mechbay) "vRO" = ( /turf/open/openspace, /area/station/hallway/floor4/aft) @@ -138333,7 +138422,7 @@ oqA wlP klY klY -klY +ePC nHv cAf klY @@ -138849,7 +138938,7 @@ sly uyD aFJ mMq -gSd +ghe uyD sHL ddT @@ -139876,7 +139965,7 @@ kcB ppO fJE jxc -lET +glU wCu vap kBK @@ -313075,7 +313164,7 @@ mSG mSG doC mSG -mSG +sJm sJm sJm nPE @@ -313332,7 +313421,7 @@ tQO mXH qyH mXH -pSI +lVT mUd xJx nPE @@ -315125,8 +315214,8 @@ ucA ucA ucA ucA -lYx -lNx +sJm +pLh koC oOA tyR @@ -317743,10 +317832,10 @@ lnl uYM eOy cgv -vEa -jbV -jbV -jbV +eNj +ftt +eNj +eNj eNj fPD jbV @@ -318002,7 +318091,7 @@ mbx rVS tlx dqs -dqs +jun dqs pIP hOs @@ -318257,11 +318346,11 @@ mBg dPf rDw pse -vEa -fXs -fXs -fXs -fXs +oQu +odH +jsL +myp +eNj jjh fXs fXs @@ -318514,11 +318603,11 @@ fNA ebz vuQ lku -vEa -owb -owb -owb -fXs +eNj +kcw +hvb +vRF +eNj mgx kHx fXs @@ -318771,11 +318860,11 @@ fNA ufI dnU dnU -fXs -vEa -vEa -owb -fXs +aRU +eNj +eNj +eNj +eNj xGh vPu fXs diff --git a/_maps/map_files/VoidRaptor/VoidRaptor.dmm b/_maps/map_files/VoidRaptor/VoidRaptor.dmm index 706a9c71528bf0..9c40f1af9ff34d 100644 --- a/_maps/map_files/VoidRaptor/VoidRaptor.dmm +++ b/_maps/map_files/VoidRaptor/VoidRaptor.dmm @@ -2144,10 +2144,6 @@ /obj/effect/turf_decal/trimline/purple/filled/line{ dir = 6 }, -/obj/machinery/button/door/directional/south{ - id = "genetics_shutters"; - name = "Genetics Shutters" - }, /obj/item/storage/box/monkeycubes{ pixel_x = 6; pixel_y = 9 @@ -16605,7 +16601,6 @@ /obj/effect/turf_decal/trimline/brown/filled/line{ dir = 4 }, -/obj/machinery/firealarm/directional/east, /obj/structure/bed/dogbed{ anchored = 1; name = "Markus's bed" @@ -24341,6 +24336,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/air_sensor/engine_chamber, /turf/open/floor/engine, /area/station/engineering/supermatter) "haq" = ( @@ -33525,6 +33521,10 @@ /obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden, /obj/machinery/airalarm/directional/west, /obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnanceburn" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, /turf/open/floor/engine, /area/station/science/ordnance/burnchamber) "jCA" = ( @@ -34478,10 +34478,14 @@ /obj/effect/turf_decal/trimline/dark_red/filled/line{ dir = 4 }, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnancefreezer" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, /turf/open/floor/iron/smooth_edge{ dir = 8 }, -/area/station/science/ordnance/freezerchamber) +/area/station/science/ordnance) "jOG" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 @@ -80157,6 +80161,10 @@ }, /obj/machinery/airalarm/directional/west, /obj/effect/mapping_helpers/airalarm/engine_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "engine" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, /turf/open/floor/engine, /area/station/engineering/supermatter) "wjk" = ( diff --git a/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_1.dmm b/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_1.dmm index 658ed7e840d0f2..67bdf4f43e910e 100644 --- a/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_1.dmm +++ b/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_1.dmm @@ -277,7 +277,7 @@ M M "} (11,1,1) = {" -w +a w w s @@ -292,7 +292,7 @@ a a "} (12,1,1) = {" -w +a w w s @@ -307,7 +307,7 @@ a a "} (13,1,1) = {" -w +a w w s @@ -322,7 +322,7 @@ a a "} (14,1,1) = {" -w +a w w s @@ -337,7 +337,7 @@ a a "} (15,1,1) = {" -w +a w w s diff --git a/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_2.dmm b/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_2.dmm index ee5e2a4a69440f..ed00e590e9d2e7 100644 --- a/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_2.dmm +++ b/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_2.dmm @@ -256,7 +256,7 @@ R R "} (11,1,1) = {" -T +a T t j @@ -271,7 +271,7 @@ a a "} (12,1,1) = {" -T +a T t d @@ -286,7 +286,7 @@ a a "} (13,1,1) = {" -T +a T t s @@ -301,7 +301,7 @@ a a "} (14,1,1) = {" -T +a T t N @@ -316,7 +316,7 @@ a a "} (15,1,1) = {" -T +a T t I diff --git a/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_3.dmm b/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_3.dmm index 21be0b689bd7c0..6f7e4019e12257 100644 --- a/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_3.dmm +++ b/_maps/map_files/tramstation/maintenance_modules/arrivalsecupper_3.dmm @@ -56,6 +56,16 @@ /obj/item/stack/ore/glass, /turf/open/misc/asteroid/dug, /area/station/asteroid) +"x" = ( +/obj/machinery/door/airlock/maintenance_hatch{ + name = "Security Maintenance Hatch" + }, +/obj/effect/mapping_helpers/airlock/access/any/security/maintenance, +/turf/open/floor/plating, +/area/station/maintenance/department/eva) +"y" = ( +/turf/closed/wall/r_wall, +/area/station/maintenance/department/eva) "E" = ( /turf/open/misc/asteroid, /area/station/asteroid) @@ -276,7 +286,7 @@ N N "} (11,1,1) = {" -t +y t L t @@ -291,7 +301,7 @@ a a "} (12,1,1) = {" -t +y r k t @@ -306,7 +316,7 @@ a a "} (13,1,1) = {" -t +y d d t @@ -321,7 +331,7 @@ a a "} (14,1,1) = {" -t +x e e K @@ -336,7 +346,7 @@ a a "} (15,1,1) = {" -t +y Y e t diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 8ffdf89bfbaef7..398d8a8ab2b672 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -4064,6 +4064,8 @@ /area/station/commons/vacant_room) "aBK" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, /turf/open/floor/iron, /area/station/security/brig) "aBL" = ( @@ -5658,6 +5660,10 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/atmos) +"aOW" = ( +/obj/machinery/light/directional/west, +/turf/open/floor/catwalk_floor, +/area/station/security/mechbay) "aPe" = ( /obj/machinery/door/airlock/maintenance_hatch{ name = "Library Maintenance Hatch" @@ -5674,6 +5680,22 @@ }, /turf/open/floor/wood/tile, /area/station/service/chapel/office) +"aPi" = ( +/obj/effect/turf_decal/stripes/line, +/obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible, +/obj/effect/turf_decal/trimline/yellow/arrow_ccw, +/obj/effect/turf_decal/trimline/yellow/arrow_cw{ + dir = 1 + }, +/obj/structure/cable/layer1, +/obj/machinery/airalarm/directional/south, +/obj/effect/mapping_helpers/airalarm/engine_access, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "engine" + }, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/turf/open/floor/engine, +/area/station/engineering/supermatter/room) "aPk" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 4 @@ -6632,6 +6654,11 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/security/interrogation) +"biB" = ( +/obj/effect/decal/cleanable/dirt, +/obj/vehicle/sealed/mecha/ripley/paddy/preset, +/turf/open/floor/iron/recharge_floor, +/area/station/security/mechbay) "biS" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 6 @@ -7256,6 +7283,13 @@ /obj/structure/cable, /turf/open/space/basic, /area/station/solars/starboard/fore) +"bwu" = ( +/obj/machinery/computer/mech_bay_power_console{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "bwz" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/trimline/neutral/filled/corner{ @@ -7896,6 +7930,14 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/exit) +"bIz" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/machinery/airalarm/directional/north, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "bIC" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 6 @@ -10263,6 +10305,14 @@ }, /turf/open/floor/iron, /area/station/cargo/storage) +"cyb" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 4 + }, +/obj/machinery/light/directional/south, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "cye" = ( /obj/structure/chair/stool/bar/directional/west, /obj/effect/turf_decal/siding/thinplating/dark{ @@ -13588,6 +13638,18 @@ /obj/machinery/firealarm/directional/east, /turf/open/floor/iron, /area/station/hallway/secondary/command) +"dFN" = ( +/obj/machinery/door/poddoor/shutters{ + id = "secmechbay"; + name = "Security Mech Bay Shutters" + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/plating, +/area/station/security/mechbay) "dFP" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -19159,6 +19221,15 @@ /obj/machinery/atmospherics/pipe/smart/simple/dark/visible, /turf/open/floor/engine/vacuum, /area/station/maintenance/disposal/incinerator) +"fLY" = ( +/obj/machinery/door/poddoor/shutters{ + id = "secmechbay"; + name = "Security Mech Bay Shutters" + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/delivery, +/turf/open/floor/plating, +/area/station/security/mechbay) "fMm" = ( /obj/machinery/atmospherics/pipe/smart/manifold/scrubbers/visible{ dir = 8 @@ -23906,6 +23977,13 @@ /obj/machinery/light/floor, /turf/open/floor/engine/n2o, /area/station/engineering/atmos) +"hCO" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "hDj" = ( /obj/machinery/door/airlock/atmos/glass{ name = "Atmospherics Testing Room" @@ -24712,6 +24790,7 @@ /obj/machinery/firealarm/directional/south, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, /turf/open/floor/iron, /area/station/security/brig) "hRK" = ( @@ -25627,6 +25706,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/commons/fitness/recreation) +"ijQ" = ( +/obj/machinery/air_sensor/engine_chamber, +/turf/open/floor/engine, +/area/station/engineering/supermatter) "ijR" = ( /obj/structure/table/reinforced, /turf/open/floor/iron/dark, @@ -26088,6 +26171,12 @@ }, /turf/open/misc/asteroid, /area/station/asteroid) +"itH" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/oil/slippery, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "itN" = ( /obj/effect/turf_decal/stripes/white/corner{ dir = 1 @@ -29176,6 +29265,13 @@ }, /turf/open/floor/plating, /area/station/medical/storage) +"jwV" = ( +/obj/effect/turf_decal/trimline/red/filled/corner, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/security/brig) "jwX" = ( /obj/structure/railing{ dir = 1 @@ -30480,6 +30576,17 @@ "jWs" = ( /turf/closed/wall/r_wall, /area/station/security/execution/transfer) +"jWy" = ( +/obj/machinery/button/door/directional/east{ + name = "Security Mech Garage Door Controls"; + id = "secmechbay"; + req_access = list("security") + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/catwalk_floor, +/area/station/security/mechbay) "jXc" = ( /obj/effect/turf_decal/trimline/yellow/filled/corner{ dir = 8 @@ -31018,6 +31125,17 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/engineering/atmos) +"kcV" = ( +/obj/structure/table, +/obj/effect/decal/cleanable/dirt, +/obj/item/stack/cable_coil{ + amount = 15; + pixel_x = 6; + pixel_y = 6 + }, +/obj/item/stack/cable_coil/cut, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "kcZ" = ( /obj/item/kirbyplants/random, /turf/open/floor/carpet, @@ -31153,6 +31271,13 @@ /obj/machinery/light/dim/directional/west, /turf/open/floor/iron, /area/station/science/lower) +"kft" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 1 + }, +/obj/machinery/light/directional/north, +/turf/open/floor/iron, +/area/station/security/brig) "kfD" = ( /obj/effect/turf_decal/sand, /obj/machinery/door/airlock/external{ @@ -31934,8 +32059,8 @@ dir = 6 }, /obj/item/storage/box/donkpockets/donkpocketberry{ - pixel_y = 10; - pixel_x = -6 + pixel_x = -6; + pixel_y = 10 }, /turf/open/floor/iron, /area/station/engineering/break_room) @@ -32761,6 +32886,15 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron/showroomfloor, /area/station/security/lockers) +"kIA" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/obj/item/stack/rods/two, +/obj/machinery/light_switch/directional/west, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "kIE" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/white/line{ @@ -33250,6 +33384,7 @@ /obj/effect/landmark/event_spawn, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, /turf/open/floor/iron, /area/station/security/brig) "kRL" = ( @@ -34683,9 +34818,9 @@ "lqu" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/shutters/preopen{ + dir = 4; id = "pharmacy_shutters_2"; - name = "Pharmacy Shutters"; - dir = 4 + name = "Pharmacy Shutters" }, /turf/open/floor/plating, /area/station/medical/pharmacy) @@ -35321,18 +35456,6 @@ /obj/machinery/light/small/dim/directional/north, /turf/open/floor/iron/freezer, /area/station/science/lower) -"lBF" = ( -/obj/machinery/atmospherics/pipe/smart/manifold/purple/visible{ - dir = 8 - }, -/obj/machinery/meter, -/obj/effect/turf_decal/trimline/purple/filled/line{ - dir = 8 - }, -/obj/machinery/airalarm/directional/west, -/obj/effect/mapping_helpers/airalarm/mixingchamber_access, -/turf/open/floor/iron/white, -/area/station/science/ordnance/freezerchamber) "lBP" = ( /obj/machinery/holopad, /obj/effect/turf_decal/bot, @@ -37105,6 +37228,12 @@ }, /turf/open/floor/iron/white, /area/station/science/lobby) +"mez" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/oil/slippery, +/obj/structure/reagent_dispensers/fueltank, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "meA" = ( /obj/machinery/disposal/bin, /obj/effect/turf_decal/trimline/green/filled/line{ @@ -38699,10 +38828,12 @@ /turf/open/floor/iron/checker, /area/station/commons/lounge) "mJQ" = ( -/obj/structure/closet/secure_closet/brig, /obj/effect/turf_decal/trimline/red/filled/line{ dir = 8 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, /turf/open/floor/iron, /area/station/security/brig) "mKe" = ( @@ -45441,9 +45572,9 @@ "pob" = ( /obj/machinery/smartfridge/chemistry/preloaded, /obj/machinery/door/poddoor/shutters/preopen{ + dir = 4; id = "pharmacy_shutters_2"; - name = "Pharmacy Shutters"; - dir = 4 + name = "Pharmacy Shutters" }, /obj/machinery/door/firedoor, /turf/open/floor/plating, @@ -47436,6 +47567,12 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/command/bridge) +"pWO" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/security/brig) "pWP" = ( /obj/structure/railing{ dir = 8 @@ -48058,8 +48195,8 @@ /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/cable, /obj/item/storage/box/bandages{ - pixel_y = 6; - pixel_x = -6 + pixel_x = -6; + pixel_y = 6 }, /obj/item/storage/box/bodybags{ pixel_x = 3; @@ -49182,17 +49319,6 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) -"qCG" = ( -/obj/effect/turf_decal/stripes/line, -/obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible, -/obj/machinery/firealarm/directional/south, -/obj/effect/turf_decal/trimline/yellow/arrow_ccw, -/obj/effect/turf_decal/trimline/yellow/arrow_cw{ - dir = 1 - }, -/obj/structure/cable/layer1, -/turf/open/floor/engine, -/area/station/engineering/supermatter/room) "qCJ" = ( /obj/structure/sign/directions/evac{ dir = 4; @@ -50333,6 +50459,27 @@ /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible, /turf/open/floor/iron, /area/station/engineering/atmos) +"qXK" = ( +/obj/structure/table, +/obj/effect/decal/cleanable/dirt, +/obj/item/stock_parts/cell/crap/empty{ + pixel_y = 10; + pixel_x = 6 + }, +/obj/item/stock_parts/cell/crap/empty{ + pixel_y = 2; + pixel_x = 6 + }, +/obj/item/stock_parts/cell/crap/empty{ + pixel_y = 7; + pixel_x = -7 + }, +/obj/item/stock_parts/cell/crap/empty{ + pixel_y = -2; + pixel_x = -2 + }, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "qXS" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -50736,6 +50883,13 @@ /obj/machinery/light/directional/east, /turf/open/floor/iron/white, /area/station/medical/treatment_center) +"rdN" = ( +/obj/machinery/mech_bay_recharge_port{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "rdO" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, /turf/closed/wall/r_wall, @@ -51809,6 +51963,18 @@ }, /turf/open/floor/tram, /area/station/hallway/primary/tram/right) +"ryY" = ( +/obj/effect/turf_decal/stripes/line, +/obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, +/obj/machinery/meter, +/obj/effect/turf_decal/trimline/yellow/arrow_ccw{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/yellow/arrow_cw, +/obj/structure/cable/layer1, +/obj/machinery/firealarm/directional/south, +/turf/open/floor/engine, +/area/station/engineering/supermatter/room) "rzt" = ( /obj/structure/rack, /obj/item/storage/box/gloves{ @@ -52241,19 +52407,6 @@ /obj/structure/sign/clock/directional/east, /turf/open/floor/iron/grimy, /area/station/hallway/secondary/entry) -"rJD" = ( -/obj/effect/turf_decal/stripes/line, -/obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, -/obj/machinery/meter, -/obj/effect/turf_decal/trimline/yellow/arrow_ccw{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/yellow/arrow_cw, -/obj/structure/cable/layer1, -/obj/machinery/airalarm/directional/south, -/obj/effect/mapping_helpers/airalarm/engine_access, -/turf/open/floor/engine, -/area/station/engineering/supermatter) "rJE" = ( /obj/machinery/door/airlock/medical/glass{ name = "Medical Freezer" @@ -54418,6 +54571,17 @@ /obj/machinery/light/directional/south, /turf/open/floor/iron, /area/station/science/ordnance/testlab) +"sub" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 10 + }, +/obj/machinery/button/door/directional/south{ + name = "Security Mech Garage Door Controls"; + id = "secmechbay"; + req_access = list("security") + }, +/turf/open/floor/iron, +/area/station/security/brig) "sud" = ( /obj/structure/table, /obj/item/food/cakeslice/birthday, @@ -56935,6 +57099,26 @@ /obj/effect/mapping_helpers/airlock/access/any/service/chapel_office, /turf/open/floor/iron/smooth, /area/station/service/chapel/office) +"tpI" = ( +/obj/machinery/atmospherics/components/unary/thermomachine/freezer{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/machinery/camera/directional/south{ + c_tag = "Science - Mixing Lab"; + network = list("ss13","rd") + }, +/obj/machinery/airalarm/directional/south, +/obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnanceburn" + }, +/turf/open/floor/iron/white, +/area/station/science/ordnance) "tpR" = ( /obj/machinery/vending/coffee, /obj/effect/turf_decal/siding/wood{ @@ -57875,13 +58059,8 @@ /turf/open/floor/iron/dark, /area/station/service/chapel) "tFk" = ( -/obj/structure/closet/secure_closet/brig, -/obj/effect/turf_decal/trimline/red/filled/line{ - dir = 9 - }, -/obj/machinery/light/directional/west, -/turf/open/floor/iron, -/area/station/security/brig) +/turf/closed/wall/r_wall, +/area/station/security/mechbay) "tFB" = ( /obj/structure/cable, /turf/open/floor/iron/white, @@ -61059,6 +61238,13 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"uGn" = ( +/obj/effect/turf_decal/trimline/red/filled/line, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/security/brig) "uGo" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/trimline/purple/filled/line{ @@ -61577,6 +61763,13 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos) +"uNJ" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/catwalk_floor, +/area/station/security/mechbay) "uNK" = ( /obj/effect/turf_decal/trimline/red/filled/line{ dir = 1 @@ -62030,22 +62223,6 @@ /obj/item/pen, /turf/open/floor/iron/grimy, /area/station/service/library/lounge) -"uXn" = ( -/obj/machinery/atmospherics/components/unary/thermomachine/freezer{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/obj/machinery/camera/directional/south{ - c_tag = "Science - Mixing Lab"; - network = list("ss13","rd") - }, -/obj/machinery/airalarm/directional/south, -/obj/effect/mapping_helpers/airalarm/mixingchamber_access, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/white, -/area/station/science/ordnance/burnchamber) "uXv" = ( /obj/effect/turf_decal/stripes/corner{ dir = 4 @@ -63612,6 +63789,10 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/hallway/primary/tram/right) +"vyO" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/catwalk_floor, +/area/station/security/mechbay) "vyR" = ( /obj/effect/spawner/random/structure/closet_private, /turf/open/floor/carpet, @@ -65922,8 +66103,8 @@ /area/station/hallway/secondary/service) "wrJ" = ( /obj/structure/railing{ - layer = 3.1; - dir = 4 + dir = 4; + layer = 3.1 }, /obj/machinery/netpod, /turf/open/floor/catwalk_floor/iron_dark, @@ -67175,6 +67356,22 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/hallway/primary/tram/right) +"wQg" = ( +/obj/machinery/atmospherics/pipe/smart/manifold/purple/visible{ + dir = 8 + }, +/obj/machinery/meter, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 8 + }, +/obj/machinery/airalarm/directional/west, +/obj/effect/mapping_helpers/airalarm/mixingchamber_access, +/obj/effect/mapping_helpers/airalarm/tlv_no_checks, +/obj/effect/mapping_helpers/airalarm/link{ + chamber_id = "ordnancefreezer" + }, +/turf/open/floor/iron/white, +/area/station/science/ordnance) "wQm" = ( /turf/open/floor/iron, /area/station/engineering/atmos) @@ -67650,9 +67847,9 @@ pixel_x = -7 }, /obj/machinery/door/poddoor/shutters/preopen{ + dir = 4; id = "pharmacy_shutters_2"; - name = "Pharmacy Shutters"; - dir = 4 + name = "Pharmacy Shutters" }, /obj/machinery/door/firedoor, /obj/machinery/door/window/left/directional/south{ @@ -68421,6 +68618,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, /area/station/medical/virology) +"xsg" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "xsh" = ( /obj/machinery/door/airlock/medical{ name = "Surgery" @@ -69520,6 +69721,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/security/checkpoint/science) +"xNL" = ( +/obj/structure/table, +/obj/effect/decal/cleanable/dirt, +/obj/structure/cable, +/obj/machinery/power/apc/auto_name/directional/east, +/obj/item/crowbar, +/turf/open/floor/iron/smooth, +/area/station/security/mechbay) "xNP" = ( /obj/structure/chair/stool/bar/directional/south, /turf/open/floor/eighties, @@ -101084,7 +101293,7 @@ nxT lfB ltq bWN -qCG +aPi hiB rZx lEf @@ -101345,7 +101554,7 @@ svA jBn bKt gqf -bKt +ijQ dQn bKt frN @@ -101855,7 +102064,7 @@ pfG qHs bpZ fuj -rJD +ryY hDI oMc lEf @@ -120353,7 +120562,7 @@ dfz vqa uIk uIk -lBF +wQg vjT fjn mBW @@ -121895,7 +122104,7 @@ dfz vqO edP edP -uXn +tpI hBl hBl gkD @@ -149067,11 +149276,11 @@ aac aaa aaa aaa -aaa -aaa -aaa -aaa -aaa +tFk +tFk +tFk +tFk +tFk aaa aaa abM @@ -149321,14 +149530,14 @@ aac aac aac aac -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +tFk +tFk +tFk +tFk +biB +rdN +bwu +tFk aaa aaa abM @@ -149578,14 +149787,14 @@ aac aac aac aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +tFk +mez +kIA +aOW +xsg +vyO +cyb +tFk aaa aaa abM @@ -149835,14 +150044,14 @@ aac aac aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +tFk +bIz +hCO +jWy +hCO +uNJ +itH +tFk aaa aaa abM @@ -150092,14 +150301,14 @@ aaa aaa aaa yji -yji -yji -yji -yji -aaa -aaa -aaa -aaa +tFk +dFN +fLY +tFk +kcV +xNL +qXK +tFk aaa aaa abM @@ -150349,9 +150558,9 @@ aaa aaa aaa yji -tFk +wOb mJQ -dTL +sub yji run run @@ -150606,8 +150815,8 @@ aaa aaa aaa yji -nDj -dkO +kft +aBK rGN dTL mjM @@ -151378,7 +151587,7 @@ qhI kDS mOZ wvG -gvQ +pWO kEc ntp mjM @@ -151892,7 +152101,7 @@ avA xSX xDQ iko -gvQ +pWO iGJ gki nca @@ -152149,7 +152358,7 @@ avB jPx xDQ rOh -iBO +jwV pNI gki nca @@ -152663,7 +152872,7 @@ avD hYT xSX rOh -rco +uGn awp hWL vgl diff --git a/_maps/shuttles/emergency_narnar.dmm b/_maps/shuttles/emergency_narnar.dmm index 804c59fa4fff45..d6c48664e08e7d 100644 --- a/_maps/shuttles/emergency_narnar.dmm +++ b/_maps/shuttles/emergency_narnar.dmm @@ -166,7 +166,7 @@ /turf/open/floor/cult, /area/shuttle/escape) "H" = ( -/mob/living/simple_animal/hostile/construct/wraith, +/mob/living/basic/construct/wraith, /turf/open/floor/cult, /area/shuttle/escape) "I" = ( diff --git a/_maps/shuttles/pirate_ex_interdyne.dmm b/_maps/shuttles/pirate_ex_interdyne.dmm index 5d2149c049fa52..ab11aa1dfdf4d4 100644 --- a/_maps/shuttles/pirate_ex_interdyne.dmm +++ b/_maps/shuttles/pirate_ex_interdyne.dmm @@ -52,7 +52,6 @@ /obj/effect/mapping_helpers/airlock/cutaiwire, /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/effect/turf_decal/tile/dark_blue/fourcorners, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, /obj/effect/mapping_helpers/airlock/access/all/syndicate/general, /turf/open/floor/iron/dark, /area/shuttle/pirate) diff --git a/_maps/shuttles/ruin_pirate_cutter.dmm b/_maps/shuttles/ruin_pirate_cutter.dmm index 634386c56c2633..7dd4be59ba7ca1 100644 --- a/_maps/shuttles/ruin_pirate_cutter.dmm +++ b/_maps/shuttles/ruin_pirate_cutter.dmm @@ -75,7 +75,7 @@ /turf/open/floor/plating, /area/shuttle/ruin/caravan/pirate) "iN" = ( -/mob/living/simple_animal/hostile/pirate/melee{ +/mob/living/basic/trooper/pirate/melee{ environment_smash = 0 }, /turf/open/floor/iron, @@ -139,7 +139,7 @@ pixel_y = -30; req_access = null }, -/mob/living/simple_animal/hostile/pirate/ranged{ +/mob/living/basic/trooper/pirate/ranged{ environment_smash = 0 }, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -787,7 +787,7 @@ /area/shuttle/ruin/caravan/pirate) "WV" = ( /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/pirate/ranged{ +/mob/living/basic/trooper/pirate/ranged{ environment_smash = 0 }, /turf/open/floor/iron, diff --git a/_maps/shuttles/skyrat/pirate_nri_raider.dmm b/_maps/shuttles/skyrat/pirate_nri_raider.dmm index 5c44bc377d4a4c..932fe6348ba0bf 100644 --- a/_maps/shuttles/skyrat/pirate_nri_raider.dmm +++ b/_maps/shuttles/skyrat/pirate_nri_raider.dmm @@ -17,12 +17,12 @@ /obj/item/storage/box/zipties{ pixel_x = 2 }, -/obj/item/gun/energy/e_gun/advtaser, -/obj/item/gun/energy/e_gun/advtaser, -/obj/item/gun/energy/e_gun/advtaser, /obj/item/melee/baton, /obj/item/melee/baton, /obj/item/melee/baton, +/obj/item/gun/energy/e_gun/advtaser/normal, +/obj/item/gun/energy/e_gun/advtaser/normal, +/obj/item/gun/energy/e_gun/advtaser/normal, /turf/open/floor/pod, /area/shuttle/pirate/nri) "be" = ( @@ -383,14 +383,12 @@ desc = "A secure crate to keep all your personal belongings in."; anchored = 1 }, -/obj/item/clothing/under/costume/nri/engineer, /obj/item/clothing/mask/balaclavaadjust, -/obj/item/clothing/under/syndicate/rus_army/cin_surplus/marine, /obj/item/clothing/glasses/meson/engine, /obj/item/storage/belt/military/cin_surplus/marine, -/obj/item/clothing/suit/armor/vest/cin_surplus_vest, -/obj/item/clothing/head/helmet/cin_surplus_helmet/marine, /obj/item/clothing/glasses/hud/security/sunglasses/peacekeeper, +/obj/item/clothing/head/helmet/nri_police, +/obj/item/clothing/suit/armor/vest/nri_police, /obj/item/encryptionkey/heads/ce, /turf/open/floor/pod/light, /area/shuttle/pirate/nri) @@ -469,8 +467,8 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/obj/item/gun/ballistic/shotgun/riot, /obj/item/gun/ballistic/automatic/nri_smg, +/obj/item/gun/ballistic/shotgun/automatic/combat/compact, /turf/open/floor/pod, /area/shuttle/pirate/nri) "rp" = ( @@ -817,13 +815,11 @@ anchored = 1 }, /obj/item/clothing/glasses/hud/health, -/obj/item/clothing/under/costume/nri/medic, /obj/item/clothing/glasses/hud/security/sunglasses/peacekeeper, /obj/item/clothing/mask/balaclavaadjust, -/obj/item/clothing/under/syndicate/rus_army/cin_surplus/marine, /obj/item/storage/belt/military/cin_surplus/marine, -/obj/item/clothing/suit/armor/vest/cin_surplus_vest, -/obj/item/clothing/head/helmet/cin_surplus_helmet/marine, +/obj/item/clothing/head/helmet/nri_police, +/obj/item/clothing/suit/armor/vest/nri_police, /obj/item/encryptionkey/heads/cmo, /turf/open/floor/pod/light, /area/shuttle/pirate/nri) @@ -943,13 +939,11 @@ desc = "A secure crate to keep all your personal belongings in."; anchored = 1 }, -/obj/item/clothing/under/costume/nri/captain, /obj/item/clothing/glasses/hud/security/sunglasses/peacekeeper, /obj/item/clothing/mask/balaclavaadjust, -/obj/item/clothing/under/syndicate/rus_army/cin_surplus/marine, /obj/item/storage/belt/military/cin_surplus/marine, -/obj/item/clothing/suit/armor/vest/cin_surplus_vest, -/obj/item/clothing/head/helmet/cin_surplus_helmet/marine, +/obj/item/clothing/head/helmet/nri_police, +/obj/item/clothing/suit/armor/vest/nri_police, /obj/item/encryptionkey/heads/hos, /turf/open/floor/pod/light, /area/shuttle/pirate/nri) diff --git a/_maps/shuttles/whiteship_obelisk.dmm b/_maps/shuttles/whiteship_obelisk.dmm index 4a632a01df2683..170c3db24bd7e0 100644 --- a/_maps/shuttles/whiteship_obelisk.dmm +++ b/_maps/shuttles/whiteship_obelisk.dmm @@ -122,7 +122,7 @@ /area/shuttle/abandoned/engine) "gw" = ( /obj/structure/cable, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/crayon{ icon_state = "rune4"; paint_colour = "#DC143C" @@ -134,7 +134,7 @@ /turf/open/floor/catwalk_floor/iron_smooth, /area/shuttle/abandoned/engine) "hg" = ( -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/blood/old, /obj/structure/cable, /turf/open/floor/mineral/titanium/white, @@ -166,7 +166,7 @@ /area/shuttle/abandoned/engine) "ji" = ( /obj/structure/cable, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ dir = 4 }, @@ -438,7 +438,7 @@ /area/shuttle/abandoned/crew) "yo" = ( /obj/structure/cable, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/crayon{ icon_state = "rune4"; paint_colour = "#DC143C" @@ -616,7 +616,7 @@ /area/shuttle/abandoned) "IH" = ( /obj/structure/cable, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/blood/gibs/core, /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 1 @@ -781,7 +781,7 @@ /area/shuttle/abandoned/medbay) "SE" = ( /obj/structure/cable, -/mob/living/simple_animal/hostile/construct/proteon/hostile, +/mob/living/basic/construct/proteon/hostile, /obj/effect/decal/cleanable/crayon{ icon_state = "rune4"; paint_colour = "#DC143C" diff --git a/_maps/skyrat/automapper/templates/metastation/metastation_arrivals.dmm b/_maps/skyrat/automapper/templates/metastation/metastation_arrivals.dmm index 946510b8f2cb92..fc238d37eddbd5 100644 --- a/_maps/skyrat/automapper/templates/metastation/metastation_arrivals.dmm +++ b/_maps/skyrat/automapper/templates/metastation/metastation_arrivals.dmm @@ -1209,6 +1209,17 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"Kh" = ( +/obj/docking_port/stationary{ + dir = 2; + dwidth = 11; + height = 24; + name = "SS13: Auxiliary Dock, Station-Port"; + shuttle_id = "whiteship_home"; + width = 35 + }, +/turf/open/space/basic, +/area/space) "Kk" = ( /obj/machinery/newscaster/directional/south, /obj/structure/table, @@ -2504,7 +2515,7 @@ EW PD aG Wm -FF +Kh FF FF "} diff --git a/_maps/templates/battlecruiser_starfury.dmm b/_maps/templates/battlecruiser_starfury.dmm index 1e4905ac26ebf4..3e759257296248 100644 --- a/_maps/templates/battlecruiser_starfury.dmm +++ b/_maps/templates/battlecruiser_starfury.dmm @@ -119,7 +119,6 @@ "as" = ( /obj/machinery/light/directional/north, /obj/machinery/atmospherics/components/unary/thermomachine/freezer, -/obj/machinery/light/directional/north, /obj/effect/turf_decal/siding/thinplating_new{ dir = 4 }, diff --git a/_maps/templates/lazy_templates/heretic_sacrifice.dmm b/_maps/templates/lazy_templates/heretic_sacrifice.dmm index 06ace91956c01f..44300c13735fee 100644 --- a/_maps/templates/lazy_templates/heretic_sacrifice.dmm +++ b/_maps/templates/lazy_templates/heretic_sacrifice.dmm @@ -44,7 +44,7 @@ /obj/effect/decal/cleanable/blood/old, /obj/effect/decal/cleanable/dirt/dust, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "fO" = ( /turf/open/indestructible, /area/space) @@ -59,7 +59,7 @@ /obj/effect/decal/cleanable/dirt/dust, /obj/item/storage/toolbox/mechanical/old, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "hZ" = ( /obj/effect/decal/cleanable/blood/old, /turf/open/indestructible/necropolis/air, @@ -71,7 +71,7 @@ /area/centcom/heretic_sacrifice/rust) "jt" = ( /turf/closed/indestructible/reinforced, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "jB" = ( /obj/machinery/light/very_dim/directional/south, /turf/open/misc/asteroid, @@ -105,7 +105,7 @@ /obj/effect/decal/cleanable/dirt/dust, /obj/item/spear, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "mZ" = ( /obj/effect/decal/fakelattice{ density = 0 @@ -176,7 +176,7 @@ /obj/effect/decal/cleanable/dirt/dust, /obj/item/storage/toolbox/mechanical/old, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "qu" = ( /obj/effect/turf_decal/weather/dirt, /turf/open/misc/ashplanet/wateryrock{ @@ -234,7 +234,7 @@ /obj/effect/decal/cleanable/dirt/dust, /obj/item/clothing/under/color/grey/ancient, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "uT" = ( /obj/structure/cable, /turf/open/floor/plating/rust, @@ -260,7 +260,7 @@ /area/centcom/heretic_sacrifice/ash) "wo" = ( /turf/closed/indestructible/grille, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "wt" = ( /obj/structure/stone_tile/block{ dir = 1 @@ -285,7 +285,7 @@ start_on = 1 }, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "wS" = ( /turf/open/misc/dirt/jungle/dark{ planetary_atmos = 0; @@ -326,7 +326,7 @@ /obj/effect/decal/cleanable/dirt/dust, /obj/item/clothing/mask/gas, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "AH" = ( /obj/effect/turf_decal/trimline/brown/corner, /turf/open/floor/plating/rust, @@ -345,11 +345,11 @@ /obj/effect/decal/cleanable/dirt/dust, /obj/item/clothing/mask/gas/tiki_mask/yalp_elor, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "AY" = ( /obj/effect/decal/cleanable/dirt/dust, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "Bv" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/trimline/brown/line, @@ -405,7 +405,7 @@ /area/centcom/heretic_sacrifice/ash) "En" = ( /turf/closed/indestructible/fakedoor/maintenance, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "ER" = ( /turf/open/misc/ironsand, /area/centcom/heretic_sacrifice/rust) @@ -543,7 +543,7 @@ start_on = 1 }, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "Nh" = ( /obj/effect/turf_decal/trimline/brown/line{ dir = 1 @@ -589,7 +589,7 @@ /obj/effect/decal/cleanable/dirt/dust, /obj/item/clothing/under/color/grey/ancient, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "Pl" = ( /obj/effect/turf_decal/weather/dirt{ dir = 6 @@ -712,9 +712,9 @@ "Zw" = ( /obj/effect/decal/cleanable/blood/old, /obj/effect/decal/cleanable/dirt/dust, -/obj/effect/landmark/heretic/knock, +/obj/effect/landmark/heretic/lock, /turf/open/indestructible/plating, -/area/centcom/heretic_sacrifice/knock) +/area/centcom/heretic_sacrifice/lock) "ZA" = ( /turf/closed/indestructible/riveted/boss, /area/centcom/heretic_sacrifice/ash) diff --git a/_maps/virtual_domains/ash_drake.dmm b/_maps/virtual_domains/ash_drake.dmm index 50fbac8696ab39..6056136a278a8b 100644 --- a/_maps/virtual_domains/ash_drake.dmm +++ b/_maps/virtual_domains/ash_drake.dmm @@ -21,7 +21,7 @@ /obj/machinery/light/small/blacklight/directional/south, /obj/effect/baseturf_helper/virtual_domain, /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, -/area/virtual_domain/powered) +/area/virtual_domain) "i" = ( /obj/structure/marker_beacon/jade, /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, @@ -35,7 +35,7 @@ /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, /area/lavaland/surface/outdoors/virtual_domain) "q" = ( -/mob/living/simple_animal/hostile/megafauna/dragon/virtual_domain, +/mob/living/simple_animal/hostile/megafauna/dragon, /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, /area/lavaland/surface/outdoors/virtual_domain) "s" = ( diff --git a/_maps/virtual_domains/beach_bar.dmm b/_maps/virtual_domains/beach_bar.dmm index 29fe04d82837f3..779b1b893c04ee 100644 --- a/_maps/virtual_domains/beach_bar.dmm +++ b/_maps/virtual_domains/beach_bar.dmm @@ -159,9 +159,9 @@ pixel_x = -8; pixel_y = -1 }, -/obj/item/reagent_containers/cup/glass/drinkingglass/filled/virtual_domain{ - pixel_y = 8; - pixel_x = 5 +/obj/item/reagent_containers/cup/glass/drinkingglass/filled/pina_colada{ + pixel_y = 5; + pixel_x = 6 }, /turf/open/floor/wood, /area/virtual_domain/powered) @@ -300,6 +300,9 @@ /obj/item/food/meat/slab/rawcrab, /turf/open/floor/wood, /area/virtual_domain/powered) +"no" = ( +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/virtual_domain/powered) "nP" = ( /obj/item/stack/sheet/iron/fifty, /obj/effect/mapping_helpers/burnt_floor, @@ -396,7 +399,6 @@ /area/virtual_domain/powered) "uc" = ( /obj/machinery/light/small/directional/east, -/obj/machinery/light/small/directional/east, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/virtual_domain/powered) "ug" = ( @@ -424,10 +426,10 @@ /area/virtual_domain/powered) "uq" = ( /obj/structure/table/wood, -/obj/item/reagent_containers/cup/glass/drinkingglass/filled/virtual_domain, -/obj/item/reagent_containers/cup/glass/drinkingglass/filled/virtual_domain{ - pixel_x = -4; - pixel_y = 8 +/obj/item/reagent_containers/cup/glass/drinkingglass/filled/pina_colada, +/obj/item/reagent_containers/cup/glass/drinkingglass/filled/pina_colada{ + pixel_x = -5; + pixel_y = 5 }, /turf/open/floor/wood, /area/virtual_domain/powered) @@ -878,11 +880,11 @@ /area/virtual_domain/powered) "Mp" = ( /obj/structure/table/wood, -/obj/item/reagent_containers/cup/glass/drinkingglass/filled/virtual_domain{ - pixel_y = 7; - pixel_x = 4 +/obj/item/reagent_containers/cup/glass/drinkingglass/filled/pina_colada{ + pixel_x = 5; + pixel_y = 5 }, -/obj/item/reagent_containers/cup/glass/drinkingglass/filled/virtual_domain, +/obj/item/reagent_containers/cup/glass/drinkingglass/filled/pina_colada, /turf/open/floor/wood, /area/virtual_domain/powered) "Mw" = ( @@ -2116,7 +2118,7 @@ iz (23,1,1) = {" iz Al -xb +no Fn Cb wD @@ -2159,7 +2161,7 @@ xW (24,1,1) = {" iz Al -xb +no Fn wD Gz @@ -2202,7 +2204,7 @@ xW (25,1,1) = {" iz Al -xb +no Fn OK Gz @@ -2245,7 +2247,7 @@ xW (26,1,1) = {" iz Al -xb +no Fn Sg wD diff --git a/_maps/virtual_domains/blood_drunk_miner.dmm b/_maps/virtual_domains/blood_drunk_miner.dmm index c3369a1c822de7..bf673bd6dfa04a 100644 --- a/_maps/virtual_domains/blood_drunk_miner.dmm +++ b/_maps/virtual_domains/blood_drunk_miner.dmm @@ -27,7 +27,7 @@ /obj/machinery/light/small/blacklight/directional/south, /obj/effect/baseturf_helper/virtual_domain, /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, -/area/virtual_domain/powered) +/area/virtual_domain) "i" = ( /obj/structure/stone_tile{ dir = 4 @@ -171,7 +171,7 @@ /obj/structure/stone_tile/surrounding/cracked{ dir = 6 }, -/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/virtual_domain, +/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner, /turf/open/lava/smooth/lava_land_surface, /area/lavaland/surface/outdoors/virtual_domain) "T" = ( diff --git a/_maps/virtual_domains/breeze_bay.dmm b/_maps/virtual_domains/breeze_bay.dmm new file mode 100644 index 00000000000000..6fe6f49ab3ab10 --- /dev/null +++ b/_maps/virtual_domains/breeze_bay.dmm @@ -0,0 +1,836 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/indestructible/binary, +/area/virtual_domain/powered) +"c" = ( +/obj/structure/flora/coconuts, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"d" = ( +/obj/structure/chair/wood, +/turf/open/floor/wood/large, +/area/virtual_domain/powered) +"e" = ( +/turf/open/floor/carpet/red, +/area/virtual_domain/powered) +"g" = ( +/obj/item/toy/beach_ball/branded, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"i" = ( +/turf/open/water/beach, +/area/virtual_domain/powered) +"k" = ( +/obj/effect/landmark/bitrunning/loot_signal, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"m" = ( +/obj/item/fishing_rod{ + pixel_x = 5; + pixel_y = -5 + }, +/obj/item/fishing_rod, +/obj/item/fishing_rod{ + pixel_y = 5; + pixel_x = -5 + }, +/obj/structure/table/wood, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"o" = ( +/obj/structure/flora/tree/jungle/style_5, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"p" = ( +/turf/open/floor/carpet/blue, +/area/virtual_domain/powered) +"s" = ( +/obj/structure/fluff/beach_umbrella/cap, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"t" = ( +/obj/structure/fluff/beach_umbrella/syndi, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"v" = ( +/obj/effect/baseturf_helper/virtual_domain, +/obj/effect/landmark/bitrunning/safehouse_spawn, +/turf/template_noop, +/area/virtual_domain/safehouse) +"y" = ( +/obj/structure/flora/bush/sparsegrass/style_random, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"z" = ( +/mob/living/basic/crab, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"B" = ( +/obj/structure/flora/tree/jungle/style_6, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"C" = ( +/obj/structure/flora/tree/jungle/style_2, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"D" = ( +/turf/open/floor/carpet/green, +/area/virtual_domain/powered) +"F" = ( +/obj/structure/fluff/beach_umbrella/engine, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"G" = ( +/obj/structure/flora/bush/jungle/a/style_random, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"H" = ( +/obj/structure/flora/tree/jungle/style_4, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"I" = ( +/turf/template_noop, +/area/virtual_domain/safehouse) +"J" = ( +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"K" = ( +/obj/structure/flora/tree/jungle, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"L" = ( +/obj/item/fishing_line, +/obj/item/fishing_hook, +/obj/item/fishing_hook, +/obj/item/fishing_hook, +/obj/structure/closet/crate, +/obj/item/bait_can/worm, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"O" = ( +/obj/structure/flora/rock/style_random, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"P" = ( +/turf/open/misc/beach/coast, +/area/virtual_domain/powered) +"Q" = ( +/obj/structure/flora/bush/stalky/style_random, +/turf/open/water/beach, +/area/virtual_domain/powered) +"R" = ( +/obj/structure/closet/crate/freezer{ + name = "Cooler" + }, +/obj/item/reagent_containers/cup/glass/ice, +/obj/item/reagent_containers/cup/glass/colocup, +/obj/item/reagent_containers/cup/glass/colocup, +/obj/item/reagent_containers/cup/glass/bottle/beer{ + desc = "Beer advertised to be the best in space."; + name = "Masterbrand Beer" + }, +/obj/item/reagent_containers/cup/glass/bottle/beer{ + desc = "Beer advertised to be the best in space."; + name = "Masterbrand Beer" + }, +/obj/item/reagent_containers/cup/glass/bottle/beer{ + desc = "Beer advertised to be the best in space."; + name = "Masterbrand Beer" + }, +/obj/item/reagent_containers/cup/glass/bottle/beer/light, +/obj/item/reagent_containers/cup/glass/bottle/beer/light, +/obj/item/reagent_containers/cup/glass/bottle/beer/light, +/obj/item/clothing/head/soft/fishing_hat, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"S" = ( +/obj/structure/flora/tree/jungle/style_3, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"U" = ( +/obj/structure/flora/tree/palm/style_random, +/turf/open/misc/beach/sand, +/area/virtual_domain/powered) +"X" = ( +/turf/open/floor/wood/large, +/area/virtual_domain/powered) +"Z" = ( +/obj/effect/baseturf_helper/virtual_domain, +/turf/closed/indestructible/binary, +/area/virtual_domain/powered) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +Z +"} +(2,1,1) = {" +a +K +G +y +J +J +J +J +J +J +J +z +P +i +i +i +i +i +i +i +Q +i +i +i +a +"} +(3,1,1) = {" +a +J +O +J +J +I +I +I +I +I +v +J +P +Q +i +i +i +i +i +i +i +i +i +i +a +"} +(4,1,1) = {" +a +J +C +J +J +I +I +I +I +I +I +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(5,1,1) = {" +a +J +y +J +J +I +I +I +I +I +I +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(6,1,1) = {" +a +S +J +J +J +I +I +I +I +I +I +y +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(7,1,1) = {" +a +G +G +J +J +I +I +I +I +I +I +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(8,1,1) = {" +a +J +H +g +J +I +I +I +I +I +I +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(9,1,1) = {" +a +G +y +J +J +I +I +I +I +I +I +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(10,1,1) = {" +a +o +J +J +J +J +J +J +J +J +J +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(11,1,1) = {" +a +J +J +J +J +J +J +J +J +J +J +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(12,1,1) = {" +a +J +B +y +J +J +J +U +c +J +J +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(13,1,1) = {" +a +J +J +J +J +s +J +J +J +J +k +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(14,1,1) = {" +a +K +y +J +J +p +p +J +J +J +m +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(15,1,1) = {" +a +J +J +J +J +t +J +J +J +J +L +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(16,1,1) = {" +a +J +C +J +J +e +e +J +J +J +J +J +P +i +i +i +i +X +X +i +i +i +i +i +a +"} +(17,1,1) = {" +a +G +J +J +J +F +J +J +J +J +J +J +P +i +i +i +i +X +X +i +i +i +i +i +a +"} +(18,1,1) = {" +a +S +G +J +J +D +D +J +J +J +J +J +X +X +X +X +X +X +X +X +X +X +i +i +a +"} +(19,1,1) = {" +a +J +J +J +J +R +J +J +J +J +J +J +X +X +X +X +X +X +X +X +d +X +i +i +a +"} +(20,1,1) = {" +a +J +H +J +J +J +J +J +J +J +J +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(21,1,1) = {" +a +J +O +J +J +J +J +J +J +c +J +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(22,1,1) = {" +a +o +J +y +J +J +J +J +J +U +J +J +P +i +i +i +i +i +i +i +i +i +i +i +a +"} +(23,1,1) = {" +a +J +G +J +J +J +J +J +J +y +J +J +P +i +i +i +i +i +i +i +i +i +Q +i +a +"} +(24,1,1) = {" +a +J +B +J +z +J +y +J +J +J +J +J +P +i +Q +i +i +i +i +i +i +i +i +i +a +"} +(25,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/_maps/virtual_domains/bubblegum.dmm b/_maps/virtual_domains/bubblegum.dmm index 3381b1735398b6..a801fa4918746b 100644 --- a/_maps/virtual_domains/bubblegum.dmm +++ b/_maps/virtual_domains/bubblegum.dmm @@ -29,7 +29,7 @@ /obj/machinery/light/small/blacklight/directional/south, /obj/effect/baseturf_helper/virtual_domain, /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, -/area/virtual_domain/powered) +/area/virtual_domain) "x" = ( /obj/structure/marker_beacon/olive, /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, @@ -43,7 +43,7 @@ /turf/template_noop, /area/virtual_domain/safehouse) "C" = ( -/mob/living/simple_animal/hostile/megafauna/bubblegum/virtual_domain, +/mob/living/simple_animal/hostile/megafauna/bubblegum, /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, /area/lavaland/surface/outdoors/virtual_domain) "F" = ( @@ -134,6 +134,16 @@ F F F F +F +F +F +F +F +F +F +F +F +F R "} (2,1,1) = {" @@ -182,16 +192,492 @@ Z Z Z Z -F -"} -(3,1,1) = {" -F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +"} +(3,1,1) = {" +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +"} +(4,1,1) = {" +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +"} +(5,1,1) = {" +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +"} +(6,1,1) = {" +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +"} +(7,1,1) = {" +F +Z +Z +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +"} +(8,1,1) = {" +F +Z +Z +F +Z +Z +Z +a +a +Z +Z +Z +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +Z +Z +Z +a +a +a +a +a +a +a +a +Z +Z +a +a +a +a +a +a +Z +Z +Z +Z +Z +Z +Z +Z +F +"} +(9,1,1) = {" +F +Z +Z +F +Z +Z +Z +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +Z +Z +Z +Z +Z +Z +F +"} +(10,1,1) = {" +F +Z +Z +Z +Z +Z +Z +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +p +Z +Z +Z +Z +F +Z +F +"} +(11,1,1) = {" +F +Z +Z +Z +Z +Z Z a a -Z -Z -Z a a a @@ -208,9 +694,6 @@ a a a a -Z -Z -Z a a a @@ -219,22 +702,38 @@ a a a a -Z -Z +a +G +a +a +a +a +a a a a a a a +a +p +p +Z Z Z Z F +Z +F "} -(4,1,1) = {" +(12,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -249,6 +748,7 @@ a a a a +x a a a @@ -270,19 +770,28 @@ a a a a +Z a a a a -a -a -a +p +Z +Z +Z +Z +Z Z F "} -(5,1,1) = {" +(13,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -319,24 +828,38 @@ a a a a +Z +Z a a a -a -a -p +Z +Z +Z +Z +Z +Z Z F "} -(6,1,1) = {" +(14,1,1) = {" F Z +Z +Z +Z +Z +Z a a a a a a +p +p +p +p a a a @@ -358,9 +881,6 @@ a a a a -G -a -a a a a @@ -371,19 +891,34 @@ a a a a -p -p +Z +Z +Z +Z +Z +Z Z F "} -(7,1,1) = {" +(15,1,1) = {" F Z +Z +Z +Z +Z +Z +Z a a a a a +Z +Z +Z +p +a a a a @@ -393,7 +928,6 @@ a a a a -x a a a @@ -416,36 +950,90 @@ a a a Z +Z +Z +Z +Z +Z +Z +F +"} +(16,1,1) = {" +F +Z +Z +Z +Z +Z +Z +Z +a a a a a -p Z -F -"} -(8,1,1) = {" -F Z +Z +p +a +a +a +a +a +a +a +a +a a a a a a a +Z +Z +a +a a a a a a a +p +p +a +a +a a a +Z +Z +Z +Z +Z +Z +F +"} +(17,1,1) = {" +F +Z +Z +Z +Z +Z +Z +Z a a a a a +p +Z +p +p a a a @@ -468,23 +1056,39 @@ Z a a a +a +a +a +a +p +a +a +a +a +a +Z +Z +Z +Z Z Z F "} -(9,1,1) = {" +(18,1,1) = {" F Z +Z +Z +Z +Z +Z +Z a a a a a a -p -p -p -p a a a @@ -504,11 +1108,15 @@ a a a a +Z +Z +Z a a a a a +M a a a @@ -518,21 +1126,27 @@ a a Z Z +Z +Z +Z +Z F "} -(10,1,1) = {" +(19,1,1) = {" F Z Z +Z +Z +Z +Z +a +a a a a a a -Z -Z -Z -p a a a @@ -552,6 +1166,10 @@ a a a a +Z +Z +Z +a a a a @@ -566,21 +1184,31 @@ a a Z Z +Z +Z +Z +Z F "} -(11,1,1) = {" +(20,1,1) = {" F Z Z +Z +Z +Z +Z +a +a +a +a +a +a a a a a a -Z -Z -Z -p a a a @@ -596,8 +1224,6 @@ a a a a -Z -Z a a a @@ -606,29 +1232,35 @@ a a a a -p -p +a +c a a a a a +a +Z +Z +Z +Z +Z Z F "} -(12,1,1) = {" +(21,1,1) = {" F Z Z +Z +Z +Z +Z a a a a a -p -Z -p -p a a a @@ -645,9 +1277,10 @@ a a a a +I +a +a a -Z -Z a a a @@ -655,19 +1288,32 @@ a a a a -p a a a a a +a +a +a +a +a +Z +Z +Z +Z +Z Z F "} -(13,1,1) = {" +(22,1,1) = {" F Z Z +Z +Z +Z +Z a a a @@ -679,6 +1325,10 @@ a a a a +W +a +a +a a a a @@ -693,15 +1343,11 @@ a a a a -Z -Z -Z a a a a a -M a a a @@ -709,12 +1355,23 @@ a a a a +a +Z +Z +Z +Z +Z Z F "} -(14,1,1) = {" +(23,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -741,9 +1398,6 @@ a a a a -Z -Z -Z a a a @@ -757,12 +1411,25 @@ a a a a +a +a +a +Z +Z +Z +Z +Z Z F "} -(15,1,1) = {" +(24,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -798,24 +1465,35 @@ a a a a -c a a a a a a +a +Z +Z +Z +Z +Z Z F "} -(16,1,1) = {" +(25,1,1) = {" F Z +Z +F +Z +Z +Z a a a a a +z a a a @@ -832,7 +1510,6 @@ a a a a -I a a a @@ -854,11 +1531,21 @@ a a a Z +Z +Z +Z +Z +Z F "} -(17,1,1) = {" +(26,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -870,13 +1557,6 @@ a a a a -W -a -a -a -a -a -a a a a @@ -900,13 +1580,30 @@ a a a a +w +S +S +S +S +S +T a Z +Z +Z +Z +Z +F F "} -(18,1,1) = {" +(27,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -942,19 +1639,29 @@ a a a a +S +S +S +S +S +S a -a -a -a -a -a -a +Z +Z +Z +Z +Z Z F "} -(19,1,1) = {" +(28,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -974,6 +1681,7 @@ a a a a +C a a a @@ -989,27 +1697,29 @@ a a a a +S +S +S +S +S +S a -a -a -a -a -a -a -a +Z +Z +Z +Z +Z Z F "} -(20,1,1) = {" +(29,1,1) = {" F Z -a -a -a -a -a -z -a +Z +Z +Z +Z +Z a a a @@ -1042,15 +1752,33 @@ a a a a +X a a +S +S +S +S +S +S a Z +Z +Z +Z +Z +Z F "} -(21,1,1) = {" +(30,1,1) = {" F Z +Z +Z +Z +Z +Z +a a a a @@ -1085,20 +1813,29 @@ a a a a -w S S S S S -T +S a Z +Z +Z +Z +Z +Z F "} -(22,1,1) = {" +(31,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -1142,11 +1879,21 @@ S S a Z +Z +Z +Z +Z +Z F "} -(23,1,1) = {" +(32,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -1166,7 +1913,6 @@ a a a a -C a a a @@ -1182,19 +1928,30 @@ a a a a +w S S S S S -S +A a Z +Z +Z +Z +Z +Z F "} -(24,1,1) = {" +(33,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -1207,6 +1964,10 @@ a a a a +f +a +a +a a a a @@ -1227,27 +1988,35 @@ a a a a -X a a -S -S -S -S -S -S a +a +a +a +Z +Z +Z +Z +Z Z F "} -(25,1,1) = {" +(34,1,1) = {" F Z +Z +Z +Z +Z +Z +a a a a a a +Z a a a @@ -1263,6 +2032,7 @@ a a a a +r a a a @@ -1278,25 +2048,35 @@ a a a a -S -S -S -S -S -S a +a +a +a +Z +Z +Z +Z +Z Z F "} -(26,1,1) = {" +(35,1,1) = {" F Z +Z +Z +Z +Z +Z a a a a a a +Z +Z +Z a a a @@ -1326,24 +2106,37 @@ a a a a -S -S -S -S -S -S a +a +a +a +Z +Z +Z +Z +Z Z F "} -(27,1,1) = {" +(36,1,1) = {" F Z +Z +Z +Z +Z +Z +a a a a a a +Z +Z +Z +a +a a a a @@ -1373,20 +2166,24 @@ a a a a -w -S -S -S -S -S -A a +a +Z +Z +Z +Z +Z Z F "} -(28,1,1) = {" +(37,1,1) = {" F Z +Z +Z +Z +Z +Z a a a @@ -1394,12 +2191,12 @@ a a a a +Z a a a a a -f a a a @@ -1430,12 +2227,21 @@ a a a Z +Z +Z +Z +Z +Z F "} -(29,1,1) = {" +(38,1,1) = {" F Z -a +Z +Z +Z +Z +Z a a a @@ -1457,7 +2263,6 @@ a a a a -r a a a @@ -1471,6 +2276,8 @@ a a a a +d +a a a a @@ -1478,20 +2285,29 @@ a a a Z +Z +Z +Z +Z +Z F "} -(30,1,1) = {" +(39,1,1) = {" F Z +Z +Z +Z +Z +Z +Z a a a a +Z a a -Z -Z -Z a a a @@ -1512,6 +2328,7 @@ a a a a +Z a a a @@ -1526,22 +2343,28 @@ a a a Z +Z +Z +Z +Z +Z F "} -(31,1,1) = {" +(40,1,1) = {" F Z +Z +Z +Z +Z +Z +Z a a a a a a -Z -Z -Z -a -a a a a @@ -1553,6 +2376,7 @@ a a a a +X a a a @@ -1561,6 +2385,9 @@ a a a a +Z +Z +Z a a a @@ -1574,11 +2401,22 @@ a a a Z +Z +Z +Z +Z +Z F "} -(32,1,1) = {" +(41,1,1) = {" F Z +Z +Z +Z +Z +Z +Z a a a @@ -1586,10 +2424,6 @@ a a a a -Z -a -a -a a a a @@ -1609,6 +2443,9 @@ a a a a +Z +Z +Z a a a @@ -1622,17 +2459,27 @@ a a a Z +Z +Z +Z +Z +Z F "} -(33,1,1) = {" +(42,1,1) = {" +F +Z +Z F Z +Z +Z +Z a a a a a -Z a a a @@ -1661,7 +2508,6 @@ a a a a -d a a a @@ -1670,40 +2516,50 @@ a a a Z +Z +Z +Z +Z +Z +Z F "} -(34,1,1) = {" +(43,1,1) = {" F Z Z -a -a -a -a Z +Z +Z +Z +a a a +p +p a a a a a +g a a a a +Z a a a a a a +p a a a a a -Z a a a @@ -1718,15 +2574,27 @@ a a a Z +Z +Z +Z +Z +Z +Z F "} -(35,1,1) = {" +(44,1,1) = {" F Z Z +Z +Z +Z +Z a a a +p +p a a a @@ -1736,23 +2604,22 @@ a a a a +Z +Z +Z a a a a a -X -a -a +p +p a a a a a a -Z -Z -Z a a a @@ -1766,13 +2633,23 @@ a a a Z +Z +Z +Z +Z +Z F "} -(36,1,1) = {" +(45,1,1) = {" F Z Z +Z +Z +Z +Z a +c a a a @@ -1798,9 +2675,6 @@ a a a a -Z -Z -Z a a a @@ -1813,13 +2687,26 @@ a a a a +a +a +a +Z +Z +Z +Z +Z Z F "} -(37,1,1) = {" +(46,1,1) = {" F Z Z +Z +Z +Z +Z +a a a a @@ -1853,6 +2740,7 @@ a a a a +Y a a a @@ -1862,34 +2750,32 @@ a a Z Z +Z +Z +Z +Z F "} -(38,1,1) = {" +(47,1,1) = {" F Z +Z +Z +Z +Z +Z a a a -p -p -a -a -a -a -a -g -a a a a -Z a a a a a a -p a a a @@ -1908,18 +2794,9 @@ a a a a -Z -Z -F -"} -(39,1,1) = {" -F -Z a a a -p -p a a a @@ -1932,227 +2809,360 @@ a Z Z Z +Z +Z +Z +F +"} +(48,1,1) = {" +F +Z +Z +Z +Z +Z +Z a +Z +Z +Z +Z a a a a -p -p a +Z +Z +Z +Z a a a +Z +Z +Z +Z +Z a a a a a a +Z +Z +Z +Z a a a a a a +Z +Z a a Z +Z +Z +Z +Z +Z +F +"} +(49,1,1) = {" +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +Z +Z +Z +Z +F +"} +(50,1,1) = {" +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +"} +(51,1,1) = {" +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z F "} -(40,1,1) = {" +(52,1,1) = {" F Z -a -c -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Z +Z +Z +Z Z F -"} -(41,1,1) = {" F Z -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -Y -a -a -a -a -a -a -a +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z Z F -"} -(42,1,1) = {" +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z F Z -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Z +Z +Z +Z +Z +Z +Z +Z Z F "} -(43,1,1) = {" +(53,1,1) = {" F Z -a Z Z Z Z -a -a -a -a -a Z Z Z Z -a -a -a Z Z Z Z Z -a -a -a -a -a -a Z Z Z Z -a -a -a -a -a -a Z Z -a -a +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +F +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z +Z Z F "} -(44,1,1) = {" +(54,1,1) = {" F Z Z @@ -2191,16 +3201,36 @@ Z Z Z Z +F +Z +Z +Z +Z +Z +Z +Z +Z Z Z Z +F Z Z Z Z F "} -(45,1,1) = {" +(55,1,1) = {" +F +F +F +F +F +F +F +F +F +F F F F diff --git a/_maps/virtual_domains/colossus.dmm b/_maps/virtual_domains/colossus.dmm index a9c3c6e6d79e72..fe97dcace42882 100644 --- a/_maps/virtual_domains/colossus.dmm +++ b/_maps/virtual_domains/colossus.dmm @@ -30,7 +30,7 @@ /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, /area/lavaland/surface/outdoors/virtual_domain) "p" = ( -/mob/living/simple_animal/hostile/megafauna/colossus/virtual_domain, +/mob/living/simple_animal/hostile/megafauna/colossus, /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, /area/lavaland/surface/outdoors/virtual_domain) "q" = ( @@ -41,7 +41,7 @@ /obj/machinery/light/small/blacklight/directional/south, /obj/effect/baseturf_helper/virtual_domain, /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins, -/area/virtual_domain/powered) +/area/virtual_domain) "s" = ( /turf/open/lava/smooth/lava_land_surface, /area/lavaland/surface/outdoors/virtual_domain) diff --git a/_maps/virtual_domains/hierophant.dmm b/_maps/virtual_domains/hierophant.dmm index 02b11ad4e1ef43..81f8a9f97a73ed 100644 --- a/_maps/virtual_domains/hierophant.dmm +++ b/_maps/virtual_domains/hierophant.dmm @@ -37,7 +37,7 @@ /turf/closed/indestructible/binary, /area/lavaland/surface/outdoors/virtual_domain) "E" = ( -/mob/living/simple_animal/hostile/megafauna/hierophant/virtual_domain, +/mob/living/simple_animal/hostile/megafauna/hierophant, /turf/open/indestructible/hierophant/two, /area/lavaland/surface/outdoors/virtual_domain) "H" = ( @@ -51,7 +51,7 @@ /obj/machinery/light/small/blacklight/directional/south, /obj/effect/baseturf_helper/virtual_domain, /turf/open/indestructible/hierophant, -/area/virtual_domain/powered) +/area/virtual_domain) "S" = ( /obj/effect/mob_spawn/corpse/human/miner, /turf/open/indestructible/hierophant, diff --git a/_maps/virtual_domains/pirates.dmm b/_maps/virtual_domains/pirates.dmm index 9c970f78c371a0..9868ab8e9b32ed 100644 --- a/_maps/virtual_domains/pirates.dmm +++ b/_maps/virtual_domains/pirates.dmm @@ -161,7 +161,7 @@ dir = 8 }, /obj/effect/decal/cleanable/dirt/dust, -/mob/living/simple_animal/hostile/pirate/ranged/space, +/mob/living/basic/trooper/pirate/ranged/space, /turf/open/floor/carpet/blue, /area/virtual_domain/powered) "iO" = ( @@ -293,7 +293,7 @@ /area/virtual_domain/powered) "nX" = ( /obj/effect/decal/cleanable/dirt/dust, -/mob/living/simple_animal/hostile/pirate/melee/space, +/mob/living/basic/trooper/pirate/melee/space, /turf/open/floor/wood/parquet, /area/virtual_domain/powered) "oo" = ( @@ -342,7 +342,7 @@ }, /obj/effect/mapping_helpers/burnt_floor, /obj/effect/decal/cleanable/dirt/dust, -/mob/living/simple_animal/hostile/pirate/ranged, +/mob/living/basic/trooper/pirate/ranged, /turf/open/floor/wood, /area/virtual_domain/powered) "qN" = ( @@ -385,7 +385,7 @@ /turf/open/misc/grass, /area/virtual_domain/powered) "to" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /turf/open/misc/grass, /area/virtual_domain/powered) "ub" = ( @@ -472,7 +472,7 @@ /turf/open/misc/dirt/jungle, /area/virtual_domain/powered) "yi" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /turf/open/misc/beach/sand, /area/virtual_domain/powered) "yq" = ( @@ -481,7 +481,7 @@ /area/virtual_domain/powered) "yw" = ( /obj/effect/mapping_helpers/burnt_floor, -/mob/living/simple_animal/hostile/pirate/ranged, +/mob/living/basic/trooper/pirate/ranged, /obj/structure/chair/wood, /turf/open/floor/wood{ icon_state = "wood_large" @@ -616,7 +616,7 @@ /area/virtual_domain/powered) "Hp" = ( /obj/effect/turf_decal/siding/wood, -/mob/living/simple_animal/hostile/pirate/ranged, +/mob/living/basic/trooper/pirate/ranged, /turf/open/floor/wood, /area/virtual_domain/powered) "HY" = ( diff --git a/_maps/virtual_domains/wendigo.dmm b/_maps/virtual_domains/wendigo.dmm index 17bcb48d688bfc..dcce722cbbd047 100644 --- a/_maps/virtual_domains/wendigo.dmm +++ b/_maps/virtual_domains/wendigo.dmm @@ -58,7 +58,7 @@ /turf/open/misc/asteroid/snow/ice/icemoon, /area/icemoon/underground/explored/virtual_domain) "H" = ( -/mob/living/simple_animal/hostile/megafauna/wendigo/virtual_domain, +/mob/living/simple_animal/hostile/megafauna/wendigo, /turf/open/indestructible/necropolis{ initial_gas_mix = "ICEMOON_ATMOS" }, diff --git a/code/__DEFINES/achievements.dm b/code/__DEFINES/achievements.dm index 4a0299d835ac32..cfe3cd2e456ae8 100644 --- a/code/__DEFINES/achievements.dm +++ b/code/__DEFINES/achievements.dm @@ -46,7 +46,7 @@ #define MEDAL_VOID_ASCENSION "Void" #define MEDAL_BLADE_ASCENSION "Blade" #define MEDAL_COSMOS_ASCENSION "Cosmos" -#define MEDAL_KNOCK_ASCENSION "Knock" +#define MEDAL_LOCK_ASCENSION "Knock" #define MEDAL_TOOLBOX_SOUL "Toolsoul" #define MEDAL_CHEM_TUT "Beginner Chemist" #define MEDAL_HOT_DAMN "Hot Damn!" diff --git a/code/__DEFINES/actions.dm b/code/__DEFINES/actions.dm index 5bc2b161781247..99f9c1aca551d9 100644 --- a/code/__DEFINES/actions.dm +++ b/code/__DEFINES/actions.dm @@ -41,3 +41,10 @@ DEFINE_BITFIELD(check_flags, list( #define UPDATE_BUTTON_BACKGROUND (1<<2) #define UPDATE_BUTTON_OVERLAY (1<<3) #define UPDATE_BUTTON_STATUS (1<<4) + +/// Takes in a typepath of a `/datum/action` and adds it to `src`. +/// Only useful if you want to add the action and never desire to reference it again ever. +#define GRANT_ACTION(typepath) do {\ + var/datum/action/_ability = new typepath(src);\ + _ability.Grant(src);\ +} while (FALSE) diff --git a/code/__DEFINES/ai/ai.dm b/code/__DEFINES/ai/ai.dm index 53cbf117af410e..5e0b979b2f8c8f 100644 --- a/code/__DEFINES/ai/ai.dm +++ b/code/__DEFINES/ai/ai.dm @@ -1,4 +1,5 @@ #define GET_AI_BEHAVIOR(behavior_type) SSai_behaviors.ai_behaviors[behavior_type] +#define GET_TARGETING_STRATEGY(targeting_type) SSai_behaviors.targeting_strategies[targeting_type] #define HAS_AI_CONTROLLER_TYPE(thing, type) istype(thing?.ai_controller, type) #define AI_STATUS_ON 1 diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 484b38b0fd16bd..3da9c08ae27ed9 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -40,31 +40,33 @@ ///Basic Mob Keys -///Targetting subtrees +///Targeting subtrees #define BB_BASIC_MOB_CURRENT_TARGET "BB_basic_current_target" #define BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION "BB_basic_current_target_hiding_location" -#define BB_TARGETTING_DATUM "targetting_datum" +#define BB_TARGETING_STRATEGY "targeting_strategy" ///some behaviors that check current_target also set this on deep crit mobs #define BB_BASIC_MOB_EXECUTION_TARGET "BB_basic_execution_target" ///Blackboard key for a whitelist typecache of "things we can target while trying to move" -#define BB_OBSTACLE_TARGETTING_WHITELIST "BB_targetting_whitelist" +#define BB_OBSTACLE_TARGETING_WHITELIST "BB_targeting_whitelist" /// Key for the minimum status at which we want to target mobs (does not need to be specified if CONSCIOUS) #define BB_TARGET_MINIMUM_STAT "BB_target_minimum_stat" /// Flag for whether to target only wounded mobs #define BB_TARGET_WOUNDED_ONLY "BB_target_wounded_only" +/// What typepath the holding object targeting strategy should look for +#define BB_TARGET_HELD_ITEM "BB_target_held_item" -/// Blackboard key storing how long your targetting datum has held a particular target +/// Blackboard key storing how long your targeting strategy has held a particular target #define BB_BASIC_MOB_HAS_TARGET_TIME "BB_basic_mob_has_target_time" -///Targetting keys for something to run away from, if you need to store this separately from current target +///Targeting keys for something to run away from, if you need to store this separately from current target #define BB_BASIC_MOB_FLEE_TARGET "BB_basic_flee_target" #define BB_BASIC_MOB_FLEE_TARGET_HIDING_LOCATION "BB_basic_flee_target_hiding_location" -#define BB_FLEE_TARGETTING_DATUM "flee_targetting_datum" +#define BB_FLEE_TARGETING_STRATEGY "flee_targeting_strategy" #define BB_BASIC_MOB_FLEE_DISTANCE "BB_basic_flee_distance" #define DEFAULT_BASIC_FLEE_DISTANCE 9 -/// Generic key for a non-specific targetted action -#define BB_TARGETTED_ACTION "BB_targetted_action" +/// Generic key for a non-specific targeted action +#define BB_TARGETED_ACTION "BB_TARGETED_action" /// Generic key for a non-specific action #define BB_GENERIC_ACTION "BB_generic_action" @@ -115,9 +117,9 @@ ///Range for a MOD AI controller. #define MOD_AI_RANGE 200 -///should we skip the faction check for the targetting datum? +///should we skip the faction check for the targeting strategy? #define BB_ALWAYS_IGNORE_FACTION "BB_always_ignore_factions" -///are we in some kind of temporary state of ignoring factions when targetting? can result in volatile results if multiple behaviours touch this +///are we in some kind of temporary state of ignoring factions when targeting? can result in volatile results if multiple behaviours touch this #define BB_TEMPORARILY_IGNORE_FACTION "BB_temporarily_ignore_factions" ///currently only used by clowns, a list of what can the mob speak randomly diff --git a/code/__DEFINES/ai/carp.dm b/code/__DEFINES/ai/carp.dm index 8286f326207748..459b98ffb0204b 100644 --- a/code/__DEFINES/ai/carp.dm +++ b/code/__DEFINES/ai/carp.dm @@ -7,9 +7,9 @@ /// Current target turf in your migration #define BB_CARP_MIGRATION_TARGET "BB_carp_migration_target" -/// Targetting keys for magicarp spells +/// Targeting keys for magicarp spells #define BB_MAGICARP_SPELL_TARGET "BB_magicarp_spell_target" -#define BB_MAGICARP_SPELL_SPECIAL_TARGETTING "BB_magicarp_spell_special_targetting" +#define BB_MAGICARP_SPELL_SPECIAL_TARGETING "BB_magicarp_spell_special_targeting" #define MAGICARP_SPELL_CORPSES "magicarp_spell_corpses" #define MAGICARP_SPELL_WALLS "magicarp_spell_walls" #define MAGICARP_SPELL_OBJECTS "magicarp_spell_objects" diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm index 72d756c0554609..750d65e6eb33e3 100644 --- a/code/__DEFINES/ai/monsters.dm +++ b/code/__DEFINES/ai/monsters.dm @@ -160,10 +160,8 @@ #define BB_DEMON_CLONE_ABILITY "demon_clone_ability" ///our slippery ice ability #define BB_DEMON_SLIP_ABILITY "demon_slip_ability" -///the turf we are escaping too +///the turf we are escaping to #define BB_ESCAPE_DESTINATION "escape_destination" -///how far away we will be from our target before teleporting -#define BB_MINIMUM_DISTANCE_RANGE "minimum_distance_range" /// Corpse we have consumed #define BB_LEGION_CORPSE "legion_corpse" @@ -191,3 +189,30 @@ #define BB_MOOK_MUSIC_AUDIENCE "music_audience" /// the bonfire we will light up #define BB_MOOK_BONFIRE_TARGET "bonfire_target" + +//leaper keys +///key holds our volley ability +#define BB_LEAPER_VOLLEY "leaper_volley" +///key holds our flop ability +#define BB_LEAPER_FLOP "leaper_flop" +///key holds our bubble ability +#define BB_LEAPER_BUBBLE "leaper_bubble" +///key holds our summon ability +#define BB_LEAPER_SUMMON "leaper_summon" +///key holds the world timer for swimming +#define BB_KEY_SWIM_TIME "key_swim_time" +///key holds the water or land target turf +#define BB_SWIM_ALTERNATE_TURF "swim_alternate_turf" +///key holds our state of swimming +#define BB_CURRENTLY_SWIMMING "currently_swimming" +///key holds how long we will be swimming for +#define BB_KEY_SWIMMER_COOLDOWN "key_swimmer_cooldown" +//Wizard AI keys +/// Key where we store our main targeted spell +#define BB_WIZARD_TARGETED_SPELL "BB_wizard_targeted_spell" +/// Key where we store our secondary, untargeted spell +#define BB_WIZARD_SECONDARY_SPELL "BB_wizard_secondary_spell" +/// Key where we store our blink spell +#define BB_WIZARD_BLINK_SPELL "BB_wizard_blink_spell" +/// Key for the next time we can cast a spell +#define BB_WIZARD_SPELL_COOLDOWN "BB_wizard_spell_cooldown" diff --git a/code/__DEFINES/ai/pet_commands.dm b/code/__DEFINES/ai/pet_commands.dm index 5894aedff14d06..1e692b9f805aaa 100644 --- a/code/__DEFINES/ai/pet_commands.dm +++ b/code/__DEFINES/ai/pet_commands.dm @@ -4,6 +4,6 @@ /// Blackboard field for what we actually want the pet to target #define BB_CURRENT_PET_TARGET "BB_current_pet_target" /// Blackboard field for how we target things, as usually we want to be more permissive than normal -#define BB_PET_TARGETTING_DATUM "BB_pet_targetting" +#define BB_PET_TARGETING_STRATEGY "BB_pet_targeting" /// Typecache of weakrefs to mobs this mob is friends with, will follow their instructions and won't attack them #define BB_FRIENDS_LIST "BB_friends_list" diff --git a/code/__DEFINES/ai/trader.dm b/code/__DEFINES/ai/trader.dm new file mode 100644 index 00000000000000..853dd8736b6492 --- /dev/null +++ b/code/__DEFINES/ai/trader.dm @@ -0,0 +1,6 @@ +///The ability to setup our "shop" +#define BB_SETUP_SHOP "BB_setup_shop" +///Reference to the plastic chair that is considered as our shop +#define BB_SHOP_SPOT "BB_shop_spot" +///Reference to our first customer to harass with deals +#define BB_FIRST_CUSTOMER "BB_first_customer" diff --git a/code/__DEFINES/ai/ventcrawling.dm b/code/__DEFINES/ai/ventcrawling.dm index f981ef3bba5d62..a60b7fd594017f 100644 --- a/code/__DEFINES/ai/ventcrawling.dm +++ b/code/__DEFINES/ai/ventcrawling.dm @@ -3,7 +3,7 @@ /// Key that holds a vent that we want to exit out of (when we're already in a pipenet) #define BB_EXIT_VENT_TARGET "BB_exit_vent_target" /// Do we plan on going inside a vent? Boolean. -#define BB_CURRENTLY_TARGETTING_VENT "BB_currently_targetting_vent" +#define BB_CURRENTLY_TARGETING_VENT "BB_currently_targeting_vent" /// How long should we wait before we try and enter a vent again? #define BB_VENTCRAWL_COOLDOWN "BB_ventcrawl_cooldown" /// The least amount of time (in seconds) we take to go through the vents. diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 8ac421f8b0a897..94296a25d9ed9f 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -80,7 +80,7 @@ #define PATH_VOID "Void Path" #define PATH_BLADE "Blade Path" #define PATH_COSMIC "Cosmic Path" -#define PATH_KNOCK "Knock Path" +#define PATH_LOCK "Lock Path" /// Defines are used in /proc/has_living_heart() to report if the heretic has no heart period, no living heart, or has a living heart. #define HERETIC_NO_HEART_ORGAN -1 diff --git a/code/__DEFINES/atmospherics/atmos_mapping_helpers.dm b/code/__DEFINES/atmospherics/atmos_mapping_helpers.dm index dd794cbf0539f5..9a040f0c160a03 100644 --- a/code/__DEFINES/atmospherics/atmos_mapping_helpers.dm +++ b/code/__DEFINES/atmospherics/atmos_mapping_helpers.dm @@ -7,6 +7,8 @@ #define OPENTURF_DEFAULT_ATMOS GAS_O2 + "=22;" + GAS_N2 + "=82;TEMP=293.15" /// the default low-pressure air mix used mostly for mining areas. #define OPENTURF_LOW_PRESSURE GAS_O2 + "=14;" + GAS_N2 + "=30;TEMP=293.15" +/// breathable air that causes disease +#define OPENTURF_DIRTY_ATMOS GAS_MIASMA + "=15;" + GAS_O2 + "=88;TEMP=293.15" /// -193,15°C telecommunications. also used for xenobiology slime killrooms #define TCOMMS_ATMOS GAS_N2 + "=100;TEMP=80" /// space diff --git a/code/__DEFINES/botany.dm b/code/__DEFINES/botany.dm index c2ec221b5e26e4..9607819c880728 100644 --- a/code/__DEFINES/botany.dm +++ b/code/__DEFINES/botany.dm @@ -84,3 +84,6 @@ /// A list of possible egg laying descriptions #define EGG_LAYING_MESSAGES list("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.") + +/// Used as a baseline plant rarity for more uncommon plants, usually requiring mutation +#define PLANT_MODERATELY_RARE 20 diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index b23df993432799..eae18813fae22c 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -33,6 +33,13 @@ #define COLOR_HALF_TRANSPARENT_BLACK "#0000007A" #define COLOR_RED "#FF0000" +#define COLOR_CHRISTMAS_RED "#D6001C" +#define COLOR_OLD_GLORY_RED "#B22234" +#define COLOR_FRENCH_RED "#EF4135" +#define COLOR_ETHIOPIA_RED "#DA121A" +#define COLOR_UNION_JACK_RED "#C8102E" +#define COLOR_MEDIUM_DARK_RED "#CC0000" +#define COLOR_PINK_RED "EF3340" #define COLOR_SYNDIE_RED "#F10303" #define COLOR_SYNDIE_RED_HEAD "#760500" #define COLOR_MOSTLY_PURE_RED "#FF3300" @@ -50,7 +57,10 @@ #define COLOR_YELLOW "#FFFF00" #define COLOR_VIVID_YELLOW "#FBFF23" +#define COLOR_TANGERINE_YELLOW "#FFCC00" #define COLOR_VERY_SOFT_YELLOW "#FAE48E" +#define COLOR_GOLD "#FFD700" +#define COLOR_ETHIOPIA_YELLOW "#FCDD09" #define COLOR_OLIVE "#808000" #define COLOR_ASSISTANT_OLIVE "#828163" @@ -63,6 +73,9 @@ #define COLOR_VERY_PALE_LIME_GREEN "#DDFFD3" #define COLOR_VERY_DARK_LIME_GREEN "#003300" #define COLOR_GREEN "#008000" +#define COLOR_CHRISTMAS_GREEN "#00873E" +#define COLOR_IRISH_GREEN "#169B62" +#define COLOR_ETHIOPIA_GREEN "#078930" #define COLOR_DARK_MODERATE_LIME_GREEN "#44964A" #define COLOR_PAI_GREEN "#00FF88" #define COLOR_PALE_GREEN "#20e28e" @@ -72,6 +85,10 @@ #define COLOR_DARK_CYAN "#00A2FF" #define COLOR_TEAL "#008080" #define COLOR_BLUE "#0000FF" +#define COLOR_OLD_GLORY_BLUE "#3C3B6E" +#define COLOR_FRENCH_BLUE "#0055A4" +#define COLOR_UNION_JACK_BLUE "#012169" +#define COLOR_TRUE_BLUE "#0066CC" #define COLOR_STRONG_BLUE "#1919c8" #define COLOR_CENTCOM_BLUE "#134975" #define COLOR_BRIGHT_BLUE "#2CB2E8" @@ -101,6 +118,7 @@ #define COLOR_DARK_PURPLE "#551A8B" #define COLOR_ORANGE "#FF9900" +#define COLOR_IRISH_ORANGE "#FF883E" #define COLOR_ENGINEERING_ORANGE "#FFA62B" #define COLOR_MOSTLY_PURE_ORANGE "#ff8000" #define COLOR_TAN_ORANGE "#FF7B00" diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm index 63c1f2fd7136e8..3335ac50fc4a9c 100644 --- a/code/__DEFINES/cooldowns.dm +++ b/code/__DEFINES/cooldowns.dm @@ -74,14 +74,18 @@ #define TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(end_cooldown), cd_source, cd_index), cd_time)) -#define TIMER_COOLDOWN_CHECK(cd_source, cd_index) LAZYACCESS(cd_source.cooldowns, cd_index) +/// Checks if a timer based cooldown is NOT finished. +#define TIMER_COOLDOWN_RUNNING(cd_source, cd_index) LAZYACCESS(cd_source.cooldowns, cd_index) + +/// Checks if a timer based cooldown is finished. +#define TIMER_COOLDOWN_FINISHED(cd_source, cd_index) (!TIMER_COOLDOWN_RUNNING(cd_source, cd_index)) #define TIMER_COOLDOWN_END(cd_source, cd_index) LAZYREMOVE(cd_source.cooldowns, cd_index) /* * Stoppable timer cooldowns. * Use indexes the same as the regular tiemr cooldowns. - * They make use of the TIMER_COOLDOWN_CHECK() and TIMER_COOLDOWN_END() macros the same, just not the TIMER_COOLDOWN_START() one. + * They make use of the TIMER_COOLDOWN_RUNNING() and TIMER_COOLDOWN_END() macros the same, just not the TIMER_COOLDOWN_START() one. * A bit more expensive than the regular timers, but can be reset before they end and the time left can be checked. */ @@ -89,7 +93,7 @@ #define S_TIMER_COOLDOWN_RESET(cd_source, cd_index) reset_cooldown(cd_source, cd_index) -#define S_TIMER_COOLDOWN_TIMELEFT(cd_source, cd_index) (timeleft(TIMER_COOLDOWN_CHECK(cd_source, cd_index))) +#define S_TIMER_COOLDOWN_TIMELEFT(cd_source, cd_index) (timeleft(TIMER_COOLDOWN_RUNNING(cd_source, cd_index))) /* diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm index cd123e2e0b15e3..c3ec1aa8a84684 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm @@ -125,5 +125,5 @@ #define COMSIG_ATOM_GERM_EXPOSED "atom_germ_exposed" /// when atom is picked up from the floor or moved to an elevated structure: (datum/component/germ_exposure) #define COMSIG_ATOM_GERM_UNEXPOSED "atom_germ_unexposed" -/// when atom is washed -#define COMSIG_ATOM_WASHED "atom_washed" +/// signal sent to puzzle pieces by activator +#define COMSIG_PUZZLE_COMPLETED "puzzle_completed" diff --git a/code/__DEFINES/dcs/signals/signals_bitrunning.dm b/code/__DEFINES/dcs/signals/signals_bitrunning.dm index e2731a05b34e73..3bca73db596b32 100644 --- a/code/__DEFINES/dcs/signals/signals_bitrunning.dm +++ b/code/__DEFINES/dcs/signals/signals_bitrunning.dm @@ -1,37 +1,50 @@ -/// from /obj/machinery/netpod/default_pry_open() : (mob/living/intruder) -#define COMSIG_BITRUNNER_CROWBAR_ALERT "bitrunner_crowbar" +/// from /atom/movable/screen/alert/bitrunning/qserver_domain_complete +#define COMSIG_BITRUNNER_ALERT_SEVER "bitrunner_alert_sever" /// from /obj/effect/bitrunning/loot_signal: (points) #define COMSIG_BITRUNNER_GOAL_POINT "bitrunner_goal_point" -/// from /obj/machinery/quantum_server/on_goal_turf_entered(): (atom/entered, reward_points) -#define COMSIG_BITRUNNER_DOMAIN_COMPLETE "bitrunner_complete" +// Netpods + +/// from /obj/machinery/netpod/sever_connection() +#define COMSIG_BITRUNNER_NETPOD_SEVER "bitrunner_netpod_sever" + +/// from /obj/machinery/netpod/default_pry_open() : (mob/living/intruder) +#define COMSIG_BITRUNNER_CROWBAR_ALERT "bitrunner_crowbar" -/// from /obj/machinery/netpod/on_take_damage() +/// from /obj/machinery/netpod/on_damage_taken() #define COMSIG_BITRUNNER_NETPOD_INTEGRITY "bitrunner_netpod_damage" -/// from /obj/structure/hololadder and complete alert -#define COMSIG_BITRUNNER_SAFE_DISCONNECT "bitrunner_disconnect" +/// from /obj/machinery/netpod/open_machine() +#define COMSIG_BITRUNNER_NETPOD_OPENED "bitrunner_netpod_opened" + +// Server + +/// from /obj/machinery/quantum_server/on_goal_turf_entered(): (atom/entered, reward_points) +#define COMSIG_BITRUNNER_DOMAIN_COMPLETE "bitrunner_complete" + +/// from /obj/machinery/quantum_server/generate_loot() +#define COMSIG_BITRUNNER_CACHE_SEVER "bitrunner_cache_sever" -/// from /obj/machinery/netpod/open_machine(), /obj/machinery/quantum_server, etc (obj/machinery/netpod) -#define COMSIG_BITRUNNER_SEVER_AVATAR "bitrunner_sever" +/// from /obj/machinery/quantum_server/sever_connection() +#define COMSIG_BITRUNNER_QSRV_SEVER "bitrunner_qserver_sever" /// from /obj/machinery/quantum_server/shutdown() : (mob/living) #define COMSIG_BITRUNNER_SHUTDOWN_ALERT "bitrunner_shutdown" -// Notifies the bitrunners -/// from /datum/antagonist/cyber_police/proc/notify() : +/// from /obj/machinery/quantum_server/notify_threat() #define COMSIG_BITRUNNER_THREAT_CREATED "bitrunner_threat" -// Informs the server to up the threat count -/// from event spawns: (mob/living) -#define COMSIG_BITRUNNER_SPAWN_GLITCH "bitrunner_spawn_glitch" - -/// from /obj/machinery/quantum_server/refreshParts(): (servo rating) -#define COMSIG_BITRUNNER_SERVER_UPGRADED "bitrunner_server_upgraded" - /// from /obj/machinery/quantum_server/scrub_vdom() #define COMSIG_BITRUNNER_DOMAIN_SCRUBBED "bitrunner_domain_scrubbed" -/// from /obj/machinery/netpod/open_machine() -#define COMSIG_BITRUNNER_NETPOD_OPENED "bitrunner_netpod_opened" +/// from /obj/machienry/quantum_server/station_spawn() +#define COMSIG_BITRUNNER_STATION_SPAWN "bitrunner_station_spawn" + +// Ladder +/// from /obj/structure/hololadder/disconnect() +#define COMSIG_BITRUNNER_LADDER_SEVER "bitrunner_ladder_sever" + + +/// deprecated +#define COMSIG_BITRUNNER_SPAWN_GLITCH "bitrunner_spawn_glitch" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_guardian.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_guardian.dm new file mode 100644 index 00000000000000..9f4819de79749f --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_guardian.dm @@ -0,0 +1,7 @@ +/// Sent when a guardian is manifested +#define COMSIG_GUARDIAN_MANIFESTED "guardian_manifested" +/// Sent when a guardian is recalled +#define COMSIG_GUARDIAN_RECALLED "guardian_recalled" + +/// Sent when an assassin guardian is forced to exit stealth +#define COMSIG_GUARDIAN_ASSASSIN_REVEALED "guardian_assassin_revealed" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index ceebe7f304be7c..160849218d1d7e 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -225,3 +225,8 @@ #define COMSIG_MOB_LOST_CHAIN_TAIL "living_detached_chain_tail" /// Sent from a 'contract chain' button on a mob chain #define COMSIG_MOB_CHAIN_CONTRACT "living_chain_contracted" + +/// Sent from a mob to their loc when starting to remove cuffs on itself +#define COMSIG_MOB_REMOVING_CUFFS "living_removing_cuffs" +/// Sent as a reply to above from any atom that wishs to stop self-cuff removal +#define COMSIG_MOB_BLOCK_CUFF_REMOVAL (1<<0) diff --git a/code/__DEFINES/exosuit_fab.dm b/code/__DEFINES/exosuit_fab.dm index 706daf6e2dec29..4cc21f210d61dd 100644 --- a/code/__DEFINES/exosuit_fab.dm +++ b/code/__DEFINES/exosuit_fab.dm @@ -33,10 +33,12 @@ #define EXOSUIT_MODULE_RETICENCE (1<<9) /// Module is compatible with Marauder models #define EXOSUIT_MODULE_MARAUDER (1<<10) +/// Module is compatible with Paddy models +#define EXOSUIT_MODULE_PADDY (1<<11) /// Module is compatible with "Working" Exosuit models - Ripley and Clarke #define EXOSUIT_MODULE_WORKING (EXOSUIT_MODULE_RIPLEY | EXOSUIT_MODULE_CLARKE) /// Module is compatible with "Combat" Exosuit models - Gygax, H.O.N.K, Durand and Phazon, or any Exosuit with an empty Concealed Weapon Bay -#define EXOSUIT_MODULE_COMBAT (EXOSUIT_MODULE_GYGAX | EXOSUIT_MODULE_HONK | EXOSUIT_MODULE_DURAND | EXOSUIT_MODULE_PHAZON | EXOSUIT_MODULE_SAVANNAH | EXOSUIT_MODULE_RETICENCE | EXOSUIT_MODULE_MARAUDER | EXOSUIT_MODULE_CONCEALED_WEP_BAY) +#define EXOSUIT_MODULE_COMBAT (EXOSUIT_MODULE_GYGAX | EXOSUIT_MODULE_HONK | EXOSUIT_MODULE_DURAND | EXOSUIT_MODULE_PHAZON | EXOSUIT_MODULE_SAVANNAH | EXOSUIT_MODULE_RETICENCE | EXOSUIT_MODULE_MARAUDER | EXOSUIT_MODULE_PADDY | EXOSUIT_MODULE_CONCEALED_WEP_BAY) /// Module is compatible with "Medical" Exosuit modelsm - Odysseus #define EXOSUIT_MODULE_MEDICAL EXOSUIT_MODULE_ODYSSEUS diff --git a/code/__DEFINES/guardian_defines.dm b/code/__DEFINES/guardian_defines.dm index e7961368feee09..ae2c3175b4a615 100644 --- a/code/__DEFINES/guardian_defines.dm +++ b/code/__DEFINES/guardian_defines.dm @@ -3,5 +3,28 @@ #define GUARDIAN_THEME_CARP "carp" #define GUARDIAN_THEME_MINER "miner" -#define GUARDIAN_COLOR_LAYER 1 -#define GUARDIAN_TOTAL_LAYERS 1 +#define GUARDIAN_MAGIC "magic" +#define GUARDIAN_TECH "tech" + +#define GUARDIAN_ASSASSIN "assassin" +#define GUARDIAN_CHARGER "charger" +#define GUARDIAN_DEXTROUS "dextrous" +#define GUARDIAN_EXPLOSIVE "explosive" +#define GUARDIAN_GASEOUS "gaseous" +#define GUARDIAN_GRAVITOKINETIC "gravitokinetic" +#define GUARDIAN_LIGHTNING "lightning" +#define GUARDIAN_PROTECTOR "protector" +#define GUARDIAN_RANGED "ranged" +#define GUARDIAN_STANDARD "standard" +#define GUARDIAN_SUPPORT "support" + +/// List of all guardians currently extant +GLOBAL_LIST_EMPTY(parasites) + +/// Assoc list of guardian theme singletons +GLOBAL_LIST_INIT(guardian_themes, list( + GUARDIAN_THEME_TECH = new /datum/guardian_fluff/tech, + GUARDIAN_THEME_MAGIC = new /datum/guardian_fluff, + GUARDIAN_THEME_CARP = new /datum/guardian_fluff/carp, + GUARDIAN_THEME_MINER = new /datum/guardian_fluff/miner, +)) diff --git a/code/__DEFINES/icon_smoothing.dm b/code/__DEFINES/icon_smoothing.dm index 55d25fd5e45b81..c00361184a50a3 100644 --- a/code/__DEFINES/icon_smoothing.dm +++ b/code/__DEFINES/icon_smoothing.dm @@ -132,12 +132,12 @@ DEFINE_BITFIELD(smoothing_junction, list( #define SMOOTH_GROUP_TURF_OPEN_CLIFF S_TURF(60) ///turf/open/cliff // SKYRAT EDIT ADDITION -#define SMOOTH_GROUP_ELEVATED_PLASTEEL S_TURF(60) -#define SMOOTH_GROUP_LOWERED_PLASTEEL S_TURF(61) +#define SMOOTH_GROUP_ELEVATED_PLASTEEL S_TURF(61) +#define SMOOTH_GROUP_LOWERED_PLASTEEL S_TURF(62) -#define SMOOTH_GROUP_FISSURE S_TURF(62) +#define SMOOTH_GROUP_FISSURE S_TURF(63) -#define MAX_S_TURF 62 //Always match this value with the one above it. +#define MAX_S_TURF 63 //Always match this value with the one above it. //SKYRAT EDIT END diff --git a/code/__DEFINES/interaction_flags.dm b/code/__DEFINES/interaction_flags.dm index 0b4e9588729430..55732f2364bb1e 100644 --- a/code/__DEFINES/interaction_flags.dm +++ b/code/__DEFINES/interaction_flags.dm @@ -36,9 +36,8 @@ #define INTERACT_MACHINE_OPEN_SILICON (1<<4) /// must be silicon to interact #define INTERACT_MACHINE_REQUIRES_SILICON (1<<5) -/// MACHINES HAVE THIS BY DEFAULT, SOMEONE SHOULD RUN THROUGH MACHINES AND REMOVE IT FROM THINGS LIKE LIGHT SWITCHES WHEN POSSIBLE!!-------------------------- /// This flag determines if a machine set_machine's the user when the user uses it, making updateUsrDialog make the user re-call interact() on it. -/// THIS FLAG IS ON ALL MACHINES BY DEFAULT, NEEDS TO BE RE-EVALUATED LATER!! +/// This is exclusively used for non-TGUI UIs, and its instances should be removed when moved to TGUI. #define INTERACT_MACHINE_SET_MACHINE (1<<6) /// the user must have vision to interact (blind people need not apply) #define INTERACT_MACHINE_REQUIRES_SIGHT (1<<7) diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 5bf9fd6d8073ac..f164c78d422d57 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -194,8 +194,6 @@ //Allowed equipment lists for security vests. GLOBAL_LIST_INIT(detective_vest_allowed, list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/detective_scanner, /obj/item/flashlight, /obj/item/gun/ballistic, @@ -216,8 +214,6 @@ GLOBAL_LIST_INIT(detective_vest_allowed, list( )) GLOBAL_LIST_INIT(security_vest_allowed, list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/flashlight, /obj/item/gun/ballistic, /obj/item/gun/energy, @@ -231,12 +227,11 @@ GLOBAL_LIST_INIT(security_vest_allowed, list( /obj/item/storage/belt/holster/nukie, /obj/item/storage/belt/holster/energy, /obj/item/gun/ballistic/shotgun/automatic/combat/compact, + /obj/item/pen/red/security, /obj/item/gun/microfusion, //SKYRAT EDIT ADDITION )) GLOBAL_LIST_INIT(security_wintercoat_allowed, list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/gun/ballistic, /obj/item/gun/energy, /obj/item/melee/baton, diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 7f408a6805ed64..e9963ca1f6a291 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -73,6 +73,8 @@ GLOBAL_LIST_INIT(turfs_openspace, typecacheof(list( #define iscliffturf(A) (istype(A, /turf/open/cliff)) +#define iswaterturf(A) (istype(A, /turf/open/water)) + GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( /turf/closed/mineral, /turf/open/misc/asteroid, @@ -145,10 +147,14 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( // basic mobs #define isbasicmob(A) (istype(A, /mob/living/basic)) +#define isconstruct(A) (istype(A, /mob/living/basic/construct)) + #define iscow(A) (istype(A, /mob/living/basic/cow)) #define isgorilla(A) (istype(A, /mob/living/basic/gorilla)) +#define isshade(A) (istype(A, /mob/living/basic/shade)) + #define is_simian(A) (isgorilla(A) || ismonkey(A)) /// returns whether or not the atom is either a basic mob OR simple animal @@ -159,9 +165,6 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define ismining(A) (istype(A, /mob/living/simple_animal/hostile/asteroid) || istype(A, /mob/living/basic/mining)) -/// constructs, which are both simple and basic for now -#define isconstruct(A) (istype(A, /mob/living/simple_animal/hostile/construct) || istype(A, /mob/living/basic/construct)) - //Simple animals #define isanimal(A) (istype(A, /mob/living/simple_animal)) @@ -169,8 +172,6 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define isbot(A) (istype(A, /mob/living/simple_animal/bot)) -#define isshade(A) (istype(A, /mob/living/simple_animal/shade)) - #define ismouse(A) (istype(A, /mob/living/basic/mouse)) #define isslime(A) (istype(A, /mob/living/simple_animal/slime)) @@ -187,7 +188,7 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define isregalrat(A) (istype(A, /mob/living/basic/regal_rat)) -#define isguardian(A) (istype(A, /mob/living/simple_animal/hostile/guardian)) +#define isguardian(A) (istype(A, /mob/living/basic/guardian)) #define ismegafauna(A) (istype(A, /mob/living/simple_animal/hostile/megafauna)) diff --git a/code/__DEFINES/mecha.dm b/code/__DEFINES/mecha.dm index db65b0b6ee8d3c..5a37f60aba6fb5 100644 --- a/code/__DEFINES/mecha.dm +++ b/code/__DEFINES/mecha.dm @@ -46,6 +46,7 @@ #define MECHA_SNOWFLAKE_ID_AIR_TANK "air_tank_snowflake" #define MECHA_SNOWFLAKE_ID_WEAPON_BALLISTIC "ballistic_weapon_snowflake" #define MECHA_SNOWFLAKE_ID_GENERATOR "generator_snowflake" +#define MECHA_SNOWFLAKE_ID_CLAW "lawclaw_snowflake" #define MECHA_AMMO_INCENDIARY "Incendiary bullet" #define MECHA_AMMO_BUCKSHOT "Buckshot shell" diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 2912da06a9cfce..14f1deff7f346a 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -151,6 +151,7 @@ #define BODYPART_ID_DIGITIGRADE "digitigrade" #define BODYPART_ID_LARVA "larva" #define BODYPART_ID_PSYKER "psyker" +#define BODYPART_ID_MEAT "meat" //See: datum/species/var/digitigrade_customization ///The species does not have digitigrade legs in generation. diff --git a/code/__DEFINES/observers.dm b/code/__DEFINES/observers.dm new file mode 100644 index 00000000000000..0bacf223d8c026 --- /dev/null +++ b/code/__DEFINES/observers.dm @@ -0,0 +1,12 @@ +// Various flags for notify_ghosts ghost popups. +/// Determines if the notification will not run if called during mapload. +#define GHOST_NOTIFY_IGNORE_MAPLOAD (1<<0) +/// Determines if the notification will flash the Byond window. +#define GHOST_NOTIFY_FLASH_WINDOW (1<<1) +/// Determines if the notification will notify suiciders. +#define GHOST_NOTIFY_NOTIFY_SUICIDERS (1<<2) + +/// The default set of flags to be passed into a notify_ghosts call. +#define NOTIFY_CATEGORY_DEFAULT (GHOST_NOTIFY_FLASH_WINDOW | GHOST_NOTIFY_IGNORE_MAPLOAD | GHOST_NOTIFY_NOTIFY_SUICIDERS) +/// The default set of flags, without the flash_window flag. +#define NOTIFY_CATEGORY_NOFLASH (NOTIFY_CATEGORY_DEFAULT & ~GHOST_NOTIFY_FLASH_WINDOW) diff --git a/code/__DEFINES/projectiles.dm b/code/__DEFINES/projectiles.dm index a82ac8422c5aef..58f25ac39f1126 100644 --- a/code/__DEFINES/projectiles.dm +++ b/code/__DEFINES/projectiles.dm @@ -52,6 +52,14 @@ #define CALIBER_ARROW "arrow" /// The caliber used by the harpoon gun. #define CALIBER_HARPOON "harpoon" +/// The caliber used by the rebar crossbow. +#define CALIBER_REBAR "sharpened iron rod" +/// The caliber used by the rebar crossbow when forced to hold 2 rods. +#define CALIBER_REBAR_FORCED "sharpened iron rod" +/// The caliber used by the syndicate rebar crossbow. +#define CALIBER_REBAR_SYNDIE "jagged iron rod" +/// The caliber used by the syndicate rebar crossbow. +#define CALIBER_REBAR_SYNDIE_NORMAL "sharpened iron rod" /// The caliber used by the meat hook. #define CALIBER_HOOK "hook" /// The caliber used by the changeling tentacle mutation. diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index 56b9c1cea2ca1b..cb2747d4f4b39a 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -58,8 +58,10 @@ #define ALLERGIC_REMOVAL_SKIP "Allergy" //Used in holder.dm/equlibrium.dm to set values and volume limits -///the minimum volume of reagents than can be operated on. +///The minimum volume of reagents than can be operated on. #define CHEMICAL_QUANTISATION_LEVEL 0.0001 +///Sanity check limit to clamp chems to sane amounts and prevent rounding errors during transfer. +#define CHEMICAL_VOLUME_ROUNDING 0.01 ///Default pH for reagents datum #define CHEMICAL_NORMAL_PH 7.000 ///Minimum pH attainable by a solution diff --git a/code/__DEFINES/research.dm b/code/__DEFINES/research.dm index 52ee2c87f4ed36..c1427fcb67a060 100644 --- a/code/__DEFINES/research.dm +++ b/code/__DEFINES/research.dm @@ -55,7 +55,6 @@ #define CELL_LINE_TABLE_WALKING_MUSHROOM "cell_line_walking_mushroom_table" #define CELL_LINE_TABLE_QUEEN_BEE "cell_line_bee_queen_table" #define CELL_LINE_TABLE_BUTTERFLY "cell_line_butterfly_table" -#define CELL_LINE_TABLE_LEAPER "cell_line_leaper_table" #define CELL_LINE_TABLE_MEGA_ARACHNID "cell_line_table_mega_arachnid" //! All cell virus types diff --git a/code/__DEFINES/research/anomalies.dm b/code/__DEFINES/research/anomalies.dm index 12a114439c7d90..9ab97ae5a8df88 100644 --- a/code/__DEFINES/research/anomalies.dm +++ b/code/__DEFINES/research/anomalies.dm @@ -44,6 +44,9 @@ GLOBAL_LIST_INIT(bioscrambler_organs_blacklist, typecacheof(list ( /obj/item/organ/internal/monster_core, /obj/item/organ/internal/vocal_cords/colossus, /obj/item/organ/internal/zombie_infection, + /obj/item/organ/internal/empowered_borer_egg, // SKYRAT EDIT ADDITION + /obj/item/organ/internal/eyes/robotic, // SKYRAT EDIT ADDITION + /obj/item/organ/internal/eyes/night_vision/cyber, // SKYRAT EDIT ADDITION ))) /// List of body parts we can apply to people diff --git a/code/__DEFINES/research/research_categories.dm b/code/__DEFINES/research/research_categories.dm index e8d426fcfc5a7c..9ebdb44c8a58c5 100644 --- a/code/__DEFINES/research/research_categories.dm +++ b/code/__DEFINES/research/research_categories.dm @@ -126,6 +126,7 @@ #define RND_SUBCATEGORY_EXOSUIT_BOARDS_SAVANNAH_IVANOV "/Savannah-Ivanov" #define RND_CATEGORY_MECHFAB_RIPLEY "/Ripley" +#define RND_CATEGORY_MECHFAB_PADDY "/Paddy" #define RND_CATEGORY_MECHFAB_ODYSSEUS "/Odysseus" #define RND_CATEGORY_MECHFAB_GYGAX "/Gygax" #define RND_CATEGORY_MECHFAB_DURAND "/Durand" diff --git a/code/__DEFINES/sight.dm b/code/__DEFINES/sight.dm index ae5f4e48352c25..645e009413593c 100644 --- a/code/__DEFINES/sight.dm +++ b/code/__DEFINES/sight.dm @@ -64,7 +64,8 @@ // INVISIBILITY PRIORITIES #define INVISIBILITY_PRIORITY_ADMIN 100 -#define INVISIBILITY_PRIORITY_BASIC_ANTI_INVISIBILITY 1 +#define INVISIBILITY_PRIORITY_TURRET_COVER 20 +#define INVISIBILITY_PRIORITY_BASIC_ANTI_INVISIBILITY 10 #define INVISIBILITY_PRIORITY_NONE 0 //------------------------ diff --git a/code/__DEFINES/span.dm b/code/__DEFINES/span.dm index 361c4d41b81d38..ab8ff969e307fc 100644 --- a/code/__DEFINES/span.dm +++ b/code/__DEFINES/span.dm @@ -23,6 +23,7 @@ #define span_bold(str) ("" + str + "") #define span_boldannounce(str) ("" + str + "") #define span_bolddanger(str) ("" + str + "") +#define span_bolditalic(str) ("" + str + "") #define span_boldnicegreen(str) ("" + str + "") #define span_boldnotice(str) ("" + str + "") #define span_boldwarning(str) ("" + str + "") @@ -115,6 +116,7 @@ #define span_smallnoticeital(str) ("" + str + "") #define span_spiderbroodmother(str) ("" + str + "") #define span_spiderscout(str) ("" + str + "") +#define span_spiderbreacher(str) ("" + str + "") #define span_suicide(str) ("" + str + "") #define span_suppradio(str) ("" + str + "") #define span_syndradio(str) ("" + str + "") diff --git a/code/__DEFINES/stack_trace.dm b/code/__DEFINES/stack_trace.dm index 969eaecc707038..4911b4a0d571e9 100644 --- a/code/__DEFINES/stack_trace.dm +++ b/code/__DEFINES/stack_trace.dm @@ -1,2 +1,4 @@ /// gives us the stack trace from CRASH() without ending the current proc. #define stack_trace(message) _stack_trace(message, __FILE__, __LINE__) + +#define WORKAROUND_IDENTIFIER "%//%" diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 2f452345ef9eab..52890a428e64c6 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -171,6 +171,7 @@ #define INIT_ORDER_LANGUAGE 25 #define INIT_ORDER_MACHINES 20 #define INIT_ORDER_SKILLS 15 +#define INIT_ORDER_QUEUELINKS 10 #define INIT_ORDER_TIMER 1 #define INIT_ORDER_DEFAULT 0 #define INIT_ORDER_AIR -1 diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm index 6187a67825a471..0cc106ec9cf2fc 100644 --- a/code/__DEFINES/tgs.dm +++ b/code/__DEFINES/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "6.5.3" +#define TGS_DMAPI_VERSION "6.6.2" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -129,6 +129,13 @@ /// DreamDaemon Ultrasafe security level. #define TGS_SECURITY_ULTRASAFE 2 +/// DreamDaemon public visibility level. +#define TGS_VISIBILITY_PUBLIC 0 +/// DreamDaemon private visibility level. +#define TGS_VISIBILITY_PRIVATE 1 +/// DreamDaemon invisible visibility level. +#define TGS_VISIBILITY_INVISIBLE 2 + //REQUIRED HOOKS /** @@ -458,6 +465,10 @@ /world/proc/TgsSecurityLevel() return +/// Returns the current BYOND visibility level as a TGS_VISIBILITY_ define if TGS is present, null otherwise. Requires TGS to be using interop API version 5 or higher otherwise the string "___unimplemented" wil be returned. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! +/world/proc/TgsVisibility() + return + /// Returns a list of active [/datum/tgs_revision_information/test_merge]s if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsTestMerges() return diff --git a/code/__DEFINES/trader.dm b/code/__DEFINES/trader.dm new file mode 100644 index 00000000000000..aae6da26499838 --- /dev/null +++ b/code/__DEFINES/trader.dm @@ -0,0 +1,16 @@ +#define ITEM_REJECTED_PHRASE "ITEM_REJECTED_PHRASE" +#define ITEM_SELLING_CANCELED_PHRASE "ITEM_SELLING_CANCELED_PHRASE" +#define ITEM_SELLING_ACCEPTED_PHRASE "ITEM_SELLING_ACCEPTED_PHRASE" +#define INTERESTED_PHRASE "INTERESTED_PHRASE" +#define BUY_PHRASE "BUY_PHRASE" +#define NO_CASH_PHRASE "NO_CASH_PHRASE" +#define NO_STOCK_PHRASE "NO_STOCK_PHRASE" +#define NOT_WILLING_TO_BUY_PHRASE "NOT_WILLING_TO_BUY_PHRASE" +#define ITEM_IS_WORTHLESS_PHRASE "ITEM_IS_WORTHLESS_PHRASE" +#define TRADER_HAS_ENOUGH_ITEM_PHRASE "TRADER_HAS_ENOUGH_ITEM_PHRASE" +#define TRADER_LORE_PHRASE "TRADER_LORE_PHRASE" +#define TRADER_BATTLE_START_PHRASE "TRADER_AGGRO_PHRASE" +#define TRADER_BATTLE_END_PHRASE "TRADER_DEAGGRO_PHRASE" +#define TRADER_NOT_BUYING_ANYTHING "TRADER_NOT_BUYING_ANYTHING" +#define TRADER_NOT_SELLING_ANYTHING "TRADER_NOT_SELLING_ANYTHING" +#define TRADER_SHOP_OPENING_PHRASE "TRADER_SHOP_OPENING_PHRASE" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 5a15c562b453a3..413c116d21cf74 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -496,8 +496,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_BLOODSHOT_EYES "bloodshot_eyes" /// This mob should never close UI even if it doesn't have a client #define TRAIT_PRESERVE_UI_WITHOUT_CLIENT "preserve_ui_without_client" -/// Lets the mob use flight potions -#define TRAIT_CAN_USE_FLIGHT_POTION "can_use_flight_potion" /// This mob overrides certian SSlag_switch measures with this special trait #define TRAIT_BYPASS_MEASURES "bypass_lagswitch_measures" /// Someone can safely be attacked with honorbound with ONLY a combat mode check, the trait is assuring holding a weapon and hitting won't hurt them.. @@ -665,7 +663,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_TENTACLE_IMMUNE "tentacle_immune" /// Currently under the effect of overwatch #define TRAIT_OVERWATCHED "watcher_overwatched" -/// Cannot be targetted by watcher overwatch +/// Cannot be targeted by watcher overwatch #define TRAIT_OVERWATCH_IMMUNE "overwatch_immune" //non-mob traits @@ -869,6 +867,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait applied when an integrated circuit/module becomes undupable #define TRAIT_CIRCUIT_UNDUPABLE "circuit_undupable" +/// Trait applied when an integrated circuit opens a UI on a player (see list pick component) +#define TRAIT_CIRCUIT_UI_OPEN "circuit_ui_open" + /// Hearing trait that is from the hearing component #define CIRCUIT_HEAR_TRAIT "circuit_hear" @@ -1335,9 +1336,15 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai ///Trait given by /datum/element/relay_attacker #define TRAIT_RELAYING_ATTACKER "relaying_attacker" +///Trait given to limb by /mob/living/basic/living_limb_flesh +#define TRAIT_IGNORED_BY_LIVING_FLESH "livingflesh_ignored" + /// Trait given while using /datum/action/cooldown/mob_cooldown/wing_buffet #define TRAIT_WING_BUFFET "wing_buffet" /// Trait given while tired after using /datum/action/cooldown/mob_cooldown/wing_buffet #define TRAIT_WING_BUFFET_TIRED "wing_buffet_tired" /// Trait given to a dragon who fails to defend their rifts #define TRAIT_RIFT_FAILURE "fail_dragon_loser" + +/// Trait given to mobs that we do not want to mindswap +#define TRAIT_NO_MINDSWAP "no_mindswap" diff --git a/code/__DEFINES/vehicles.dm b/code/__DEFINES/vehicles.dm index 9aac19be3c1087..d210a07dde4dd5 100644 --- a/code/__DEFINES/vehicles.dm +++ b/code/__DEFINES/vehicles.dm @@ -26,6 +26,8 @@ #define UNBUCKLE_DISABLED_RIDER (1<<3) // For fireman carries, the carrying human needs an arm #define CARRIER_NEEDS_ARM (1<<4) +// This rider must be our friend +#define JUST_FRIEND_RIDERS (1<<5) //car_traits flags ///Will this car kidnap people by ramming into them? diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 1cc9025b821646..f6cb654b1d5493 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -57,7 +57,7 @@ // VV HREF KEYS #define VV_HK_TARGET "target" -#define VV_HK_VARNAME "targetvar" //name or index of var for 1 variable targetting hrefs. +#define VV_HK_VARNAME "targetvar" //name or index of var for 1 variable targeting hrefs. // vv_do_list() keys #define VV_HK_LIST_ADD "listadd" diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm index 14a03d780ce10b..421650e3bf1e79 100644 --- a/code/__DEFINES/wiremod.dm +++ b/code/__DEFINES/wiremod.dm @@ -45,6 +45,8 @@ #define PORT_TYPE_ATOM "entity" /// Datum datatype #define PORT_TYPE_DATUM "datum" +/// User datatype +#define PORT_TYPE_USER "user" /// The maximum range between a port and an atom diff --git a/code/__DEFINES/wounds.dm b/code/__DEFINES/wounds.dm index 7aec41d7b5cb33..79c188cd4817c5 100644 --- a/code/__DEFINES/wounds.dm +++ b/code/__DEFINES/wounds.dm @@ -90,7 +90,7 @@ GLOBAL_LIST_INIT(wound_severities_chronological, list( // "Where" a specific biostate is within a given limb // Interior is hard shit, the last line, shit like bones -// Exterior is soft shit, targetted by slashes and pierces (usually), protects exterior +// Exterior is soft shit, targeted by slashes and pierces (usually), protects exterior // A limb needs both mangled interior and exterior to be dismembered, but slash/pierce must mangle exterior to attack the interior // Not having exterior/interior counts as mangled exterior/interior for the purposes of dismemberment /// The given biostate is on the "interior" of the limb - hard shit, protected by exterior diff --git a/code/__DEFINES/~skyrat_defines/barsigns.dm b/code/__DEFINES/~skyrat_defines/barsigns.dm new file mode 100644 index 00000000000000..8a6fe2652bb677 --- /dev/null +++ b/code/__DEFINES/~skyrat_defines/barsigns.dm @@ -0,0 +1,2 @@ +#define SKYRAT_BARSIGN_FILE 'modular_skyrat/modules/barsigns/icons/barsigns.dmi' +#define SKYRAT_LARGE_BARSIGN_FILE 'modular_skyrat/modules/barsigns/icons/barsigns96x96.dmi' diff --git a/code/__DEFINES/~skyrat_defines/colors.dm b/code/__DEFINES/~skyrat_defines/colors.dm index 9c5e17b06a5b5c..4f00b0651b1b1f 100644 --- a/code/__DEFINES/~skyrat_defines/colors.dm +++ b/code/__DEFINES/~skyrat_defines/colors.dm @@ -1,3 +1,5 @@ #define LIGHT_COLOR_CLOCKWORK "#BE8700" #define COLOR_SOLFED_GOLD "#FFD900" #define LIGHT_COLOR_YELLOW "#E1E17D" +#define COLOR_NRI_POLICE_BLUE "#1f3347" +#define COLOR_NRI_POLICE_SILVER "#c0c0c0" diff --git a/code/__DEFINES/~tannhauser_defines/barsigns.dm b/code/__DEFINES/~tannhauser_defines/barsigns.dm new file mode 100644 index 00000000000000..6df6490f950bd6 --- /dev/null +++ b/code/__DEFINES/~tannhauser_defines/barsigns.dm @@ -0,0 +1 @@ +#define TAN_BAR_SIGNS 'modular_tannhauser/_skyrat_override/modules/barsigns/icons/tanbars.dmi' diff --git a/code/__DEFINES/~tannhauser_defines/jobs.dm b/code/__DEFINES/~tannhauser_defines/jobs.dm deleted file mode 100644 index 05ec0d1af469c9..00000000000000 --- a/code/__DEFINES/~tannhauser_defines/jobs.dm +++ /dev/null @@ -1 +0,0 @@ -#define FLAVOR_TEXT_CHAR_REQUIREMENT 100 diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 32e4135b96515b..4ab974dd4a8a9a 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -898,6 +898,13 @@ UNTYPED_LIST_ADD(keys, key) return keys +///Gets the total amount of everything in the associative list. +/proc/assoc_value_sum(list/input) + var/list/keys = list() + for(var/key in input) + keys += input[key] + return keys + ///compare two lists, returns TRUE if they are the same /proc/compare_list(list/l,list/d) if(!islist(l) || !islist(d)) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 616469ecabfbc0..9dbfa2e3e2bdd3 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -119,7 +119,7 @@ /obj/item/stack/sheet/sinew = GLOB.sinew_recipes, /obj/item/stack/sheet/animalhide/carp = GLOB.carp_recipes, /obj/item/stack/sheet/mineral/sandstone = GLOB.sandstone_recipes, - /obj/item/stack/sheet/mineral/clay = GLOB.clay_recipes, + /obj/item/stack/sheet/mineral/clay = GLOB.clay_recipes, // SKYRAT EDIT ADDITION /obj/item/stack/sheet/mineral/sandbags = GLOB.sandbag_recipes, /obj/item/stack/sheet/mineral/diamond = GLOB.diamond_recipes, /obj/item/stack/sheet/mineral/uranium = GLOB.uranium_recipes, diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index c2b2f1e33b23fa..4a60dd23c6020b 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -1481,3 +1481,27 @@ GLOBAL_LIST_EMPTY(transformation_animation_objects) var/icon/my_icon = icon(icon_path) GLOB.icon_dimensions[icon_path] = list("width" = my_icon.Width(), "height" = my_icon.Height()) return GLOB.icon_dimensions[icon_path] + +/// Fikou's fix for making toast alerts look nice - resets offsets, transforms to fit +/proc/get_small_overlay(atom/source) + var/mutable_appearance/alert_overlay = new(source) + alert_overlay.pixel_x = 0 + alert_overlay.pixel_y = 0 + + var/scale = 1 + var/list/icon_dimensions = get_icon_dimensions(source.icon) + var/width = icon_dimensions["width"] + var/height = icon_dimensions["height"] + + if(width > world.icon_size) + alert_overlay.pixel_x = -(world.icon_size / 2) * ((width - world.icon_size) / world.icon_size) + if(height > world.icon_size) + alert_overlay.pixel_y = -(world.icon_size / 2) * ((height - world.icon_size) / world.icon_size) + if(width > world.icon_size || height > world.icon_size) + if(width >= height) + scale = world.icon_size / width + else + scale = world.icon_size / height + alert_overlay.transform = alert_overlay.transform.Scale(scale) + + return alert_overlay diff --git a/code/__HELPERS/priority_announce.dm b/code/__HELPERS/priority_announce.dm index a7d47fb8f09225..72d6aa0597ce11 100644 --- a/code/__HELPERS/priority_announce.dm +++ b/code/__HELPERS/priority_announce.dm @@ -87,16 +87,21 @@ if(isnull(sender_override)) if(length(title) > 0) - GLOB.news_network.submit_article(title + "

" + text, "Central Command", "Station Announcements", null) + GLOB.news_network.submit_article(title + "

" + text, "[command_name()]", "Station Announcements", null) else - GLOB.news_network.submit_article(text, "Central Command Update", "Station Announcements", null) + GLOB.news_network.submit_article(text, "[command_name()] Update", "Station Announcements", null) /proc/print_command_report(text = "", title = null, announce=TRUE) if(!title) title = "Classified [command_name()] Update" if(announce) - priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", SSstation.announcer.get_rand_report_sound(), has_important_message = TRUE) + priority_announce( + text = "A report has been downloaded and printed out at all communications consoles.", + title = "Incoming Classified Message", + sound = SSstation.announcer.get_rand_report_sound(), + has_important_message = TRUE, + ) var/datum/comm_message/message = new message.title = title diff --git a/code/__HELPERS/stack_trace.dm b/code/__HELPERS/stack_trace.dm index 5c220d7a74a46e..bb2d78de110805 100644 --- a/code/__HELPERS/stack_trace.dm +++ b/code/__HELPERS/stack_trace.dm @@ -1,4 +1,4 @@ /// gives us the stack trace from CRASH() without ending the current proc. /// Do not call directly, use the [stack_trace] macro instead. /proc/_stack_trace(message, file, line) - CRASH("[message] ([file]:[line])") + CRASH("[message][WORKAROUND_IDENTIFIER][json_encode(list(file, line))][WORKAROUND_IDENTIFIER]") diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 135fb00dea10a2..1e775dd49ae40f 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -6,16 +6,11 @@ GLOBAL_LIST_EMPTY(deadmins) //all ckeys who have used the de-admin verb. GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client GLOBAL_LIST_EMPTY(stealthminID) //reference list with IDs that store ckeys, for stealthmins -GLOBAL_LIST_INIT(dangerous_turfs, typecacheof(list( - /turf/open/lava, - /turf/open/chasm, - /turf/open/space, - /turf/open/openspace))) - /// List of types of abstract mob which shouldn't usually exist in the world on its own if we're spawning random mobs GLOBAL_LIST_INIT(abstract_mob_types, list( /mob/living/basic/blob_minion, /mob/living/basic/construct, + /mob/living/basic/guardian, /mob/living/basic/heretic_summon, /mob/living/basic/mining, /mob/living/basic/pet, @@ -32,8 +27,6 @@ GLOBAL_LIST_INIT(abstract_mob_types, list( /mob/living/simple_animal/bot, /mob/living/simple_animal/hostile/asteroid/elite, /mob/living/simple_animal/hostile/asteroid, - /mob/living/simple_animal/hostile/construct, - /mob/living/simple_animal/hostile/guardian, /mob/living/simple_animal/hostile/megafauna, /mob/living/simple_animal/hostile/mimic, // Cannot exist if spawned without being passed an item reference /mob/living/simple_animal/hostile/retaliate, diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm index b2662b5e804a6f..52af61db88ac94 100644 --- a/code/_globalvars/lists/names.dm +++ b/code/_globalvars/lists/names.dm @@ -25,6 +25,9 @@ GLOBAL_LIST_INIT(megacarp_first_names, world.file2list("strings/names/megacarp1. GLOBAL_LIST_INIT(megacarp_last_names, world.file2list("strings/names/megacarp2.txt")) GLOBAL_LIST_INIT(cyberauth_names, world.file2list("strings/names/cyberauth.txt")) GLOBAL_LIST_INIT(syndicate_monkey_names, world.file2list("strings/names/syndicate_monkey.txt")) +GLOBAL_LIST_INIT(guardian_first_names, world.file2list("strings/names/guardian_descriptions.txt")) +GLOBAL_LIST_INIT(guardian_tech_surnames, world.file2list("strings/names/guardian_gamepieces.txt")) +GLOBAL_LIST_INIT(guardian_fantasy_surnames, world.file2list("strings/names/guardian_tarot.txt")) GLOBAL_LIST_INIT(verbs, world.file2list("strings/names/verbs.txt")) GLOBAL_LIST_INIT(ing_verbs, world.file2list("strings/names/ing_verbs.txt")) diff --git a/code/_globalvars/lists/reagents.dm b/code/_globalvars/lists/reagents.dm index 68d63d97934eaf..47b1008aa8aa6d 100644 --- a/code/_globalvars/lists/reagents.dm +++ b/code/_globalvars/lists/reagents.dm @@ -63,8 +63,6 @@ GLOBAL_LIST_INIT(blacklisted_metalgen_types, typecacheof(list( /turf/closed/indestructible, //indestructible turfs should be indestructible, metalgen transmutation to plasma allows them to be destroyed /turf/open/indestructible ))) -/// Names of human readable reagents used by plumbing UI. -GLOBAL_LIST_INIT(chemical_name_list, init_chemical_name_list()) /// Map of reagent names to its datum path GLOBAL_LIST_INIT(name2reagent, build_name2reagentlist()) @@ -81,16 +79,6 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagentlist()) return reagent_list -/// Creates an list which is indexed by reagent name . used by plumbing reaction chamber and chemical filter UI -/proc/init_chemical_name_list() - var/list/name_list = list() - - for(var/X in GLOB.chemical_reagents_list) - var/datum/reagent/Reagent = GLOB.chemical_reagents_list[X] - name_list += Reagent.name - - return sort_list(name_list) - /** * Chemical Reactions - Initialises all /datum/chemical_reaction into a list * It is filtered into multiple lists within a list. @@ -196,7 +184,19 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagentlist()) /// Builds map of reagent name to its datum path /proc/build_name2reagentlist() . = list() - for (var/datum/reagent/R as anything in subtypesof(/datum/reagent)) - var/name = initial(R.name) + + //build map with keys stored seperatly + var/list/name_to_reagent = list() + var/list/only_names = list() + for (var/datum/reagent/reagent as anything in GLOB.chemical_reagents_list) + var/name = initial(reagent.name) if (length(name)) - .[ckey(name)] = R + name_to_reagent[name] = reagent + only_names += name + + //sort keys + only_names = sort_list(only_names) + + //build map with sorted keys + for(var/name as anything in only_names) + .[name] = name_to_reagent[name] diff --git a/code/_globalvars/lists/xenobiology.dm b/code/_globalvars/lists/xenobiology.dm index 1e247a6279d39a..f641e9d5eccdef 100644 --- a/code/_globalvars/lists/xenobiology.dm +++ b/code/_globalvars/lists/xenobiology.dm @@ -73,11 +73,9 @@ GLOBAL_LIST_INIT_TYPED(cell_line_tables, /list, list( CELL_LINE_TABLE_WALKING_MUSHROOM = list(/datum/micro_organism/cell_line/walking_mushroom = 1), CELL_LINE_TABLE_QUEEN_BEE = list(/datum/micro_organism/cell_line/queen_bee = 1), CELL_LINE_TABLE_BUTTERFLY = list(/datum/micro_organism/cell_line/butterfly = 1), - CELL_LINE_TABLE_LEAPER = list(/datum/micro_organism/cell_line/leaper = 1), CELL_LINE_TABLE_MEGA_ARACHNID = list(/datum/micro_organism/cell_line/mega_arachnid = 1), CELL_LINE_TABLE_ALGAE = list( /datum/micro_organism/cell_line/frog = 2, - /datum/micro_organism/cell_line/leaper = 2, /datum/micro_organism/cell_line/mega_arachnid = 1, /datum/micro_organism/cell_line/queen_bee = 1, /datum/micro_organism/cell_line/butterfly = 1, diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm index f8ea532914bcc3..5bb8b4bf31498d 100644 --- a/code/_globalvars/phobias.dm +++ b/code/_globalvars/phobias.dm @@ -57,7 +57,7 @@ GLOBAL_LIST_INIT(phobia_mobs, list( /mob/living/carbon/alien, /mob/living/simple_animal/slime, )), - "anime" = typecacheof(list(/mob/living/simple_animal/hostile/guardian)), + "anime" = typecacheof(list(/mob/living/basic/guardian)), "birds" = typecacheof(list( /mob/living/basic/chick, /mob/living/basic/chicken, @@ -96,14 +96,13 @@ GLOBAL_LIST_INIT(phobia_mobs, list( /mob/living/basic/faithless, /mob/living/basic/ghost, /mob/living/basic/heretic_summon, - /mob/living/basic/skeleton, /mob/living/basic/revenant, + /mob/living/basic/shade, + /mob/living/basic/skeleton, + /mob/living/basic/wizard, /mob/living/simple_animal/bot/mulebot/paranormal, - /mob/living/simple_animal/hostile/construct, /mob/living/simple_animal/hostile/dark_wizard, - /mob/living/simple_animal/hostile/wizard, /mob/living/simple_animal/hostile/zombie, - /mob/living/simple_animal/shade, )), )) @@ -368,7 +367,7 @@ GLOBAL_LIST_INIT(phobia_objs, list( /obj/effect/forcefield/wizard/heretic, /obj/effect/heretic_influence, /obj/effect/heretic_rune, - /obj/effect/knock_portal, + /obj/effect/lock_portal, /obj/effect/visible_heretic_influence, /obj/item/ammo_box/strilka310/lionhunter, /obj/item/ammo_casing/strilka310/lionhunter, @@ -380,7 +379,7 @@ GLOBAL_LIST_INIT(phobia_objs, list( /obj/item/codex_cicatrix, /obj/item/coin/eldritch, /obj/item/gun/ballistic/rifle/lionhunter, - /obj/item/heretic_lintel, + /obj/item/heretic_labyrinth_handbook, /obj/item/melee/rune_carver, /obj/item/melee/sickly_blade, /obj/item/melee/touch_attack/mansus_fist, @@ -389,7 +388,7 @@ GLOBAL_LIST_INIT(phobia_objs, list( /obj/item/toy/reality_pierce, /obj/projectile/curse_hand, /obj/structure/destructible/eldritch_crucible, - /obj/structure/knock_tear, + /obj/structure/lock_tear, )), "insects" = typecacheof(list( /obj/item/clothing/mask/animal/small/bee, diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 8fd711279a5e24..4e83823b4d9e55 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -85,6 +85,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BLOOD_DEFICIENCY" = TRAIT_BLOOD_DEFICIENCY, "TRAIT_JOLLY" = TRAIT_JOLLY, "TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE, + "TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM, "TRAIT_NOCRITDAMAGE" = TRAIT_NOCRITDAMAGE, "TRAIT_NO_SLIP_WATER" = TRAIT_NO_SLIP_WATER, "TRAIT_NO_SLIP_ICE" = TRAIT_NO_SLIP_ICE, diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 4275c78dbe43eb..3e6790aee6b7d1 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -502,7 +502,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." alerttooltipstyle = "cult" var/static/image/narnar var/angle = 0 - var/mob/living/simple_animal/hostile/construct/Cviewer = null + var/mob/living/basic/construct/Cviewer /atom/movable/screen/alert/bloodsense/Initialize(mapload, datum/hud/hud_owner) . = ..() @@ -607,19 +607,13 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." //GUARDIANS -/atom/movable/screen/alert/cancharge - name = "Charge Ready" - desc = "You are ready to charge at a location!" - icon_state = "guardian_charge" - alerttooltipstyle = "parasite" - /atom/movable/screen/alert/canstealth name = "Stealth Ready" desc = "You are ready to enter stealth!" icon_state = "guardian_canstealth" alerttooltipstyle = "parasite" -/atom/movable/screen/alert/instealth +/atom/movable/screen/alert/status_effect/instealth name = "In Stealth" desc = "You are in stealth and your next attack will do bonus damage!" icon_state = "guardian_instealth" diff --git a/code/_onclick/hud/guardian.dm b/code/_onclick/hud/guardian.dm index f9963c1fa3a915..ba1d8f4565e64f 100644 --- a/code/_onclick/hud/guardian.dm +++ b/code/_onclick/hud/guardian.dm @@ -1,7 +1,7 @@ /datum/hud/guardian ui_style = 'icons/hud/guardian.dmi' -/datum/hud/guardian/New(mob/living/simple_animal/hostile/guardian/owner) +/datum/hud/guardian/New(mob/living/basic/guardian/owner) ..() var/atom/movable/screen/using @@ -34,10 +34,10 @@ using.screen_loc = ui_back static_inventory += using -/datum/hud/dextrous/guardian/New(mob/living/simple_animal/hostile/guardian/owner) //for a dextrous guardian +/datum/hud/dextrous/guardian/New(mob/living/basic/guardian/owner) //for a dextrous guardian ..() var/atom/movable/screen/using - if(istype(owner, /mob/living/simple_animal/hostile/guardian/dextrous)) + if(istype(owner, /mob/living/basic/guardian/dextrous)) var/atom/movable/screen/inventory/inv_box inv_box = new /atom/movable/screen/inventory(null, src) @@ -86,8 +86,8 @@ /datum/hud/dextrous/guardian/persistent_inventory_update() if(!mymob) return - if(istype(mymob, /mob/living/simple_animal/hostile/guardian/dextrous)) - var/mob/living/simple_animal/hostile/guardian/dextrous/dex_guardian = mymob + if(istype(mymob, /mob/living/basic/guardian/dextrous)) + var/mob/living/basic/guardian/dextrous/dex_guardian = mymob if(hud_shown) if(dex_guardian.internal_storage) @@ -109,7 +109,7 @@ /atom/movable/screen/guardian/manifest/Click() if(isguardian(usr)) - var/mob/living/simple_animal/hostile/guardian/user = usr + var/mob/living/basic/guardian/user = usr user.manifest() @@ -120,7 +120,7 @@ /atom/movable/screen/guardian/recall/Click() if(isguardian(usr)) - var/mob/living/simple_animal/hostile/guardian/user = usr + var/mob/living/basic/guardian/user = usr user.recall() /atom/movable/screen/guardian/toggle_mode @@ -130,7 +130,7 @@ /atom/movable/screen/guardian/toggle_mode/Click() if(isguardian(usr)) - var/mob/living/simple_animal/hostile/guardian/user = usr + var/mob/living/basic/guardian/user = usr user.toggle_modes() /atom/movable/screen/guardian/toggle_mode/inactive @@ -153,7 +153,7 @@ /atom/movable/screen/guardian/communicate/Click() if(isguardian(usr)) - var/mob/living/simple_animal/hostile/guardian/user = usr + var/mob/living/basic/guardian/user = usr user.communicate() @@ -164,5 +164,5 @@ /atom/movable/screen/guardian/toggle_light/Click() if(isguardian(usr)) - var/mob/living/simple_animal/hostile/guardian/user = usr + var/mob/living/basic/guardian/user = usr user.toggle_light() diff --git a/code/_onclick/hud/ooze.dm b/code/_onclick/hud/ooze.dm index 1b466f7ff97969..0962b58126af9f 100644 --- a/code/_onclick/hud/ooze.dm +++ b/code/_onclick/hud/ooze.dm @@ -1,4 +1,4 @@ -///Hud type with targetting dol and a nutrition bar +///Hud type with targeting dol and a nutrition bar /datum/hud/ooze/New(mob/living/owner) . = ..() diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index f54b81ca669876..ba1ccbd5d47b76 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -347,9 +347,13 @@ GLOBAL_LIST_EMPTY(radial_menus) Choices should be a list where list keys are movables or text used for element names and return value and list values are movables/icons/images used for element icons */ -/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, radial_slice_icon = "radial_slice") +/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, radial_slice_icon = "radial_slice", autopick_single_option = TRUE) if(!user || !anchor || !length(choices)) return + + if(length(choices)==1 && autopick_single_option) + return choices[1] + if(!uniqueid) uniqueid = "defmenu_[REF(user)]_[REF(anchor)]" diff --git a/code/_onclick/hud/rendering/plane_master.dm b/code/_onclick/hud/rendering/plane_master.dm deleted file mode 100644 index 4ae1c573ad4af2..00000000000000 --- a/code/_onclick/hud/rendering/plane_master.dm +++ /dev/null @@ -1,684 +0,0 @@ -// I hate this place -INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) - -/atom/movable/screen/plane_master - screen_loc = "CENTER" - icon_state = "blank" - appearance_flags = PLANE_MASTER - blend_mode = BLEND_OVERLAY - plane = LOWEST_EVER_PLANE - /// Will be sent to the debug ui as a description for each plane - /// Also useful as a place to explain to coders how/why your plane works, and what it's meant to do - /// Plaintext and basic html are fine to use here. - /// I'll bonk you if I find you putting "lmao stuff" in here, make this useful. - var/documentation = "" - /// Our real alpha value, so alpha can persist through being hidden/shown - var/true_alpha = 255 - /// Tracks if we're using our true alpha, or being manipulated in some other way - var/alpha_enabled = TRUE - - /// The plane master group we're a member of, our "home" - var/datum/plane_master_group/home - - /// If our plane master allows for offsetting - /// Mostly used for planes that really don't need to be duplicated, like the hud planes - var/allows_offsetting = TRUE - /// Our offset from our "true" plane, see below - var/offset - /// When rendering multiz, lower levels get their own set of plane masters - /// Real plane here represents the "true" plane value of something, ignoring the offset required to handle lower levels - var/real_plane - - //--rendering relay vars-- - /// list of planes we will relay this plane's render to - var/list/render_relay_planes = list(RENDER_PLANE_GAME) - /// blend mode to apply to the render relay in case you dont want to use the plane_masters blend_mode - var/blend_mode_override - /// list of current relays this plane is utilizing to render - var/list/atom/movable/render_plane_relay/relays = list() - /// if render relays have already be generated - var/relays_generated = FALSE - - /// If this plane master should be hidden from the player at roundstart - /// We do this so PMs can opt into being temporary, to reduce load on clients - var/start_hidden = FALSE - /// If this plane master is being forced to hide. - /// Hidden PMs will dump ANYTHING relayed or drawn onto them. Be careful with this - /// Remember: a hidden plane master will dump anything drawn directly to it onto the output render. It does NOT hide its contents - /// Use alpha for that - var/force_hidden = FALSE - - /// If this plane should be scaled by multiz - /// Planes with this set should NEVER be relay'd into each other, as that will cause visual fuck - var/multiz_scaled = TRUE - - /// Bitfield that describes how this plane master will render if its z layer is being "optimized" - /// If a plane master is NOT critical, it will be completely dropped if we start to render outside a client's multiz boundary prefs - /// Of note: most of the time we will relay renders to non critical planes in this stage. so the plane master will end up drawing roughly "in order" with its friends - /// This is NOT done for parallax and other problem children, because the rules of BLEND_MULTIPLY appear to not behave as expected :( - /// This will also just make debugging harder, because we do fragile things in order to ensure things operate as epected. I'm sorry - /// Compile time - /// See [code\__DEFINES\layers.dm] for our bitflags - var/critical = NONE - - /// If this plane master is outside of our visual bounds right now - var/is_outside_bounds = FALSE - -/atom/movable/screen/plane_master/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset = 0) - . = ..() - src.offset = offset - true_alpha = alpha - real_plane = plane - - if(!set_home(home)) - return INITIALIZE_HINT_QDEL - update_offset() - if(!documentation && !(istype(src, /atom/movable/screen/plane_master) || istype(src, /atom/movable/screen/plane_master/rendering_plate))) - stack_trace("Plane master created without a description. Document how your thing works so people will know in future, and we can display it in the debug menu") - if(start_hidden) - hide_plane(home.our_hud?.mymob) - generate_render_relays() - -/atom/movable/screen/plane_master/Destroy() - if(home) - // NOTE! We do not clear ourselves from client screens - // We relay on whoever qdel'd us to reset our hud, and properly purge us - home.plane_masters -= "[plane]" - home = null - . = ..() - QDEL_LIST(relays) - -/// Sets the plane group that owns us, it also determines what screen we render to -/// Returns FALSE if the set_home fails, TRUE otherwise -/atom/movable/screen/plane_master/proc/set_home(datum/plane_master_group/home) - if(!istype(home, /datum/plane_master_group)) - return FALSE - src.home = home - if(home.map) - screen_loc = "[home.map]:[screen_loc]" - assigned_map = home.map - return TRUE - -/// Updates our "offset", basically what layer of multiz we're meant to render -/// Top is 0, goes up as you go down -/// It's taken into account by render targets and relays, so we gotta make sure they're on the same page -/atom/movable/screen/plane_master/proc/update_offset() - name = "[initial(name)] #[offset]" - SET_PLANE_W_SCALAR(src, real_plane, offset) - for(var/i in 1 to length(render_relay_planes)) - render_relay_planes[i] = GET_NEW_PLANE(render_relay_planes[i], offset) - if(initial(render_target)) - render_target = OFFSET_RENDER_TARGET(initial(render_target), offset) - -/atom/movable/screen/plane_master/proc/set_alpha(new_alpha) - true_alpha = new_alpha - if(!alpha_enabled) - return - alpha = new_alpha - -/atom/movable/screen/plane_master/proc/disable_alpha() - alpha_enabled = FALSE - alpha = 0 - -/atom/movable/screen/plane_master/proc/enable_alpha() - alpha_enabled = TRUE - alpha = true_alpha - -/// Shows a plane master to the passed in mob -/// Override this to apply unique effects and such -/// Returns TRUE if the call is allowed, FALSE otherwise -/atom/movable/screen/plane_master/proc/show_to(mob/mymob) - SHOULD_CALL_PARENT(TRUE) - if(force_hidden) - return FALSE - - var/client/our_client = mymob?.canon_client - // Alright, let's get this out of the way - // Mobs can move z levels without their client. If this happens, we need to ensure critical display settings are respected - // This is done here. Mild to severe pain but it's nessesary - if(check_outside_bounds()) - if(!(critical & PLANE_CRITICAL_DISPLAY)) - return FALSE - if(!our_client) - return TRUE - our_client.screen += src - - if(!(critical & PLANE_CRITICAL_NO_RELAY)) - our_client.screen += relays - return TRUE - return TRUE - - if(!our_client) - return TRUE - - our_client.screen += src - our_client.screen += relays - return TRUE - -/// Hook to allow planes to work around is_outside_bounds -/// Return false to allow a show, true otherwise -/atom/movable/screen/plane_master/proc/check_outside_bounds() - return is_outside_bounds - -/// Hides a plane master from the passeed in mob -/// Do your effect cleanup here -/atom/movable/screen/plane_master/proc/hide_from(mob/oldmob) - SHOULD_CALL_PARENT(TRUE) - var/client/their_client = oldmob?.client - if(!their_client) - return - their_client.screen -= src - their_client.screen -= relays - - -/// Forces this plane master to hide, until unhide_plane is called -/// This allows us to disable unused PMs without breaking anything else -/atom/movable/screen/plane_master/proc/hide_plane(mob/cast_away) - force_hidden = TRUE - hide_from(cast_away) - -/// Disables any forced hiding, allows the plane master to be used as normal -/atom/movable/screen/plane_master/proc/unhide_plane(mob/enfold) - force_hidden = FALSE - show_to(enfold) - -/// Mirrors our force hidden state to the hidden state of the plane that came before, assuming it's valid -/// This allows us to mirror any hidden sets from before we were created, no matter how low that chance is -/atom/movable/screen/plane_master/proc/mirror_parent_hidden() - var/mob/our_mob = home?.our_hud?.mymob - var/atom/movable/screen/plane_master/true_plane = our_mob?.hud_used?.get_plane_master(plane) - if(true_plane == src || !true_plane) - return - - if(true_plane.force_hidden == force_hidden) - return - - // If one of us already exists and it's not hidden, unhide ourselves - if(true_plane.force_hidden) - hide_plane(our_mob) - else - unhide_plane(our_mob) - -/atom/movable/screen/plane_master/proc/outside_bounds(mob/relevant) - if(force_hidden || is_outside_bounds) - return - is_outside_bounds = TRUE - // If we're of critical importance, AND we're below the rendering layer - if(critical & PLANE_CRITICAL_DISPLAY) - // We here assume that your render target starts with * - if(critical & PLANE_CRITICAL_CUT_RENDER && render_target) - render_target = copytext_char(render_target, 2) - if(!(critical & PLANE_CRITICAL_NO_RELAY)) - return - var/client/our_client = relevant.client - if(our_client) - for(var/atom/movable/render_plane_relay/relay as anything in relays) - our_client.screen -= relay - - return - hide_from(relevant) - -/atom/movable/screen/plane_master/proc/inside_bounds(mob/relevant) - is_outside_bounds = FALSE - if(critical & PLANE_CRITICAL_DISPLAY) - // We here assume that your render target starts with * - if(critical & PLANE_CRITICAL_CUT_RENDER && render_target) - render_target = "*[render_target]" - - if(!(critical & PLANE_CRITICAL_NO_RELAY)) - return - var/client/our_client = relevant.client - if(our_client) - for(var/atom/movable/render_plane_relay/relay as anything in relays) - our_client.screen += relay - - return - show_to(relevant) - -/atom/movable/screen/plane_master/clickcatcher - name = "Click Catcher" - documentation = "Contains the screen object we use as a backdrop to catch clicks on portions of the screen that would otherwise contain nothing else. \ -
Will always be below almost everything else" - plane = CLICKCATCHER_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - multiz_scaled = FALSE - critical = PLANE_CRITICAL_DISPLAY - -/atom/movable/screen/plane_master/clickcatcher/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, PROC_REF(offset_increased)) - offset_increased(SSmapping, 0, SSmapping.max_plane_offset) - -/atom/movable/screen/plane_master/clickcatcher/proc/offset_increased(datum/source, old_off, new_off) - SIGNAL_HANDLER - // We only want need the lowest level - // If my system better supported changing PM plane values mid op I'd do that, but I do NOT so - if(new_off > offset) - hide_plane(home?.our_hud?.mymob) - -/atom/movable/screen/plane_master/parallax_white - name = "Parallax whitifier" - documentation = "Essentially a backdrop for the parallax plane. We're rendered just below it, so we'll be multiplied by its well, parallax.\ -
If you want something to look as if it has parallax on it, draw it to this plane." - plane = PLANE_SPACE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_GAME, LIGHT_MASK_PLANE) - critical = PLANE_CRITICAL_FUCKO_PARALLAX // goes funny when touched. no idea why I don't trust byond - -/atom/movable/screen/plane_master/parallax_white/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_SPACE_LAYER) - -///Contains space parallax -/atom/movable/screen/plane_master/parallax - name = "Parallax" - documentation = "Contains parallax, or to be more exact the screen objects that hold parallax.\ -
Note the BLEND_MULTIPLY. The trick here is how low our plane value is. Because of that, we draw below almost everything in the game.\ -
We abuse this to ensure we multiply against the Parallax whitifier plane, or space's plane. It's set to full white, so when you do the multiply you just get parallax out where it well, makes sense to be.\ -
Also notice that the parent parallax plane is mirrored down to all children. We want to support viewing parallax across all z levels at once." - plane = PLANE_SPACE_PARALLAX - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - blend_mode = BLEND_MULTIPLY - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - multiz_scaled = FALSE - -/atom/movable/screen/plane_master/parallax/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - if(offset != 0) - // You aren't the source? don't change yourself - return - RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, PROC_REF(on_offset_increase)) - RegisterSignal(SSdcs, COMSIG_NARSIE_SUMMON_UPDATE, PROC_REF(narsie_modified)) - if(GLOB.narsie_summon_count >= 1) - narsie_start_midway(GLOB.narsie_effect_last_modified) // We assume we're on the start, so we can use this number - offset_increase(0, SSmapping.max_plane_offset) - -/atom/movable/screen/plane_master/parallax/proc/on_offset_increase(datum/source, old_offset, new_offset) - SIGNAL_HANDLER - offset_increase(old_offset, new_offset) - -/atom/movable/screen/plane_master/parallax/proc/offset_increase(old_offset, new_offset) - // Parallax will be mirrored down to any new planes that are added, so it will properly render across mirage borders - for(var/offset in old_offset to new_offset) - if(offset != 0) - // Overlay so we don't multiply twice, and thus fuck up our rendering - add_relay_to(GET_NEW_PLANE(plane, offset), BLEND_OVERLAY) - -// Hacky shit to ensure parallax works in perf mode -/atom/movable/screen/plane_master/parallax/outside_bounds(mob/relevant) - if(offset == 0) - remove_relay_from(GET_NEW_PLANE(RENDER_PLANE_GAME, 0)) - is_outside_bounds = TRUE // I'm sorry :( - return - // If we can't render, and we aren't the bottom layer, don't render us - // This way we only multiply against stuff that's not fullwhite space - var/atom/movable/screen/plane_master/parent_parallax = home.our_hud.get_plane_master(PLANE_SPACE_PARALLAX) - var/turf/viewing_turf = get_turf(relevant) - if(!viewing_turf || offset != GET_LOWEST_STACK_OFFSET(viewing_turf.z)) - parent_parallax.remove_relay_from(plane) - else - parent_parallax.add_relay_to(plane, BLEND_OVERLAY) - return ..() - -/atom/movable/screen/plane_master/parallax/inside_bounds(mob/relevant) - if(offset == 0) - add_relay_to(GET_NEW_PLANE(RENDER_PLANE_GAME, 0)) - is_outside_bounds = FALSE - return - // Always readd, just in case we lost it - var/atom/movable/screen/plane_master/parent_parallax = home.our_hud.get_plane_master(PLANE_SPACE_PARALLAX) - parent_parallax.add_relay_to(plane, BLEND_OVERLAY) - return ..() - -// Needs to handle rejoining on a lower z level, so we NEED to readd old planes -/atom/movable/screen/plane_master/parallax/check_outside_bounds() - // If we're outside bounds AND we're the 0th plane, we need to show cause parallax is hacked to hell - return offset != 0 && is_outside_bounds - -/// Starts the narsie animation midway, so we can catch up to everyone else quickly -/atom/movable/screen/plane_master/parallax/proc/narsie_start_midway(start_time) - var/time_elapsed = world.time - start_time - narsie_summoned_effect(max(16 SECONDS - time_elapsed, 0)) - -/// Starts the narsie animation, make us grey, then red -/atom/movable/screen/plane_master/parallax/proc/narsie_modified(datum/source, new_count) - SIGNAL_HANDLER - if(new_count >= 1) - narsie_summoned_effect(16 SECONDS) - else - narsie_unsummoned() - -/atom/movable/screen/plane_master/parallax/proc/narsie_summoned_effect(animate_time) - if(GLOB.narsie_summon_count >= 2) - var/static/list/nightmare_parallax = list(255,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, -130,0,0,0) - animate(src, color = nightmare_parallax, time = animate_time) - return - - var/static/list/grey_parallax = list(0.4,0.4,0.4,0, 0.4,0.4,0.4,0, 0.4,0.4,0.4,0, 0,0,0,1, -0.1,-0.1,-0.1,0) - // We're gonna animate ourselves grey - // Then, once it's done, about 40 seconds into the event itself, we're gonna start doin some shit. see below - animate(src, color = grey_parallax, time = animate_time) - -/atom/movable/screen/plane_master/parallax/proc/narsie_unsummoned() - animate(src, color = null, time = 8 SECONDS) - -/atom/movable/screen/plane_master/gravpulse - name = "Gravpulse" - documentation = "Ok so this one's fun. Basically, we want to be able to distort the game plane when a grav annom is around.\ -
So we draw the pattern we want to use to this plane, and it's then used as a render target by a distortion filter on the game plane.\ -
Note the blend mode and lack of relay targets. This plane exists only to distort, it's never rendered anywhere." - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - plane = GRAVITY_PULSE_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - blend_mode = BLEND_ADD - render_target = GRAVITY_PULSE_RENDER_TARGET - render_relay_planes = list() - -///Contains just the floor -/atom/movable/screen/plane_master/floor - name = "Floor" - documentation = "The well, floor. This is mostly used as a sorting mechanism, but it also lets us create a \"border\" around the game world plane, so its drop shadow will actually work." - plane = FLOOR_PLANE - render_relay_planes = list(RENDER_PLANE_GAME, LIGHT_MASK_PLANE) - -/atom/movable/screen/plane_master/transparent_floor - name = "Transparent Floor" - documentation = "Really just openspace, stuff that is a turf but has no color or alpha whatsoever.\ -
We use this to draw to just the light mask plane, cause if it's not there we get holes of blackness over openspace" - plane = TRANSPARENT_FLOOR_PLANE - render_relay_planes = list(LIGHT_MASK_PLANE) - // Needs to be critical or it uh, it'll look white - critical = PLANE_CRITICAL_DISPLAY|PLANE_CRITICAL_NO_RELAY - -/atom/movable/screen/plane_master/floor/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_FLOOR_LAYER, relay_color = GLOB.em_block_color) - -/atom/movable/screen/plane_master/wall - name = "Wall" - documentation = "Holds all walls. We render this onto the game world. Separate so we can use this + space and floor planes as a guide for where byond blackness is NOT." - plane = WALL_PLANE - render_relay_planes = list(RENDER_PLANE_GAME_WORLD, LIGHT_MASK_PLANE) - -/atom/movable/screen/plane_master/wall/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_WALL_LAYER, relay_color = GLOB.em_block_color) - -/atom/movable/screen/plane_master/game - name = "Lower game world" - documentation = "Exists mostly because of FOV shit. Basically, if you've just got a normal not ABOVE fov thing, and you don't want it masked, stick it here yeah?" - plane = GAME_PLANE - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - -/atom/movable/screen/plane_master/game_world_fov_hidden - name = "lower game world fov hidden" - documentation = "If you want something to be hidden by fov, stick it on this plane. We're masked by the fov blocker plane, so the items on us can actually well, disappear." - plane = GAME_PLANE_FOV_HIDDEN - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - -/atom/movable/screen/plane_master/game_world_fov_hidden/Initialize(mapload, datum/hud/hud_owner) - . = ..() - add_filter("vision_cone", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(FIELD_OF_VISION_BLOCKER_RENDER_TARGET, offset), flags = MASK_INVERSE)) - -/atom/movable/screen/plane_master/field_of_vision_blocker - name = "Field of vision blocker" - documentation = "This is one of those planes that's only used as a filter. It masks out things that want to be hidden by fov.\ -
Literally just contains FOV images, or masks." - plane = FIELD_OF_VISION_BLOCKER_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_target = FIELD_OF_VISION_BLOCKER_RENDER_TARGET - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - render_relay_planes = list() - // We do NOT allow offsetting, because there's no case where you would want to block only one layer, at least currently - allows_offsetting = FALSE - start_hidden = TRUE - // We mark as multiz_scaled FALSE so transforms don't effect us, and we draw to the planes below us as if they were us. - // This is safe because we will ALWAYS be on the top z layer, so it DON'T MATTER - multiz_scaled = FALSE - -/atom/movable/screen/plane_master/field_of_vision_blocker/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - mirror_parent_hidden() - -/atom/movable/screen/plane_master/game_world_upper - name = "Upper game world" - documentation = "Ok so fov is kinda fucky, because planes in byond serve both as effect groupings and as rendering orderers. Since that's true, we need a plane that we can stick stuff that draws above fov blocked stuff on." - plane = GAME_PLANE_UPPER - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - -/atom/movable/screen/plane_master/wall_upper - name = "Upper wall" - documentation = "There are some walls that want to render above most things (mostly minerals since they shift over.\ -
We draw them to their own plane so we can hijack them for our emissive mask stuff" - plane = WALL_PLANE_UPPER - render_relay_planes = list(RENDER_PLANE_GAME_WORLD, LIGHT_MASK_PLANE) - -/atom/movable/screen/plane_master/wall_upper/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_WALL_LAYER, relay_color = GLOB.em_block_color) - -/atom/movable/screen/plane_master/game_world_upper_fov_hidden - name = "Upper game world fov hidden" - documentation = "Just as we need a place to draw things \"above\" the hidden fov plane, we also need to be able to hide stuff that draws over the upper game plane." - plane = GAME_PLANE_UPPER_FOV_HIDDEN - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - -/atom/movable/screen/plane_master/game_world_upper_fov_hidden/Initialize(mapload, datum/hud/hud_owner) - . = ..() - // Dupe of the other hidden plane - add_filter("vision_cone", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(FIELD_OF_VISION_BLOCKER_RENDER_TARGET, offset), flags = MASK_INVERSE)) - -/atom/movable/screen/plane_master/seethrough - name = "Seethrough" - documentation = "Holds the seethrough versions (done using image overrides) of large objects. Mouse transparent, so you can click through them." - plane = SEETHROUGH_PLANE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - start_hidden = TRUE - -/atom/movable/screen/plane_master/game_world_above - name = "Above game world" - documentation = "We need a place that's unmasked by fov that also draws above the upper game world fov hidden plane. I told you fov was hacky man." - plane = ABOVE_GAME_PLANE - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - -/** - * Plane master that byond will by default draw to - * Shouldn't be used, exists to prevent people using plane 0 - * NOTE: If we used SEE_BLACKNESS on a map format that wasn't SIDE_MAP, this is where its darkness would land - * This would allow us to control it and do fun things. But we can't because side map doesn't support it, so this is just a stub - */ -/atom/movable/screen/plane_master/default - name = "Default" - documentation = "This is quite fiddly, so bear with me. By default (in byond) everything in the game is rendered onto plane 0. It's the default plane. \ -
But, because we've moved everything we control off plane 0, all that's left is stuff byond internally renders. \ -
What I'd like to do with this is capture byond blackness by giving mobs the SEE_BLACKNESS sight flag. \ -
But we CAN'T because SEE_BLACKNESS does not work with our rendering format. So I just eat it I guess" - plane = DEFAULT_PLANE - multiz_scaled = FALSE - start_hidden = TRUE // Doesn't DO anything, exists to hold this place - -/atom/movable/screen/plane_master/area - name = "Area" - documentation = "Holds the areas themselves, which ends up meaning it holds any overlays/effects we apply to areas. NOT snow or rad storms, those go on above lighting" - plane = AREA_PLANE - -/atom/movable/screen/plane_master/massive_obj - name = "Massive object" - documentation = "Huge objects need to render above everything else on the game plane, otherwise they'd well, get clipped and look not that huge. This does that." - plane = MASSIVE_OBJ_PLANE - -/atom/movable/screen/plane_master/point - name = "Point" - documentation = "I mean like, what do you want me to say? Points draw over pretty much everything else, so they get their own plane. Remember we layer render relays to draw planes in their proper order on render plates." - plane = POINT_PLANE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - -///Contains all turf lighting -/atom/movable/screen/plane_master/turf_lighting - name = "Turf Lighting" - documentation = "Contains all lighting drawn to turfs. Not so complex, draws directly onto the lighting plate." - plane = LIGHTING_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_LIGHTING) - blend_mode_override = BLEND_ADD - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - critical = PLANE_CRITICAL_DISPLAY - -/// This will not work through multiz, because of a byond bug with BLEND_MULTIPLY -/// Bug report is up, waiting on a fix -/atom/movable/screen/plane_master/o_light_visual - name = "Overlight light visual" - documentation = "Holds overlay lighting objects, or the sort of lighting that's a well, overlay stuck to something.\ -
Exists because lighting updating is really slow, and movement needs to feel smooth.\ -
We draw to the game plane, and mask out space for ourselves on the lighting plane so any color we have has the chance to display." - plane = O_LIGHTING_VISUAL_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_target = O_LIGHTING_VISUAL_RENDER_TARGET - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - blend_mode = BLEND_MULTIPLY - critical = PLANE_CRITICAL_DISPLAY - -/atom/movable/screen/plane_master/above_lighting - name = "Above lighting" - plane = ABOVE_LIGHTING_PLANE - documentation = "Anything on the game plane that needs a space to draw on that will be above the lighting plane.\ -
Mostly little alerts and effects, also sometimes contains things that are meant to look as if they glow." - -/** - * Handles emissive overlays and emissive blockers. - */ -/atom/movable/screen/plane_master/emissive - name = "Emissive" - documentation = "Holds things that will be used to mask the lighting plane later on. Masked by the Emissive Mask plane to ensure we don't emiss out under a wall.\ -
Relayed onto the Emissive render plane to do the actual masking of lighting, since we need to be transformed and other emissive stuff needs to be transformed too.\ -
Don't want to double scale now." - plane = EMISSIVE_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - render_relay_planes = list(EMISSIVE_RENDER_PLATE) - critical = PLANE_CRITICAL_DISPLAY - -/atom/movable/screen/plane_master/pipecrawl - name = "Pipecrawl" - documentation = "Holds pipecrawl images generated during well, pipecrawling.\ -
Has a few effects and a funky color matrix designed to make things a bit more visually readable." - plane = PIPECRAWL_IMAGES_PLANE - start_hidden = TRUE - -/atom/movable/screen/plane_master/pipecrawl/Initialize(mapload, datum/hud/hud_owner) - . = ..() - // Makes everything on this plane slightly brighter - // Has a nice effect, makes thing stand out - color = list(1.2,0,0,0, 0,1.2,0,0, 0,0,1.2,0, 0,0,0,1, 0,0,0,0) - // This serves a similar purpose, I want the pipes to pop - add_filter("pipe_dropshadow", 1, drop_shadow_filter(x = -1, y= -1, size = 1, color = "#0000007A")) - mirror_parent_hidden() - -/atom/movable/screen/plane_master/camera_static - name = "Camera static" - documentation = "Holds camera static images. Usually only visible to people who can well, see static.\ -
We use images rather then vis contents because they're lighter on maptick, and maptick sucks butt." - plane = CAMERA_STATIC_PLANE - -/atom/movable/screen/plane_master/camera_static/show_to(mob/mymob) - . = ..() - if(!.) - return - var/datum/hud/our_hud = home.our_hud - if(isnull(our_hud)) - return - - // We'll hide the slate if we're not seeing through a camera eye - // This can call on a cycle cause we don't clear in hide_from - // Yes this is the best way of hooking into the hud, I hate myself too - RegisterSignal(our_hud, COMSIG_HUD_EYE_CHANGED, PROC_REF(eye_changed), override = TRUE) - eye_changed(our_hud, null, our_hud.mymob?.canon_client?.eye) - -/atom/movable/screen/plane_master/camera_static/proc/eye_changed(datum/hud/source, atom/old_eye, atom/new_eye) - SIGNAL_HANDLER - - if(!isaicamera(new_eye)) - if(!force_hidden) - hide_plane(source.mymob) - return - - if(force_hidden) - unhide_plane(source.mymob) - -/atom/movable/screen/plane_master/high_game - name = "High Game" - documentation = "Holds anything that wants to be displayed above the rest of the game plane, and doesn't want to be clickable. \ -
This includes atmos debug overlays, blind sound images, and mining scanners. \ -
Really only exists for its layering potential, we don't use this for any vfx" - plane = HIGH_GAME_PLANE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - -/atom/movable/screen/plane_master/ghost - name = "Ghost" - documentation = "Ghosts draw here, so they don't get mixed up in the visuals of the game world. Note, this is not not how we HIDE ghosts from people, that's done with invisible and see_invisible." - plane = GHOST_PLANE - render_relay_planes = list(RENDER_PLANE_NON_GAME) - -/atom/movable/screen/plane_master/fullscreen - name = "Fullscreen" - documentation = "Holds anything that applies to or above the full screen. \ -
Note, it's still rendered underneath hud objects, but this lets us control the order that things like death/damage effects render in." - plane = FULLSCREEN_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_NON_GAME) - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - allows_offsetting = FALSE - -/atom/movable/screen/plane_master/runechat - name = "Runechat" - documentation = "Holds runechat images, that text that pops up when someone say something. Uses a dropshadow to well, look nice." - plane = RUNECHAT_PLANE - render_relay_planes = list(RENDER_PLANE_NON_GAME) - -/atom/movable/screen/plane_master/runechat/show_to(mob/mymob) - . = ..() - if(!.) - return - remove_filter("AO") - if(istype(mymob) && mymob.canon_client?.prefs?.read_preference(/datum/preference/toggle/ambient_occlusion)) - add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA")) - -/atom/movable/screen/plane_master/balloon_chat - name = "Balloon chat" - documentation = "Holds ballon chat images, those little text bars that pop up for a second when you do some things. NOT runechat." - plane = BALLOON_CHAT_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_NON_GAME) - -/atom/movable/screen/plane_master/hud - name = "HUD" - documentation = "Contains anything that want to be rendered on the hud. Typically is just screen elements." - plane = HUD_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_NON_GAME) - allows_offsetting = FALSE - -/atom/movable/screen/plane_master/above_hud - name = "Above HUD" - documentation = "Anything that wants to be drawn ABOVE the rest of the hud. Typically close buttons and other elements that need to be always visible. Think preventing draggable action button memes." - plane = ABOVE_HUD_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_NON_GAME) - allows_offsetting = FALSE - -/atom/movable/screen/plane_master/splashscreen - name = "Splashscreen" - documentation = "Cinematics and the splash screen." - plane = SPLASHSCREEN_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_NON_GAME) - allows_offsetting = FALSE - -/atom/movable/screen/plane_master/escape_menu - name = "Escape Menu" - documentation = "Anything relating to the escape menu." - plane = ESCAPE_MENU_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_MASTER) - allows_offsetting = FALSE diff --git a/code/_onclick/hud/rendering/plane_masters/_plane_master.dm b/code/_onclick/hud/rendering/plane_masters/_plane_master.dm new file mode 100644 index 00000000000000..13f94fa9f5aa09 --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/_plane_master.dm @@ -0,0 +1,236 @@ +// I hate this place +INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) + +/atom/movable/screen/plane_master + screen_loc = "CENTER" + icon_state = "blank" + appearance_flags = PLANE_MASTER + blend_mode = BLEND_OVERLAY + plane = LOWEST_EVER_PLANE + /// Will be sent to the debug ui as a description for each plane + /// Also useful as a place to explain to coders how/why your plane works, and what it's meant to do + /// Plaintext and basic html are fine to use here. + /// I'll bonk you if I find you putting "lmao stuff" in here, make this useful. + var/documentation = "" + /// Our real alpha value, so alpha can persist through being hidden/shown + var/true_alpha = 255 + /// Tracks if we're using our true alpha, or being manipulated in some other way + var/alpha_enabled = TRUE + + /// The plane master group we're a member of, our "home" + var/datum/plane_master_group/home + + /// If our plane master allows for offsetting + /// Mostly used for planes that really don't need to be duplicated, like the hud planes + var/allows_offsetting = TRUE + /// Our offset from our "true" plane, see below + var/offset + /// When rendering multiz, lower levels get their own set of plane masters + /// Real plane here represents the "true" plane value of something, ignoring the offset required to handle lower levels + var/real_plane + + //--rendering relay vars-- + /// list of planes we will relay this plane's render to + var/list/render_relay_planes = list(RENDER_PLANE_GAME) + /// blend mode to apply to the render relay in case you dont want to use the plane_masters blend_mode + var/blend_mode_override + /// list of current relays this plane is utilizing to render + var/list/atom/movable/render_plane_relay/relays = list() + /// if render relays have already be generated + var/relays_generated = FALSE + + /// If this plane master should be hidden from the player at roundstart + /// We do this so PMs can opt into being temporary, to reduce load on clients + var/start_hidden = FALSE + /// If this plane master is being forced to hide. + /// Hidden PMs will dump ANYTHING relayed or drawn onto them. Be careful with this + /// Remember: a hidden plane master will dump anything drawn directly to it onto the output render. It does NOT hide its contents + /// Use alpha for that + var/force_hidden = FALSE + + /// If this plane should be scaled by multiz + /// Planes with this set should NEVER be relay'd into each other, as that will cause visual fuck + var/multiz_scaled = TRUE + + /// Bitfield that describes how this plane master will render if its z layer is being "optimized" + /// If a plane master is NOT critical, it will be completely dropped if we start to render outside a client's multiz boundary prefs + /// Of note: most of the time we will relay renders to non critical planes in this stage. so the plane master will end up drawing roughly "in order" with its friends + /// This is NOT done for parallax and other problem children, because the rules of BLEND_MULTIPLY appear to not behave as expected :( + /// This will also just make debugging harder, because we do fragile things in order to ensure things operate as epected. I'm sorry + /// Compile time + /// See [code\__DEFINES\layers.dm] for our bitflags + var/critical = NONE + + /// If this plane master is outside of our visual bounds right now + var/is_outside_bounds = FALSE + +/atom/movable/screen/plane_master/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset = 0) + . = ..() + src.offset = offset + true_alpha = alpha + real_plane = plane + + if(!set_home(home)) + return INITIALIZE_HINT_QDEL + update_offset() + if(!documentation && !(istype(src, /atom/movable/screen/plane_master) || istype(src, /atom/movable/screen/plane_master/rendering_plate))) + stack_trace("Plane master created without a description. Document how your thing works so people will know in future, and we can display it in the debug menu") + if(start_hidden) + hide_plane(home.our_hud?.mymob) + generate_render_relays() + +/atom/movable/screen/plane_master/Destroy() + if(home) + // NOTE! We do not clear ourselves from client screens + // We relay on whoever qdel'd us to reset our hud, and properly purge us + home.plane_masters -= "[plane]" + home = null + . = ..() + QDEL_LIST(relays) + +/// Sets the plane group that owns us, it also determines what screen we render to +/// Returns FALSE if the set_home fails, TRUE otherwise +/atom/movable/screen/plane_master/proc/set_home(datum/plane_master_group/home) + if(!istype(home, /datum/plane_master_group)) + return FALSE + src.home = home + if(home.map) + screen_loc = "[home.map]:[screen_loc]" + assigned_map = home.map + return TRUE + +/// Updates our "offset", basically what layer of multiz we're meant to render +/// Top is 0, goes up as you go down +/// It's taken into account by render targets and relays, so we gotta make sure they're on the same page +/atom/movable/screen/plane_master/proc/update_offset() + name = "[initial(name)] #[offset]" + SET_PLANE_W_SCALAR(src, real_plane, offset) + for(var/i in 1 to length(render_relay_planes)) + render_relay_planes[i] = GET_NEW_PLANE(render_relay_planes[i], offset) + if(initial(render_target)) + render_target = OFFSET_RENDER_TARGET(initial(render_target), offset) + +/atom/movable/screen/plane_master/proc/set_alpha(new_alpha) + true_alpha = new_alpha + if(!alpha_enabled) + return + alpha = new_alpha + +/atom/movable/screen/plane_master/proc/disable_alpha() + alpha_enabled = FALSE + alpha = 0 + +/atom/movable/screen/plane_master/proc/enable_alpha() + alpha_enabled = TRUE + alpha = true_alpha + +/// Shows a plane master to the passed in mob +/// Override this to apply unique effects and such +/// Returns TRUE if the call is allowed, FALSE otherwise +/atom/movable/screen/plane_master/proc/show_to(mob/mymob) + SHOULD_CALL_PARENT(TRUE) + if(force_hidden) + return FALSE + + var/client/our_client = mymob?.canon_client + // Alright, let's get this out of the way + // Mobs can move z levels without their client. If this happens, we need to ensure critical display settings are respected + // This is done here. Mild to severe pain but it's nessesary + if(check_outside_bounds()) + if(!(critical & PLANE_CRITICAL_DISPLAY)) + return FALSE + if(!our_client) + return TRUE + our_client.screen += src + + if(!(critical & PLANE_CRITICAL_NO_RELAY)) + our_client.screen += relays + return TRUE + return TRUE + + if(!our_client) + return TRUE + + our_client.screen += src + our_client.screen += relays + return TRUE + +/// Hook to allow planes to work around is_outside_bounds +/// Return false to allow a show, true otherwise +/atom/movable/screen/plane_master/proc/check_outside_bounds() + return is_outside_bounds + +/// Hides a plane master from the passeed in mob +/// Do your effect cleanup here +/atom/movable/screen/plane_master/proc/hide_from(mob/oldmob) + SHOULD_CALL_PARENT(TRUE) + var/client/their_client = oldmob?.client + if(!their_client) + return + their_client.screen -= src + their_client.screen -= relays + + +/// Forces this plane master to hide, until unhide_plane is called +/// This allows us to disable unused PMs without breaking anything else +/atom/movable/screen/plane_master/proc/hide_plane(mob/cast_away) + force_hidden = TRUE + hide_from(cast_away) + +/// Disables any forced hiding, allows the plane master to be used as normal +/atom/movable/screen/plane_master/proc/unhide_plane(mob/enfold) + force_hidden = FALSE + show_to(enfold) + +/// Mirrors our force hidden state to the hidden state of the plane that came before, assuming it's valid +/// This allows us to mirror any hidden sets from before we were created, no matter how low that chance is +/atom/movable/screen/plane_master/proc/mirror_parent_hidden() + var/mob/our_mob = home?.our_hud?.mymob + var/atom/movable/screen/plane_master/true_plane = our_mob?.hud_used?.get_plane_master(plane) + if(true_plane == src || !true_plane) + return + + if(true_plane.force_hidden == force_hidden) + return + + // If one of us already exists and it's not hidden, unhide ourselves + if(true_plane.force_hidden) + hide_plane(our_mob) + else + unhide_plane(our_mob) + +/atom/movable/screen/plane_master/proc/outside_bounds(mob/relevant) + if(force_hidden || is_outside_bounds) + return + is_outside_bounds = TRUE + // If we're of critical importance, AND we're below the rendering layer + if(critical & PLANE_CRITICAL_DISPLAY) + // We here assume that your render target starts with * + if(critical & PLANE_CRITICAL_CUT_RENDER && render_target) + render_target = copytext_char(render_target, 2) + if(!(critical & PLANE_CRITICAL_NO_RELAY)) + return + var/client/our_client = relevant.client + if(our_client) + for(var/atom/movable/render_plane_relay/relay as anything in relays) + our_client.screen -= relay + + return + hide_from(relevant) + +/atom/movable/screen/plane_master/proc/inside_bounds(mob/relevant) + is_outside_bounds = FALSE + if(critical & PLANE_CRITICAL_DISPLAY) + // We here assume that your render target starts with * + if(critical & PLANE_CRITICAL_CUT_RENDER && render_target) + render_target = "*[render_target]" + + if(!(critical & PLANE_CRITICAL_NO_RELAY)) + return + var/client/our_client = relevant.client + if(our_client) + for(var/atom/movable/render_plane_relay/relay as anything in relays) + our_client.screen += relay + + return + show_to(relevant) diff --git a/code/_onclick/hud/rendering/plane_masters/camera_static.dm b/code/_onclick/hud/rendering/plane_masters/camera_static.dm new file mode 100644 index 00000000000000..4cb3436a7a4901 --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/camera_static.dm @@ -0,0 +1,30 @@ +/atom/movable/screen/plane_master/camera_static + name = "Camera static" + documentation = "Holds camera static images. Usually only visible to people who can well, see static.\ +
We use images rather then vis contents because they're lighter on maptick, and maptick sucks butt." + plane = CAMERA_STATIC_PLANE + +/atom/movable/screen/plane_master/camera_static/show_to(mob/mymob) + . = ..() + if(!.) + return + var/datum/hud/our_hud = home.our_hud + if(isnull(our_hud)) + return + + // We'll hide the slate if we're not seeing through a camera eye + // This can call on a cycle cause we don't clear in hide_from + // Yes this is the best way of hooking into the hud, I hate myself too + RegisterSignal(our_hud, COMSIG_HUD_EYE_CHANGED, PROC_REF(eye_changed), override = TRUE) + eye_changed(our_hud, null, our_hud.mymob?.canon_client?.eye) + +/atom/movable/screen/plane_master/camera_static/proc/eye_changed(datum/hud/source, atom/old_eye, atom/new_eye) + SIGNAL_HANDLER + + if(!isaicamera(new_eye)) + if(!force_hidden) + hide_plane(source.mymob) + return + + if(force_hidden) + unhide_plane(source.mymob) diff --git a/code/_onclick/hud/rendering/plane_masters/clickcatcher.dm b/code/_onclick/hud/rendering/plane_masters/clickcatcher.dm new file mode 100644 index 00000000000000..8e581dc081c824 --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/clickcatcher.dm @@ -0,0 +1,20 @@ +/atom/movable/screen/plane_master/clickcatcher + name = "Click Catcher" + documentation = "Contains the screen object we use as a backdrop to catch clicks on portions of the screen that would otherwise contain nothing else. \ +
Will always be below almost everything else" + plane = CLICKCATCHER_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + multiz_scaled = FALSE + critical = PLANE_CRITICAL_DISPLAY + +/atom/movable/screen/plane_master/clickcatcher/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, PROC_REF(offset_increased)) + offset_increased(SSmapping, 0, SSmapping.max_plane_offset) + +/atom/movable/screen/plane_master/clickcatcher/proc/offset_increased(datum/source, old_off, new_off) + SIGNAL_HANDLER + // We only want need the lowest level + // If my system better supported changing PM plane values mid op I'd do that, but I do NOT so + if(new_off > offset) + hide_plane(home?.our_hud?.mymob) diff --git a/code/_onclick/hud/rendering/plane_masters/core_game_planes.dm b/code/_onclick/hud/rendering/plane_masters/core_game_planes.dm new file mode 100644 index 00000000000000..89379070b35006 --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/core_game_planes.dm @@ -0,0 +1,122 @@ +//-------------------- FLOOR PLANE -------------------- + +///Contains just the floor +/atom/movable/screen/plane_master/floor + name = "Floor" + documentation = "The well, floor. This is mostly used as a sorting mechanism, but it also lets us create a \"border\" around the game world plane, so its drop shadow will actually work." + plane = FLOOR_PLANE + render_relay_planes = list(RENDER_PLANE_GAME, LIGHT_MASK_PLANE) + +/atom/movable/screen/plane_master/transparent_floor + name = "Transparent Floor" + documentation = "Really just openspace, stuff that is a turf but has no color or alpha whatsoever.\ +
We use this to draw to just the light mask plane, cause if it's not there we get holes of blackness over openspace" + plane = TRANSPARENT_FLOOR_PLANE + render_relay_planes = list(LIGHT_MASK_PLANE) + // Needs to be critical or it uh, it'll look white + critical = PLANE_CRITICAL_DISPLAY|PLANE_CRITICAL_NO_RELAY + +/atom/movable/screen/plane_master/floor/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_FLOOR_LAYER, relay_color = GLOB.em_block_color) + +//-------------------- WALL PLANE -------------------- + +/atom/movable/screen/plane_master/wall + name = "Wall" + documentation = "Holds all walls. We render this onto the game world. Separate so we can use this + space and floor planes as a guide for where byond blackness is NOT." + plane = WALL_PLANE + render_relay_planes = list(RENDER_PLANE_GAME_WORLD, LIGHT_MASK_PLANE) + +/atom/movable/screen/plane_master/wall/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_WALL_LAYER, relay_color = GLOB.em_block_color) + +/atom/movable/screen/plane_master/wall_upper + name = "Upper wall" + documentation = "There are some walls that want to render above most things (mostly minerals since they shift over.\ +
We draw them to their own plane so we can hijack them for our emissive mask stuff" + plane = WALL_PLANE_UPPER + render_relay_planes = list(RENDER_PLANE_GAME_WORLD, LIGHT_MASK_PLANE) + +/atom/movable/screen/plane_master/wall_upper/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_WALL_LAYER, relay_color = GLOB.em_block_color) + +//-------------------- AREA PLANE -------------------- + +/atom/movable/screen/plane_master/area + name = "Area" + documentation = "Holds the areas themselves, which ends up meaning it holds any overlays/effects we apply to areas. NOT snow or rad storms, those go on above lighting" + plane = AREA_PLANE + +//-------------------- GAME PLANES -------------------- + +/atom/movable/screen/plane_master/game + name = "Lower game world" + documentation = "Exists mostly because of FOV shit. Basically, if you've just got a normal not ABOVE fov thing, and you don't want it masked, stick it here yeah?" + plane = GAME_PLANE + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + +/atom/movable/screen/plane_master/high_game + name = "High Game" + documentation = "Holds anything that wants to be displayed above the rest of the game plane, and doesn't want to be clickable. \ +
This includes atmos debug overlays, blind sound images, and mining scanners. \ +
Really only exists for its layering potential, we don't use this for any vfx" + plane = HIGH_GAME_PLANE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + +//-------------------- FOV PLANES -------------------- + +/atom/movable/screen/plane_master/game_world_fov_hidden + name = "lower game world fov hidden" + documentation = "If you want something to be hidden by fov, stick it on this plane. We're masked by the fov blocker plane, so the items on us can actually well, disappear." + plane = GAME_PLANE_FOV_HIDDEN + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + +/atom/movable/screen/plane_master/game_world_fov_hidden/Initialize(mapload, datum/hud/hud_owner) + . = ..() + add_filter("vision_cone", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(FIELD_OF_VISION_BLOCKER_RENDER_TARGET, offset), flags = MASK_INVERSE)) + +/atom/movable/screen/plane_master/field_of_vision_blocker + name = "Field of vision blocker" + documentation = "This is one of those planes that's only used as a filter. It masks out things that want to be hidden by fov.\ +
Literally just contains FOV images, or masks." + plane = FIELD_OF_VISION_BLOCKER_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_target = FIELD_OF_VISION_BLOCKER_RENDER_TARGET + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + render_relay_planes = list() + // We do NOT allow offsetting, because there's no case where you would want to block only one layer, at least currently + allows_offsetting = FALSE + start_hidden = TRUE + // We mark as multiz_scaled FALSE so transforms don't effect us, and we draw to the planes below us as if they were us. + // This is safe because we will ALWAYS be on the top z layer, so it DON'T MATTER + multiz_scaled = FALSE + +/atom/movable/screen/plane_master/field_of_vision_blocker/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + mirror_parent_hidden() + +/atom/movable/screen/plane_master/game_world_above + name = "Above game world" + documentation = "We need a place that's unmasked by fov that also draws above the upper game world fov hidden plane. I told you fov was hacky man." + plane = ABOVE_GAME_PLANE + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + +/atom/movable/screen/plane_master/game_world_upper + name = "Upper game world" + documentation = "Ok so fov is kinda fucky, because planes in byond serve both as effect groupings and as rendering orderers. Since that's true, we need a plane that we can stick stuff that draws above fov blocked stuff on." + plane = GAME_PLANE_UPPER + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + +/atom/movable/screen/plane_master/game_world_upper_fov_hidden + name = "Upper game world fov hidden" + documentation = "Just as we need a place to draw things \"above\" the hidden fov plane, we also need to be able to hide stuff that draws over the upper game plane." + plane = GAME_PLANE_UPPER_FOV_HIDDEN + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + +/atom/movable/screen/plane_master/game_world_upper_fov_hidden/Initialize(mapload, datum/hud/hud_owner) + . = ..() + // Dupe of the other hidden plane + add_filter("vision_cone", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(FIELD_OF_VISION_BLOCKER_RENDER_TARGET, offset), flags = MASK_INVERSE)) diff --git a/code/_onclick/hud/rendering/plane_masters/default.dm b/code/_onclick/hud/rendering/plane_masters/default.dm new file mode 100644 index 00000000000000..f4f49f5bdd86b4 --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/default.dm @@ -0,0 +1,15 @@ +/** + * Plane master that byond will by default draw to + * Shouldn't be used, exists to prevent people using plane 0 + * NOTE: If we used SEE_BLACKNESS on a map format that wasn't SIDE_MAP, this is where its darkness would land + * This would allow us to control it and do fun things. But we can't because side map doesn't support it, so this is just a stub + */ +/atom/movable/screen/plane_master/default + name = "Default" + documentation = "This is quite fiddly, so bear with me. By default (in byond) everything in the game is rendered onto plane 0. It's the default plane. \ +
But, because we've moved everything we control off plane 0, all that's left is stuff byond internally renders. \ +
What I'd like to do with this is capture byond blackness by giving mobs the SEE_BLACKNESS sight flag. \ +
But we CAN'T because SEE_BLACKNESS does not work with our rendering format. So I just eat it I guess" + plane = DEFAULT_PLANE + multiz_scaled = FALSE + start_hidden = TRUE // Doesn't DO anything, exists to hold this place diff --git a/code/_onclick/hud/rendering/plane_masters/in_world_chat.dm b/code/_onclick/hud/rendering/plane_masters/in_world_chat.dm new file mode 100644 index 00000000000000..bc7d327b8fb954 --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/in_world_chat.dm @@ -0,0 +1,20 @@ +/atom/movable/screen/plane_master/runechat + name = "Runechat" + documentation = "Holds runechat images, that text that pops up when someone say something. Uses a dropshadow to well, look nice." + plane = RUNECHAT_PLANE + render_relay_planes = list(RENDER_PLANE_NON_GAME) + +/atom/movable/screen/plane_master/runechat/show_to(mob/mymob) + . = ..() + if(!.) + return + remove_filter("AO") + if(istype(mymob) && mymob.canon_client?.prefs?.read_preference(/datum/preference/toggle/ambient_occlusion)) + add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA")) + +/atom/movable/screen/plane_master/balloon_chat + name = "Balloon chat" + documentation = "Holds ballon chat images, those little text bars that pop up for a second when you do some things. NOT runechat." + plane = BALLOON_CHAT_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_NON_GAME) diff --git a/code/_onclick/hud/rendering/plane_masters/lighting.dm b/code/_onclick/hud/rendering/plane_masters/lighting.dm new file mode 100644 index 00000000000000..2ac4139b78f49d --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/lighting.dm @@ -0,0 +1,44 @@ +///Contains all turf lighting +/atom/movable/screen/plane_master/turf_lighting + name = "Turf Lighting" + documentation = "Contains all lighting drawn to turfs. Not so complex, draws directly onto the lighting plate." + plane = LIGHTING_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_LIGHTING) + blend_mode_override = BLEND_ADD + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + critical = PLANE_CRITICAL_DISPLAY + +/// This will not work through multiz, because of a byond bug with BLEND_MULTIPLY +/// Bug report is up, waiting on a fix +/atom/movable/screen/plane_master/o_light_visual + name = "Overlight light visual" + documentation = "Holds overlay lighting objects, or the sort of lighting that's a well, overlay stuck to something.\ +
Exists because lighting updating is really slow, and movement needs to feel smooth.\ +
We draw to the game plane, and mask out space for ourselves on the lighting plane so any color we have has the chance to display." + plane = O_LIGHTING_VISUAL_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_target = O_LIGHTING_VISUAL_RENDER_TARGET + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + blend_mode = BLEND_MULTIPLY + critical = PLANE_CRITICAL_DISPLAY + +/atom/movable/screen/plane_master/above_lighting + name = "Above lighting" + plane = ABOVE_LIGHTING_PLANE + documentation = "Anything on the game plane that needs a space to draw on that will be above the lighting plane.\ +
Mostly little alerts and effects, also sometimes contains things that are meant to look as if they glow." + +/** + * Handles emissive overlays and emissive blockers. + */ +/atom/movable/screen/plane_master/emissive + name = "Emissive" + documentation = "Holds things that will be used to mask the lighting plane later on. Masked by the Emissive Mask plane to ensure we don't emiss out under a wall.\ +
Relayed onto the Emissive render plane to do the actual masking of lighting, since we need to be transformed and other emissive stuff needs to be transformed too.\ +
Don't want to double scale now." + plane = EMISSIVE_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + render_relay_planes = list(EMISSIVE_RENDER_PLATE) + critical = PLANE_CRITICAL_DISPLAY diff --git a/code/_onclick/hud/rendering/plane_masters/parallax.dm b/code/_onclick/hud/rendering/plane_masters/parallax.dm new file mode 100644 index 00000000000000..ee49ab177007ec --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/parallax.dm @@ -0,0 +1,105 @@ +/atom/movable/screen/plane_master/parallax_white + name = "Parallax whitifier" + documentation = "Essentially a backdrop for the parallax plane. We're rendered just below it, so we'll be multiplied by its well, parallax.\ +
If you want something to look as if it has parallax on it, draw it to this plane." + plane = PLANE_SPACE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_GAME, LIGHT_MASK_PLANE) + critical = PLANE_CRITICAL_FUCKO_PARALLAX // goes funny when touched. no idea why I don't trust byond + +/atom/movable/screen/plane_master/parallax_white/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_SPACE_LAYER) + +///Contains space parallax +/atom/movable/screen/plane_master/parallax + name = "Parallax" + documentation = "Contains parallax, or to be more exact the screen objects that hold parallax.\ +
Note the BLEND_MULTIPLY. The trick here is how low our plane value is. Because of that, we draw below almost everything in the game.\ +
We abuse this to ensure we multiply against the Parallax whitifier plane, or space's plane. It's set to full white, so when you do the multiply you just get parallax out where it well, makes sense to be.\ +
Also notice that the parent parallax plane is mirrored down to all children. We want to support viewing parallax across all z levels at once." + plane = PLANE_SPACE_PARALLAX + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + blend_mode = BLEND_MULTIPLY + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + multiz_scaled = FALSE + +/atom/movable/screen/plane_master/parallax/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + if(offset != 0) + // You aren't the source? don't change yourself + return + RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, PROC_REF(on_offset_increase)) + RegisterSignal(SSdcs, COMSIG_NARSIE_SUMMON_UPDATE, PROC_REF(narsie_modified)) + if(GLOB.narsie_summon_count >= 1) + narsie_start_midway(GLOB.narsie_effect_last_modified) // We assume we're on the start, so we can use this number + offset_increase(0, SSmapping.max_plane_offset) + +/atom/movable/screen/plane_master/parallax/proc/on_offset_increase(datum/source, old_offset, new_offset) + SIGNAL_HANDLER + offset_increase(old_offset, new_offset) + +/atom/movable/screen/plane_master/parallax/proc/offset_increase(old_offset, new_offset) + // Parallax will be mirrored down to any new planes that are added, so it will properly render across mirage borders + for(var/offset in old_offset to new_offset) + if(offset != 0) + // Overlay so we don't multiply twice, and thus fuck up our rendering + add_relay_to(GET_NEW_PLANE(plane, offset), BLEND_OVERLAY) + +// Hacky shit to ensure parallax works in perf mode +/atom/movable/screen/plane_master/parallax/outside_bounds(mob/relevant) + if(offset == 0) + remove_relay_from(GET_NEW_PLANE(RENDER_PLANE_GAME, 0)) + is_outside_bounds = TRUE // I'm sorry :( + return + // If we can't render, and we aren't the bottom layer, don't render us + // This way we only multiply against stuff that's not fullwhite space + var/atom/movable/screen/plane_master/parent_parallax = home.our_hud.get_plane_master(PLANE_SPACE_PARALLAX) + var/turf/viewing_turf = get_turf(relevant) + if(!viewing_turf || offset != GET_LOWEST_STACK_OFFSET(viewing_turf.z)) + parent_parallax.remove_relay_from(plane) + else + parent_parallax.add_relay_to(plane, BLEND_OVERLAY) + return ..() + +/atom/movable/screen/plane_master/parallax/inside_bounds(mob/relevant) + if(offset == 0) + add_relay_to(GET_NEW_PLANE(RENDER_PLANE_GAME, 0)) + is_outside_bounds = FALSE + return + // Always readd, just in case we lost it + var/atom/movable/screen/plane_master/parent_parallax = home.our_hud.get_plane_master(PLANE_SPACE_PARALLAX) + parent_parallax.add_relay_to(plane, BLEND_OVERLAY) + return ..() + +// Needs to handle rejoining on a lower z level, so we NEED to readd old planes +/atom/movable/screen/plane_master/parallax/check_outside_bounds() + // If we're outside bounds AND we're the 0th plane, we need to show cause parallax is hacked to hell + return offset != 0 && is_outside_bounds + +/// Starts the narsie animation midway, so we can catch up to everyone else quickly +/atom/movable/screen/plane_master/parallax/proc/narsie_start_midway(start_time) + var/time_elapsed = world.time - start_time + narsie_summoned_effect(max(16 SECONDS - time_elapsed, 0)) + +/// Starts the narsie animation, make us grey, then red +/atom/movable/screen/plane_master/parallax/proc/narsie_modified(datum/source, new_count) + SIGNAL_HANDLER + if(new_count >= 1) + narsie_summoned_effect(16 SECONDS) + else + narsie_unsummoned() + +/atom/movable/screen/plane_master/parallax/proc/narsie_summoned_effect(animate_time) + if(GLOB.narsie_summon_count >= 2) + var/static/list/nightmare_parallax = list(255,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, -130,0,0,0) + animate(src, color = nightmare_parallax, time = animate_time) + return + + var/static/list/grey_parallax = list(0.4,0.4,0.4,0, 0.4,0.4,0.4,0, 0.4,0.4,0.4,0, 0,0,0,1, -0.1,-0.1,-0.1,0) + // We're gonna animate ourselves grey + // Then, once it's done, about 40 seconds into the event itself, we're gonna start doin some shit. see below + animate(src, color = grey_parallax, time = animate_time) + +/atom/movable/screen/plane_master/parallax/proc/narsie_unsummoned() + animate(src, color = null, time = 8 SECONDS) diff --git a/code/_onclick/hud/rendering/plane_masters/pipecrawl.dm b/code/_onclick/hud/rendering/plane_masters/pipecrawl.dm new file mode 100644 index 00000000000000..cb75135e1a4914 --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/pipecrawl.dm @@ -0,0 +1,15 @@ +/atom/movable/screen/plane_master/pipecrawl + name = "Pipecrawl" + documentation = "Holds pipecrawl images generated during well, pipecrawling.\ +
Has a few effects and a funky color matrix designed to make things a bit more visually readable." + plane = PIPECRAWL_IMAGES_PLANE + start_hidden = TRUE + +/atom/movable/screen/plane_master/pipecrawl/Initialize(mapload, datum/hud/hud_owner) + . = ..() + // Makes everything on this plane slightly brighter + // Has a nice effect, makes thing stand out + color = list(1.2,0,0,0, 0,1.2,0,0, 0,0,1.2,0, 0,0,0,1, 0,0,0,0) + // This serves a similar purpose, I want the pipes to pop + add_filter("pipe_dropshadow", 1, drop_shadow_filter(x = -1, y= -1, size = 1, color = "#0000007A")) + mirror_parent_hidden() diff --git a/code/_onclick/hud/rendering/plane_masters/simple_plane_masters.dm b/code/_onclick/hud/rendering/plane_masters/simple_plane_masters.dm new file mode 100644 index 00000000000000..ea0ad21a773558 --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/simple_plane_masters.dm @@ -0,0 +1,82 @@ +/* + * Put plane masters that are just a simple type def in here, anything more complex should get its own file + */ + +/atom/movable/screen/plane_master/gravpulse + name = "Gravpulse" + documentation = "Ok so this one's fun. Basically, we want to be able to distort the game plane when a grav annom is around.\ +
So we draw the pattern we want to use to this plane, and it's then used as a render target by a distortion filter on the game plane.\ +
Note the blend mode and lack of relay targets. This plane exists only to distort, it's never rendered anywhere." + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + plane = GRAVITY_PULSE_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + blend_mode = BLEND_ADD + render_target = GRAVITY_PULSE_RENDER_TARGET + render_relay_planes = list() + +/atom/movable/screen/plane_master/seethrough + name = "Seethrough" + documentation = "Holds the seethrough versions (done using image overrides) of large objects. Mouse transparent, so you can click through them." + plane = SEETHROUGH_PLANE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + start_hidden = TRUE + +/atom/movable/screen/plane_master/massive_obj + name = "Massive object" + documentation = "Huge objects need to render above everything else on the game plane, otherwise they'd well, get clipped and look not that huge. This does that." + plane = MASSIVE_OBJ_PLANE + +/atom/movable/screen/plane_master/point + name = "Point" + documentation = "I mean like, what do you want me to say? Points draw over pretty much everything else, so they get their own plane. Remember we layer render relays to draw planes in their proper order on render plates." + plane = POINT_PLANE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + +/atom/movable/screen/plane_master/ghost + name = "Ghost" + documentation = "Ghosts draw here, so they don't get mixed up in the visuals of the game world. Note, this is not not how we HIDE ghosts from people, that's done with invisible and see_invisible." + plane = GHOST_PLANE + render_relay_planes = list(RENDER_PLANE_NON_GAME) + +/atom/movable/screen/plane_master/fullscreen + name = "Fullscreen" + documentation = "Holds anything that applies to or above the full screen. \ +
Note, it's still rendered underneath hud objects, but this lets us control the order that things like death/damage effects render in." + plane = FULLSCREEN_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_NON_GAME) + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + allows_offsetting = FALSE + +/atom/movable/screen/plane_master/hud + name = "HUD" + documentation = "Contains anything that want to be rendered on the hud. Typically is just screen elements." + plane = HUD_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_NON_GAME) + allows_offsetting = FALSE + +/atom/movable/screen/plane_master/above_hud + name = "Above HUD" + documentation = "Anything that wants to be drawn ABOVE the rest of the hud. Typically close buttons and other elements that need to be always visible. Think preventing draggable action button memes." + plane = ABOVE_HUD_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_NON_GAME) + allows_offsetting = FALSE + +/atom/movable/screen/plane_master/splashscreen + name = "Splashscreen" + documentation = "Cinematics and the splash screen." + plane = SPLASHSCREEN_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_NON_GAME) + allows_offsetting = FALSE + +/atom/movable/screen/plane_master/escape_menu + name = "Escape Menu" + documentation = "Anything relating to the escape menu." + plane = ESCAPE_MENU_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_MASTER) + allows_offsetting = FALSE diff --git a/code/controllers/subsystem/circuit_component.dm b/code/controllers/subsystem/circuit_component.dm index 3ef1be5a3aa322..bae302ed9d0a3c 100644 --- a/code/controllers/subsystem/circuit_component.dm +++ b/code/controllers/subsystem/circuit_component.dm @@ -39,7 +39,7 @@ SUBSYSTEM_DEF(circuit_component) * Those that registered first will be executed first and those registered last will be executed last. */ /datum/controller/subsystem/circuit_component/proc/add_callback(datum/port/input, datum/callback/to_call) - if(instant_run_tick == world.time && (TICK_USAGE - instant_run_start_cpu_usage) < instant_run_max_cpu_usage) + if(instant_run_tick == world.time && (TICK_USAGE - instant_run_start_cpu_usage) <= instant_run_max_cpu_usage) instant_run_callbacks_to_run += to_call return @@ -80,7 +80,7 @@ SUBSYSTEM_DEF(circuit_component) else instant_run_tick = 0 - if((TICK_USAGE - instant_run_start_cpu_usage) < instant_run_max_cpu_usage) + if((TICK_USAGE - instant_run_start_cpu_usage) <= instant_run_max_cpu_usage) return received_inputs else return null diff --git a/code/controllers/subsystem/economy.dm b/code/controllers/subsystem/economy.dm index 511a438bf9a60c..f047d17d944f0b 100644 --- a/code/controllers/subsystem/economy.dm +++ b/code/controllers/subsystem/economy.dm @@ -53,10 +53,6 @@ SUBSYSTEM_DEF(economy) */ var/list/audit_log = list() - /// Total value of exported materials. - var/export_total = 0 - /// Total value of imported goods. - var/import_total = 0 /// Number of mail items generated. var/mail_waiting = 0 /// Mail Holiday: AKA does mail arrive today? Always blocked on Sundays. diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 88112f9322676b..d21e2da97d2e74 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -359,75 +359,80 @@ SUBSYSTEM_DEF(garbage) /datum/qdel_item/New(mytype) name = "[mytype]" - /// Should be treated as a replacement for the 'del' keyword. /// /// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. -/proc/qdel(datum/D, force=FALSE, ...) - if(!istype(D)) - del(D) +/proc/qdel(datum/to_delete, force = FALSE, ...) + if(!istype(to_delete)) + del(to_delete) return - var/datum/qdel_item/I = SSgarbage.items[D.type] - if (!I) - I = SSgarbage.items[D.type] = new /datum/qdel_item(D.type) - I.qdels++ + var/datum/qdel_item/trash = SSgarbage.items[to_delete.type] + if (isnull(trash)) + trash = SSgarbage.items[to_delete.type] = new /datum/qdel_item(to_delete.type) + trash.qdels++ - if(isnull(D.gc_destroyed)) - if (SEND_SIGNAL(D, COMSIG_PREQDELETED, force)) // Give the components a chance to prevent their parent from being deleted - return - D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED - var/start_time = world.time - var/start_tick = world.tick_usage - SEND_SIGNAL(D, COMSIG_QDELETING, force) // Let the (remaining) components know about the result of Destroy - var/hint = D.Destroy(arglist(args.Copy(2))) // Let our friend know they're about to get fucked up. - if(world.time != start_time) - I.slept_destroy++ - else - I.destroy_time += TICK_USAGE_TO_MS(start_tick) - if(!D) + if(!isnull(to_delete.gc_destroyed)) + if(to_delete.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) + CRASH("[to_delete.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic") + return + + if (SEND_SIGNAL(to_delete, COMSIG_PREQDELETED, force)) // Give the components a chance to prevent their parent from being deleted + return + + to_delete.gc_destroyed = GC_CURRENTLY_BEING_QDELETED + var/start_time = world.time + var/start_tick = world.tick_usage + SEND_SIGNAL(to_delete, COMSIG_QDELETING, force) // Let the (remaining) components know about the result of Destroy + var/hint = to_delete.Destroy(arglist(args.Copy(2))) // Let our friend know they're about to get fucked up. + + if(world.time != start_time) + trash.slept_destroy++ + else + trash.destroy_time += TICK_USAGE_TO_MS(start_tick) + + if(isnull(to_delete)) + return + + switch(hint) + if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion. + SSgarbage.Queue(to_delete) + if (QDEL_HINT_IWILLGC) + to_delete.gc_destroyed = world.time return - switch(hint) - if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion. - SSgarbage.Queue(D) - if (QDEL_HINT_IWILLGC) - D.gc_destroyed = world.time + if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory. + if(!force) + to_delete.gc_destroyed = null //clear the gc variable (important!) return - if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory. - if(!force) - D.gc_destroyed = null //clear the gc variable (important!) - return - // Returning LETMELIVE after being told to force destroy - // indicates the objects Destroy() does not respect force - #ifdef TESTING - if(!I.no_respect_force) - testing("WARNING: [D.type] has been force deleted, but is \ - returning an immortal QDEL_HINT, indicating it does \ - not respect the force flag for qdel(). It has been \ - placed in the queue, further instances of this type \ - will also be queued.") - #endif - I.no_respect_force++ + // Returning LETMELIVE after being told to force destroy + // indicates the objects Destroy() does not respect force + #ifdef TESTING + if(!trash.no_respect_force) + testing("WARNING: [to_delete.type] has been force deleted, but is \ + returning an immortal QDEL_HINT, indicating it does \ + not respect the force flag for qdel(). It has been \ + placed in the queue, further instances of this type \ + will also be queued.") + #endif + trash.no_respect_force++ - SSgarbage.Queue(D) - if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete - SSgarbage.Queue(D, GC_QUEUE_HARDDELETE) - if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. - SSgarbage.HardDelete(D) - #ifdef REFERENCE_TRACKING - if (QDEL_HINT_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion. - SSgarbage.Queue(D) - INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references)) - if (QDEL_HINT_IFFAIL_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled and the object fails to collect, display all references to this object. - SSgarbage.Queue(D) - SSgarbage.reference_find_on_fail[text_ref(D)] = TRUE + SSgarbage.Queue(to_delete) + if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete + SSgarbage.Queue(to_delete, GC_QUEUE_HARDDELETE) + if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. + SSgarbage.HardDelete(to_delete) + #ifdef REFERENCE_TRACKING + if (QDEL_HINT_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion. + SSgarbage.Queue(to_delete) + INVOKE_ASYNC(to_delete, TYPE_PROC_REF(/datum, find_references)) + if (QDEL_HINT_IFFAIL_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled and the object fails to collect, display all references to this object. + SSgarbage.Queue(to_delete) + SSgarbage.reference_find_on_fail[text_ref(to_delete)] = TRUE + #endif + else + #ifdef TESTING + if(!trash.no_hint) + testing("WARNING: [to_delete.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.") #endif - else - #ifdef TESTING - if(!I.no_hint) - testing("WARNING: [D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.") - #endif - I.no_hint++ - SSgarbage.Queue(D) - else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) - CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic") + trash.no_hint++ + SSgarbage.Queue(to_delete) diff --git a/code/controllers/subsystem/movement/movement_types.dm b/code/controllers/subsystem/movement/movement_types.dm index 0b464a9a1960ce..6e18d35dd8ff44 100644 --- a/code/controllers/subsystem/movement/movement_types.dm +++ b/code/controllers/subsystem/movement/movement_types.dm @@ -367,7 +367,7 @@ ///Bool used to determine if we're already making a path in JPS. this prevents us from re-pathing while we're already busy. var/is_pathing = FALSE ///Callbacks to invoke once we make a path - var/list/datum/callback/on_finish_callbacks + var/list/datum/callback/on_finish_callbacks = list() /datum/move_loop/has_target/jps/New(datum/movement_packet/owner, datum/controller/subsystem/movement/controller, atom/moving, priority, flags, datum/extra_info) . = ..() diff --git a/code/controllers/subsystem/nightshift.dm b/code/controllers/subsystem/nightshift.dm index 78583cef3503ff..b8df42742e43c1 100644 --- a/code/controllers/subsystem/nightshift.dm +++ b/code/controllers/subsystem/nightshift.dm @@ -24,7 +24,12 @@ SUBSYSTEM_DEF(nightshift) check_nightshift() /datum/controller/subsystem/nightshift/proc/announce(message) - priority_announce(message, sound='sound/misc/notice2.ogg', sender_override="Automated Lighting System Announcement") + priority_announce( + text = message, + sound = 'sound/misc/notice2.ogg', + sender_override = "Automated Lighting System Announcement", + color_override = "grey", + ) /datum/controller/subsystem/nightshift/proc/check_nightshift() var/emergency = SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm deleted file mode 100644 index ce3c1f7619b016..00000000000000 --- a/code/controllers/subsystem/persistence.dm +++ /dev/null @@ -1,631 +0,0 @@ -#define FILE_RECENT_MAPS "data/RecentMaps.json" - -#define KEEP_ROUNDS_MAP 3 - -SUBSYSTEM_DEF(persistence) - name = "Persistence" - init_order = INIT_ORDER_PERSISTENCE - flags = SS_NO_FIRE - - ///instantiated wall engraving components - var/list/wall_engravings = list() - ///all saved persistent engravings loaded from JSON - var/list/saved_engravings = list() - ///tattoo stories that we're saving. - var/list/prison_tattoos_to_save = list() - ///tattoo stories that have been selected for this round. - var/list/prison_tattoos_to_use = list() - var/list/saved_messages = list() - var/list/saved_modes = list(1,2,3) - var/list/saved_maps = list() - var/list/blocked_maps = list() - var/list/saved_trophies = list() - var/list/picture_logging_information = list() - var/list/obj/structure/sign/picture_frame/photo_frames - var/list/obj/item/storage/photo_album/photo_albums - var/rounds_since_engine_exploded = 0 - var/delam_highscore = 0 - var/tram_hits_this_round = 0 - var/tram_hits_last_round = 0 - -/datum/controller/subsystem/persistence/Initialize() - load_poly() - load_wall_engravings() - load_prisoner_tattoos() - load_trophies() - load_recent_maps() - load_photo_persistence() - load_randomized_recipes() - load_custom_outfits() - load_delamination_counter() - load_tram_counter() - load_panic_bunker() //SKYRAT EDIT ADDITION - PANICBUNKER - load_adventures() - return SS_INIT_SUCCESS - -///Collects all data to persist. -/datum/controller/subsystem/persistence/proc/collect_data() - save_wall_engravings() - save_prisoner_tattoos() - collect_trophies() - collect_maps() - save_photo_persistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION. - save_randomized_recipes() - save_scars() - save_modular_persistence() // SKYRAT EDIT ADDITION - MODULAR_PERSISTENCE - save_custom_outfits() - save_delamination_counter() - if(SStransport.can_fire) - for(var/datum/transport_controller/linear/tram/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) - save_tram_history(transport.specific_transport_id) - save_tram_counter() - save_panic_bunker() //SKYRAT EDIT ADDITION - PANICBUNKER - -///Loads up Poly's speech buffer. -/datum/controller/subsystem/persistence/proc/load_poly() - for(var/mob/living/simple_animal/parrot/poly/P in GLOB.alive_mob_list) - twitterize(P.speech_buffer, "polytalk") - break //Who's been duping the bird?! - -///Loads all engravings, and places a select amount in maintenance and the prison. -/datum/controller/subsystem/persistence/proc/load_wall_engravings() - var/json_file = file(ENGRAVING_SAVE_FILE) - if(!fexists(json_file)) - return - - var/list/json = json_decode(file2text(json_file)) - if(!json) - return - - if(json["version"] < ENGRAVING_PERSISTENCE_VERSION) - update_wall_engravings(json) - - saved_engravings = json["entries"] - - if(!saved_engravings.len) - log_world("Failed to load engraved messages on map [SSmapping.config.map_name]") - return - - var/list/viable_turfs = get_area_turfs(/area/station/maintenance, subtypes = TRUE) + get_area_turfs(/area/station/security/prison, subtypes = TRUE) - var/list/turfs_to_pick_from = list() - - for(var/turf/T as anything in viable_turfs) - if(!isclosedturf(T)) - continue - turfs_to_pick_from += T - - var/successfully_loaded_engravings = 0 - - for(var/iteration in 1 to rand(MIN_PERSISTENT_ENGRAVINGS, MAX_PERSISTENT_ENGRAVINGS)) - var/engraving = pick_n_take(saved_engravings) - if(!islist(engraving)) - stack_trace("something's wrong with the engraving data! one of the saved engravings wasn't a list!") - continue - - var/turf/closed/engraved_wall = pick(turfs_to_pick_from) - - if(HAS_TRAIT(engraved_wall, TRAIT_NOT_ENGRAVABLE)) - continue - - engraved_wall.AddComponent(/datum/component/engraved, engraving["story"], FALSE, engraving["story_value"]) - successfully_loaded_engravings++ - turfs_to_pick_from -= engraved_wall - - log_world("Loaded [successfully_loaded_engravings] engraved messages on map [SSmapping.config.map_name]") - -///Saves all new engravings in the world. -/datum/controller/subsystem/persistence/proc/save_wall_engravings() - var/list/saved_data = list() - - saved_data["version"] = ENGRAVING_PERSISTENCE_VERSION - saved_data["entries"] = list() - - - var/json_file = file(ENGRAVING_SAVE_FILE) - if(fexists(json_file)) - var/list/old_json = json_decode(file2text(json_file)) - if(old_json) - saved_data["entries"] = old_json["entries"] - - for(var/datum/component/engraved/engraving in wall_engravings) - if(!engraving.persistent_save) - continue - var/area/engraved_area = get_area(engraving.parent) - if(!(engraved_area.area_flags & PERSISTENT_ENGRAVINGS)) - continue - saved_data["entries"] += engraving.save_persistent() - - fdel(json_file) - - WRITE_FILE(json_file, json_encode(saved_data)) - -///This proc can update entries if the format has changed at some point. -/datum/controller/subsystem/persistence/proc/update_wall_engravings(json) - for(var/engraving_entry in json["entries"]) - continue //no versioning yet - - //Save it to the file - var/json_file = file(ENGRAVING_SAVE_FILE) - fdel(json_file) - WRITE_FILE(json_file, json_encode(json)) - - return json - -///Loads all tattoos, and select a few based on the amount of prisoner spawn positions. -/datum/controller/subsystem/persistence/proc/load_prisoner_tattoos() - var/json_file = file(PRISONER_TATTOO_SAVE_FILE) - if(!fexists(json_file)) - return - var/list/json = json_decode(file2text(json_file)) - if(!json) - return - - if(json["version"] < TATTOO_PERSISTENCE_VERSION) - update_prisoner_tattoos(json) - - var/datum/job/prisoner_datum = SSjob.name_occupations[JOB_PRISONER] - if(!prisoner_datum) - return - var/iterations_allowed = prisoner_datum.spawn_positions - - var/list/entries = json["entries"] - if(entries.len) - for(var/index in 1 to iterations_allowed) - prison_tattoos_to_use += list(entries[rand(1, entries.len)]) - - log_world("Loaded [prison_tattoos_to_use.len] prison tattoos") - -///Saves all tattoos, so they can appear on prisoners in future rounds -/datum/controller/subsystem/persistence/proc/save_prisoner_tattoos() - var/json_file = file(PRISONER_TATTOO_SAVE_FILE) - var/list/saved_data = list() - var/list/entries = list() - - if(fexists(json_file)) - var/list/old_json = json_decode(file2text(json_file)) - if(old_json) - entries += old_json["entries"] //Save the old if its there - - entries += prison_tattoos_to_save - - saved_data["version"] = ENGRAVING_PERSISTENCE_VERSION - saved_data["entries"] = entries - - fdel(json_file) - WRITE_FILE(json_file, json_encode(saved_data)) - -///This proc can update entries if the format has changed at some point. -/datum/controller/subsystem/persistence/proc/update_prisoner_tattoos(json) - for(var/tattoo_entry in json["entries"]) - continue //no versioning yet - - //Save it to the file - var/json_file = file(PRISONER_TATTOO_SAVE_FILE) - fdel(json_file) - WRITE_FILE(json_file, json_encode(json)) - - return json - -/// Loads the trophies from the source file, and places a few in trophy display cases. -/datum/controller/subsystem/persistence/proc/load_trophies() - var/list/raw_saved_trophies = list() - if(fexists("data/npc_saves/TrophyItems.json")) - var/json_file = file("data/npc_saves/TrophyItems.json") - if(!fexists(json_file)) - return - var/list/json = json_decode(file2text(json_file)) - if(!json) - return - raw_saved_trophies = json["data"] - fdel("data/npc_saves/TrophyItems.json") - else - var/json_file = file("data/trophy_items.json") - if(!fexists(json_file)) - return - var/list/json = json_decode(file2text(json_file)) - if(!json) - return - raw_saved_trophies = json["data"] - - for(var/raw_json in raw_saved_trophies) - var/datum/trophy_data/parsed_trophy_data = new - parsed_trophy_data.load_from_json(raw_json) - saved_trophies += parsed_trophy_data - - set_up_trophies() - -///trophy data datum, for admin manipulation -/datum/trophy_data - ///path of the item the trophy will try to mimic, null if path_string is invalid - var/path - ///the message that appears under the item - var/message - ///the key of the one who placed the item in the trophy case - var/placer_key - -/datum/trophy_data/proc/load_from_json(list/json_data) - path = json_data["path"] - message = json_data["message"] - placer_key = json_data["placer_key"] - -/datum/trophy_data/proc/to_json() - var/list/new_data = list() - new_data["path"] = path - new_data["message"] = message - new_data["placer_key"] = placer_key - new_data["is_valid"] = text2path(path) ? TRUE : FALSE - return new_data - -/// Returns a list for the admin trophy panel. -/datum/controller/subsystem/persistence/proc/trophy_ui_data() - var/list/ui_data = list() - for(var/datum/trophy_data/data in saved_trophies) - var/list/pdata = data.to_json() - pdata["ref"] = REF(data) - ui_data += list(pdata) - - return ui_data - -/// Loads up the amount of times maps appeared to alter their appearance in voting and rotation. -/datum/controller/subsystem/persistence/proc/load_recent_maps() - var/map_sav = FILE_RECENT_MAPS - if(!fexists(FILE_RECENT_MAPS)) - return - var/list/json = json_decode(file2text(map_sav)) - if(!json) - return - saved_maps = json["data"] - - //Convert the mapping data to a shared blocking list, saves us doing this in several places later. - for(var/map in config.maplist) - var/datum/map_config/VM = config.maplist[map] - var/run = 0 - if(VM.map_name == SSmapping.config.map_name) - run++ - for(var/name in SSpersistence.saved_maps) - if(VM.map_name == name) - run++ - if(run >= 2) //If run twice in the last KEEP_ROUNDS_MAP + 1 (including current) rounds, disable map for voting and rotation. - blocked_maps += VM.map_name - -/// Puts trophies into trophy cases. -/datum/controller/subsystem/persistence/proc/set_up_trophies() - - var/list/valid_trophies = list() - - for(var/datum/trophy_data/data in saved_trophies) - - if(!data) //sanity for incorrect deserialization - continue - - var/path = text2path(data.path) - if(!path) //If the item no longer exist, ignore it - continue - - valid_trophies += data - - for(var/obj/structure/displaycase/trophy/trophy_case in GLOB.trophy_cases) - if(!valid_trophies.len) - break - - if(trophy_case.showpiece) - continue - - trophy_case.set_up_trophy(pick_n_take(valid_trophies)) - -///Loads up the photo album source file. -/datum/controller/subsystem/persistence/proc/get_photo_albums() - var/album_path = file("data/photo_albums.json") - if(fexists(album_path)) - return json_decode(file2text(album_path)) - -///Loads up the photo frames source file. -/datum/controller/subsystem/persistence/proc/get_photo_frames() - var/frame_path = file("data/photo_frames.json") - if(fexists(frame_path)) - return json_decode(file2text(frame_path)) - -/// Removes the identifier of a persistent photo frame from the json. -/datum/controller/subsystem/persistence/proc/remove_photo_frames(identifier) - var/frame_path = file("data/photo_frames.json") - if(!fexists(frame_path)) - return - - var/frame_json = json_decode(file2text(frame_path)) - frame_json -= identifier - - frame_json = json_encode(frame_json) - fdel(frame_path) - WRITE_FILE(frame_path, frame_json) - -///Loads photo albums, and populates them; also loads and applies frames to picture frames. -/datum/controller/subsystem/persistence/proc/load_photo_persistence() - var/album_path = file("data/photo_albums.json") - var/frame_path = file("data/photo_frames.json") - if(fexists(album_path)) - var/list/json = json_decode(file2text(album_path)) - if(json.len) - for(var/i in photo_albums) - var/obj/item/storage/photo_album/A = i - if(!A.persistence_id) - continue - if(json[A.persistence_id]) - A.populate_from_id_list(json[A.persistence_id]) - - if(fexists(frame_path)) - var/list/json = json_decode(file2text(frame_path)) - if(json.len) - for(var/i in photo_frames) - var/obj/structure/sign/picture_frame/PF = i - if(!PF.persistence_id) - continue - if(json[PF.persistence_id]) - PF.load_from_id(json[PF.persistence_id]) - -///Saves the contents of photo albums and the picture frames. -/datum/controller/subsystem/persistence/proc/save_photo_persistence() - var/album_path = file("data/photo_albums.json") - var/frame_path = file("data/photo_frames.json") - - var/list/frame_json = list() - var/list/album_json = list() - - if(fexists(album_path)) - album_json = json_decode(file2text(album_path)) - fdel(album_path) - - for(var/i in photo_albums) - var/obj/item/storage/photo_album/A = i - if(!istype(A) || !A.persistence_id) - continue - var/list/L = A.get_picture_id_list() - album_json[A.persistence_id] = L - - album_json = json_encode(album_json) - - WRITE_FILE(album_path, album_json) - - if(fexists(frame_path)) - frame_json = json_decode(file2text(frame_path)) - fdel(frame_path) - - for(var/i in photo_frames) - var/obj/structure/sign/picture_frame/F = i - if(!istype(F) || !F.persistence_id) - continue - frame_json[F.persistence_id] = F.get_photo_id() - - frame_json = json_encode(frame_json) - - WRITE_FILE(frame_path, frame_json) - -///Collects trophies from all existing trophy cases. -/datum/controller/subsystem/persistence/proc/collect_trophies() - for(var/trophy_case in GLOB.trophy_cases) - save_trophy(trophy_case) - - var/json_file = file("data/trophy_items.json") - var/list/file_data = list() - var/list/converted_data = list() - - for(var/datum/trophy_data/data in saved_trophies) - converted_data += list(data.to_json()) - - converted_data = remove_duplicate_trophies(converted_data) - - file_data["data"] = converted_data - fdel(json_file) - WRITE_FILE(json_file, json_encode(file_data)) - -///gets the list of json trophies, and deletes the ones with an identical path and message -/datum/controller/subsystem/persistence/proc/remove_duplicate_trophies(list/trophies) - var/list/ukeys = list() - . = list() - for(var/trophy in trophies) - var/tkey = "[trophy["path"]]-[trophy["message"]]" - if(ukeys[tkey]) - continue - else - . += list(trophy) - ukeys[tkey] = TRUE - -///If there is a trophy in the trophy case, saved it, if the trophy was not a holo trophy and has a message attached. -/datum/controller/subsystem/persistence/proc/save_trophy(obj/structure/displaycase/trophy/trophy_case) - if(!trophy_case.holographic_showpiece && trophy_case.showpiece && trophy_case.trophy_message) - var/datum/trophy_data/data = new - data.path = trophy_case.showpiece.type - data.message = trophy_case.trophy_message - data.placer_key = trophy_case.placer_key - saved_trophies += data - -///Updates the list of the most recent maps. -/datum/controller/subsystem/persistence/proc/collect_maps() - if(length(saved_maps) > KEEP_ROUNDS_MAP) //Get rid of extras from old configs. - saved_maps.Cut(KEEP_ROUNDS_MAP+1) - var/mapstosave = min(length(saved_maps)+1, KEEP_ROUNDS_MAP) - if(length(saved_maps) < mapstosave) //Add extras if too short, one per round. - saved_maps += mapstosave - for(var/i = mapstosave; i > 1; i--) - saved_maps[i] = saved_maps[i-1] - saved_maps[1] = SSmapping.config.map_name - var/json_file = file(FILE_RECENT_MAPS) - var/list/file_data = list() - file_data["data"] = saved_maps - fdel(json_file) - WRITE_FILE(json_file, json_encode(file_data)) - -///Loads all randomized recipes. -/datum/controller/subsystem/persistence/proc/load_randomized_recipes() - var/json_file = file("data/RandomizedChemRecipes.json") - var/json - if(fexists(json_file)) - json = json_decode(file2text(json_file)) - - for(var/randomized_type in subtypesof(/datum/chemical_reaction/randomized)) - var/datum/chemical_reaction/randomized/R = new randomized_type - var/loaded = FALSE - if(R.persistent && json) - var/list/recipe_data = json["[R.type]"] - if(recipe_data) - if(R.LoadOldRecipe(recipe_data) && (daysSince(R.created) <= R.persistence_period)) - loaded = TRUE - if(!loaded) //We do not have information for whatever reason, just generate new one - if(R.persistent) - log_game("Resetting persistent [randomized_type] random recipe.") - R.GenerateRecipe() - - if(!R.HasConflicts()) //Might want to try again if conflicts happened in the future. - add_chemical_reaction(R) - else - log_game("Randomized recipe [randomized_type] resulted in conflicting recipes.") - -///Saves all randomized recipes. -/datum/controller/subsystem/persistence/proc/save_randomized_recipes() - var/json_file = file("data/RandomizedChemRecipes.json") - var/list/file_data = list() - - //asert globchems done - for(var/randomized_type in subtypesof(/datum/chemical_reaction/randomized)) - var/datum/chemical_reaction/randomized/R = get_chemical_reaction(randomized_type) //ew, would be nice to add some simple tracking - if(R?.persistent) - var/list/recipe_data = R.SaveOldRecipe() - file_data["[R.type]"] = recipe_data - - fdel(json_file) - WRITE_FILE(json_file, json_encode(file_data)) - -///Saves all scars for everyone's original characters -/datum/controller/subsystem/persistence/proc/save_scars() - for(var/i in GLOB.joined_player_list) - var/mob/living/carbon/human/ending_human = get_mob_by_ckey(i) - if(!istype(ending_human) || !ending_human.mind?.original_character_slot_index || !ending_human.client?.prefs.read_preference(/datum/preference/toggle/persistent_scars)) - continue - - var/mob/living/carbon/human/original_human = ending_human.mind.original_character.resolve() - - if(!original_human) - continue - - if(original_human.stat == DEAD || !original_human.all_scars || original_human != ending_human) - original_human.save_persistent_scars(TRUE) - else - original_human.save_persistent_scars() - -///Loads the custom outfits of every admin. -/datum/controller/subsystem/persistence/proc/load_custom_outfits() - var/file = file("data/custom_outfits.json") - if(!fexists(file)) - return - var/outfits_json = file2text(file) - var/list/outfits = json_decode(outfits_json) - if(!islist(outfits)) - return - - for(var/outfit_data in outfits) - if(!islist(outfit_data)) - continue - - var/outfittype = text2path(outfit_data["outfit_type"]) - if(!ispath(outfittype, /datum/outfit)) - continue - var/datum/outfit/outfit = new outfittype - if(!outfit.load_from(outfit_data)) - continue - GLOB.custom_outfits += outfit - -///Saves each admin's custom outfit list -/datum/controller/subsystem/persistence/proc/save_custom_outfits() - var/file = file("data/custom_outfits.json") - fdel(file) - - var/list/data = list() - for(var/datum/outfit/outfit in GLOB.custom_outfits) - data += list(outfit.get_json_data()) - - WRITE_FILE(file, json_encode(data)) - -/// Location where we save the information about how many rounds it has been since the engine blew up/tram hits -#define DELAMINATION_COUNT_FILEPATH "data/rounds_since_delamination.txt" -#define DELAMINATION_HIGHSCORE_FILEPATH "data/delamination_highscore.txt" -#define TRAM_COUNT_FILEPATH "data/tram_hits_last_round.txt" - -/datum/controller/subsystem/persistence/proc/load_delamination_counter() - if (!fexists(DELAMINATION_COUNT_FILEPATH)) - return - rounds_since_engine_exploded = text2num(file2text(DELAMINATION_COUNT_FILEPATH)) - if (fexists(DELAMINATION_HIGHSCORE_FILEPATH)) - delam_highscore = text2num(file2text(DELAMINATION_HIGHSCORE_FILEPATH)) - for (var/obj/machinery/incident_display/sign as anything in GLOB.map_delamination_counters) - sign.update_delam_count(rounds_since_engine_exploded, delam_highscore) - -/datum/controller/subsystem/persistence/proc/save_delamination_counter() - rustg_file_write("[rounds_since_engine_exploded + 1]", DELAMINATION_COUNT_FILEPATH) - if((rounds_since_engine_exploded + 1) > delam_highscore) - rustg_file_write("[rounds_since_engine_exploded + 1]", DELAMINATION_HIGHSCORE_FILEPATH) - -/datum/controller/subsystem/persistence/proc/load_tram_counter() - if(!fexists(TRAM_COUNT_FILEPATH)) - return - tram_hits_last_round = text2num(file2text(TRAM_COUNT_FILEPATH)) - -/datum/controller/subsystem/persistence/proc/save_tram_counter() - rustg_file_write("[tram_hits_this_round]", TRAM_COUNT_FILEPATH) - -#define MAX_TRAM_SAVES 4 - -// Loads historical tram data -/datum/controller/subsystem/persistence/proc/load_tram_history(specific_transport_id) - var/list/raw_saved_trams = list() - var/json_file = file("data/tram_data/[specific_transport_id].json") - if(!fexists(json_file)) - return - var/list/json = json_decode(file2text(json_file)) - if(!json) - return - raw_saved_trams = json["data"] - - var/list/previous_tram_data = list() - for(var/raw_json in raw_saved_trams) - var/datum/tram_mfg_info/parsed_tram_data = new - parsed_tram_data.load_from_json(raw_json) - previous_tram_data += parsed_tram_data - return previous_tram_data - -// Saves historical tram data -/datum/controller/subsystem/persistence/proc/save_tram_history(specific_transport_id) - var/list/packaged_tram_data = list() - for(var/datum/transport_controller/linear/tram/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) - if(transport.specific_transport_id == specific_transport_id) - packaged_tram_data = package_tram_data(transport) - break - - var/json_file = file("data/tram_data/[specific_transport_id].json") - var/list/file_data = list() - var/list/converted_data = list() - - for(var/datum/tram_mfg_info/data in packaged_tram_data) - converted_data += list(data.export_to_json()) - - file_data["data"] = converted_data - fdel(json_file) - WRITE_FILE(json_file, json_encode(file_data)) - -/datum/controller/subsystem/persistence/proc/package_tram_data(datum/transport_controller/linear/tram/tram_controller) - var/list/packaged_data = list() - var/list/tram_list = tram_controller.tram_history - if(!isnull(tram_list)) - while(tram_list.len > MAX_TRAM_SAVES) - tram_list.Cut(1,2) - - for(var/datum/tram_mfg_info/data as anything in tram_list) - packaged_data += data - - packaged_data += tram_controller.tram_registration - return packaged_data - -#undef DELAMINATION_COUNT_FILEPATH -#undef DELAMINATION_HIGHSCORE_FILEPATH -#undef TRAM_COUNT_FILEPATH -#undef FILE_RECENT_MAPS -#undef KEEP_ROUNDS_MAP -#undef MAX_TRAM_SAVES diff --git a/code/controllers/subsystem/persistence/_persistence.dm b/code/controllers/subsystem/persistence/_persistence.dm new file mode 100644 index 00000000000000..c98be5d1c5a96d --- /dev/null +++ b/code/controllers/subsystem/persistence/_persistence.dm @@ -0,0 +1,108 @@ +#define FILE_RECENT_MAPS "data/RecentMaps.json" +#define KEEP_ROUNDS_MAP 3 + +SUBSYSTEM_DEF(persistence) + name = "Persistence" + init_order = INIT_ORDER_PERSISTENCE + flags = SS_NO_FIRE + + ///instantiated wall engraving components + var/list/wall_engravings = list() + ///all saved persistent engravings loaded from JSON + var/list/saved_engravings = list() + ///tattoo stories that we're saving. + var/list/prison_tattoos_to_save = list() + ///tattoo stories that have been selected for this round. + var/list/prison_tattoos_to_use = list() + var/list/saved_messages = list() + var/list/saved_modes = list(1,2,3) + var/list/saved_maps = list() + var/list/blocked_maps = list() + var/list/saved_trophies = list() + var/list/picture_logging_information = list() + var/list/obj/structure/sign/picture_frame/photo_frames + var/list/obj/item/storage/photo_album/photo_albums + var/rounds_since_engine_exploded = 0 + var/delam_highscore = 0 + var/tram_hits_this_round = 0 + var/tram_hits_last_round = 0 + +/datum/controller/subsystem/persistence/Initialize() + load_poly() + load_wall_engravings() + load_prisoner_tattoos() + load_trophies() + load_recent_maps() + load_photo_persistence() + load_randomized_recipes() + load_custom_outfits() + load_delamination_counter() + load_panic_bunker() //SKYRAT EDIT ADDITION - PANICBUNKER + load_tram_counter() + load_adventures() + return SS_INIT_SUCCESS + +///Collects all data to persist. +/datum/controller/subsystem/persistence/proc/collect_data() + save_wall_engravings() + save_prisoner_tattoos() + collect_trophies() + collect_maps() + save_photo_persistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION. + save_randomized_recipes() + save_scars() + save_custom_outfits() + save_modular_persistence() // SKYRAT EDIT ADDITION - MODULAR_PERSISTENCE + save_delamination_counter() + if(SStransport.can_fire) + for(var/datum/transport_controller/linear/tram/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + save_tram_history(transport.specific_transport_id) + save_tram_counter() + save_panic_bunker() //SKYRAT EDIT ADDITION - PANICBUNKER + +///Loads up Poly's speech buffer. +/datum/controller/subsystem/persistence/proc/load_poly() + for(var/mob/living/simple_animal/parrot/poly/P in GLOB.alive_mob_list) + twitterize(P.speech_buffer, "polytalk") + break //Who's been duping the bird?! + +/// Loads up the amount of times maps appeared to alter their appearance in voting and rotation. +/datum/controller/subsystem/persistence/proc/load_recent_maps() + var/map_sav = FILE_RECENT_MAPS + if(!fexists(FILE_RECENT_MAPS)) + return + var/list/json = json_decode(file2text(map_sav)) + if(!json) + return + saved_maps = json["data"] + + //Convert the mapping data to a shared blocking list, saves us doing this in several places later. + for(var/map in config.maplist) + var/datum/map_config/VM = config.maplist[map] + var/run = 0 + if(VM.map_name == SSmapping.config.map_name) + run++ + for(var/name in SSpersistence.saved_maps) + if(VM.map_name == name) + run++ + if(run >= 2) //If run twice in the last KEEP_ROUNDS_MAP + 1 (including current) rounds, disable map for voting and rotation. + blocked_maps += VM.map_name + +///Updates the list of the most recent maps. +/datum/controller/subsystem/persistence/proc/collect_maps() + if(length(saved_maps) > KEEP_ROUNDS_MAP) //Get rid of extras from old configs. + saved_maps.Cut(KEEP_ROUNDS_MAP+1) + var/mapstosave = min(length(saved_maps)+1, KEEP_ROUNDS_MAP) + if(length(saved_maps) < mapstosave) //Add extras if too short, one per round. + saved_maps += mapstosave + for(var/i = mapstosave; i > 1; i--) + saved_maps[i] = saved_maps[i-1] + saved_maps[1] = SSmapping.config.map_name + var/json_file = file(FILE_RECENT_MAPS) + var/list/file_data = list() + file_data["data"] = saved_maps + fdel(json_file) + WRITE_FILE(json_file, json_encode(file_data)) + +#undef FILE_RECENT_MAPS +#undef KEEP_ROUNDS_MAP diff --git a/code/controllers/subsystem/persistence/counter_delamination.dm b/code/controllers/subsystem/persistence/counter_delamination.dm new file mode 100644 index 00000000000000..81dca300c7e1ee --- /dev/null +++ b/code/controllers/subsystem/persistence/counter_delamination.dm @@ -0,0 +1,20 @@ +/// Location where we save the information about how many rounds it has been since the engine blew up +#define DELAMINATION_COUNT_FILEPATH "data/rounds_since_delamination.txt" +#define DELAMINATION_HIGHSCORE_FILEPATH "data/delamination_highscore.txt" + +/datum/controller/subsystem/persistence/proc/load_delamination_counter() + if(!fexists(DELAMINATION_COUNT_FILEPATH)) + return + rounds_since_engine_exploded = text2num(file2text(DELAMINATION_COUNT_FILEPATH)) + if(fexists(DELAMINATION_HIGHSCORE_FILEPATH)) + delam_highscore = text2num(file2text(DELAMINATION_HIGHSCORE_FILEPATH)) + for(var/obj/machinery/incident_display/sign as anything in GLOB.map_delamination_counters) + sign.update_delam_count(rounds_since_engine_exploded, delam_highscore) + +/datum/controller/subsystem/persistence/proc/save_delamination_counter() + rustg_file_write("[rounds_since_engine_exploded + 1]", DELAMINATION_COUNT_FILEPATH) + if((rounds_since_engine_exploded + 1) > delam_highscore) + rustg_file_write("[rounds_since_engine_exploded + 1]", DELAMINATION_HIGHSCORE_FILEPATH) + +#undef DELAMINATION_COUNT_FILEPATH +#undef DELAMINATION_HIGHSCORE_FILEPATH diff --git a/code/controllers/subsystem/persistence/counter_tram_hits.dm b/code/controllers/subsystem/persistence/counter_tram_hits.dm new file mode 100644 index 00000000000000..806d5d5b5c2cc5 --- /dev/null +++ b/code/controllers/subsystem/persistence/counter_tram_hits.dm @@ -0,0 +1,64 @@ +/// Location where we save the information about how many times the tram hit on previous round +#define TRAM_COUNT_FILEPATH "data/tram_hits_last_round.txt" +#define MAX_TRAM_SAVES 4 + +// Loads historical tram data +/datum/controller/subsystem/persistence/proc/load_tram_history(specific_transport_id) + var/list/raw_saved_trams = list() + var/json_file = file("data/tram_data/[specific_transport_id].json") + if(!fexists(json_file)) + return + var/list/json = json_decode(file2text(json_file)) + if(!json) + return + raw_saved_trams = json["data"] + + var/list/previous_tram_data = list() + for(var/raw_json in raw_saved_trams) + var/datum/tram_mfg_info/parsed_tram_data = new + parsed_tram_data.load_from_json(raw_json) + previous_tram_data += parsed_tram_data + return previous_tram_data + +// Saves historical tram data +/datum/controller/subsystem/persistence/proc/save_tram_history(specific_transport_id) + var/list/packaged_tram_data = list() + for(var/datum/transport_controller/linear/tram/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) + if(transport.specific_transport_id == specific_transport_id) + packaged_tram_data = package_tram_data(transport) + break + + var/json_file = file("data/tram_data/[specific_transport_id].json") + var/list/file_data = list() + var/list/converted_data = list() + + for(var/datum/tram_mfg_info/data in packaged_tram_data) + converted_data += list(data.export_to_json()) + + file_data["data"] = converted_data + fdel(json_file) + WRITE_FILE(json_file, json_encode(file_data)) + +/datum/controller/subsystem/persistence/proc/package_tram_data(datum/transport_controller/linear/tram/tram_controller) + var/list/packaged_data = list() + var/list/tram_list = tram_controller.tram_history + if(!isnull(tram_list)) + while(tram_list.len > MAX_TRAM_SAVES) + tram_list.Cut(1,2) + + for(var/datum/tram_mfg_info/data as anything in tram_list) + packaged_data += data + + packaged_data += tram_controller.tram_registration + return packaged_data + +/datum/controller/subsystem/persistence/proc/load_tram_counter() + if(!fexists(TRAM_COUNT_FILEPATH)) + return + tram_hits_last_round = text2num(file2text(TRAM_COUNT_FILEPATH)) + +/datum/controller/subsystem/persistence/proc/save_tram_counter() + rustg_file_write("[tram_hits_this_round]", TRAM_COUNT_FILEPATH) + +#undef TRAM_COUNT_FILEPATH +#undef MAX_TRAM_SAVES diff --git a/code/controllers/subsystem/persistence/custom_outfits.dm b/code/controllers/subsystem/persistence/custom_outfits.dm new file mode 100644 index 00000000000000..942f874fde5e59 --- /dev/null +++ b/code/controllers/subsystem/persistence/custom_outfits.dm @@ -0,0 +1,32 @@ +///Loads the custom outfits of every admin. +/datum/controller/subsystem/persistence/proc/load_custom_outfits() + var/file = file("data/custom_outfits.json") + if(!fexists(file)) + return + var/outfits_json = file2text(file) + var/list/outfits = json_decode(outfits_json) + if(!islist(outfits)) + return + + for(var/outfit_data in outfits) + if(!islist(outfit_data)) + continue + + var/outfittype = text2path(outfit_data["outfit_type"]) + if(!ispath(outfittype, /datum/outfit)) + continue + var/datum/outfit/outfit = new outfittype + if(!outfit.load_from(outfit_data)) + continue + GLOB.custom_outfits += outfit + +///Saves each admin's custom outfit list +/datum/controller/subsystem/persistence/proc/save_custom_outfits() + var/file = file("data/custom_outfits.json") + fdel(file) + + var/list/data = list() + for(var/datum/outfit/outfit in GLOB.custom_outfits) + data += list(outfit.get_json_data()) + + WRITE_FILE(file, json_encode(data)) diff --git a/code/controllers/subsystem/persistence/engravings.dm b/code/controllers/subsystem/persistence/engravings.dm new file mode 100644 index 00000000000000..f47fc7fbba124c --- /dev/null +++ b/code/controllers/subsystem/persistence/engravings.dm @@ -0,0 +1,84 @@ +///Loads all engravings, and places a select amount in maintenance and the prison. +/datum/controller/subsystem/persistence/proc/load_wall_engravings() + var/json_file = file(ENGRAVING_SAVE_FILE) + if(!fexists(json_file)) + return + + var/list/json = json_decode(file2text(json_file)) + if(!json) + return + + if(json["version"] < ENGRAVING_PERSISTENCE_VERSION) + update_wall_engravings(json) + + saved_engravings = json["entries"] + + if(!saved_engravings.len) + log_world("Failed to load engraved messages on map [SSmapping.config.map_name]") + return + + var/list/viable_turfs = get_area_turfs(/area/station/maintenance, subtypes = TRUE) + get_area_turfs(/area/station/security/prison, subtypes = TRUE) + var/list/turfs_to_pick_from = list() + + for(var/turf/T as anything in viable_turfs) + if(!isclosedturf(T)) + continue + turfs_to_pick_from += T + + var/successfully_loaded_engravings = 0 + + for(var/iteration in 1 to rand(MIN_PERSISTENT_ENGRAVINGS, MAX_PERSISTENT_ENGRAVINGS)) + var/engraving = pick_n_take(saved_engravings) + if(!islist(engraving)) + stack_trace("something's wrong with the engraving data! one of the saved engravings wasn't a list!") + continue + + var/turf/closed/engraved_wall = pick(turfs_to_pick_from) + + if(HAS_TRAIT(engraved_wall, TRAIT_NOT_ENGRAVABLE)) + continue + + engraved_wall.AddComponent(/datum/component/engraved, engraving["story"], FALSE, engraving["story_value"]) + successfully_loaded_engravings++ + turfs_to_pick_from -= engraved_wall + + log_world("Loaded [successfully_loaded_engravings] engraved messages on map [SSmapping.config.map_name]") + +///Saves all new engravings in the world. +/datum/controller/subsystem/persistence/proc/save_wall_engravings() + var/list/saved_data = list() + + saved_data["version"] = ENGRAVING_PERSISTENCE_VERSION + saved_data["entries"] = list() + + + var/json_file = file(ENGRAVING_SAVE_FILE) + if(fexists(json_file)) + var/list/old_json = json_decode(file2text(json_file)) + if(old_json) + saved_data["entries"] = old_json["entries"] + + for(var/datum/component/engraved/engraving in wall_engravings) + if(!engraving.persistent_save) + continue + var/area/engraved_area = get_area(engraving.parent) + if(!(engraved_area.area_flags & PERSISTENT_ENGRAVINGS)) + continue + saved_data["entries"] += engraving.save_persistent() + + fdel(json_file) + + WRITE_FILE(json_file, json_encode(saved_data)) + +///This proc can update entries if the format has changed at some point. +/datum/controller/subsystem/persistence/proc/update_wall_engravings(json) + for(var/engraving_entry in json["entries"]) + continue //no versioning yet + + //Save it to the file + var/json_file = file(ENGRAVING_SAVE_FILE) + fdel(json_file) + WRITE_FILE(json_file, json_encode(json)) + + return json + diff --git a/code/controllers/subsystem/persistence/photo_albums.dm b/code/controllers/subsystem/persistence/photo_albums.dm new file mode 100644 index 00000000000000..3aee856b2c21ce --- /dev/null +++ b/code/controllers/subsystem/persistence/photo_albums.dm @@ -0,0 +1,86 @@ +///Loads up the photo album source file. +/datum/controller/subsystem/persistence/proc/get_photo_albums() + var/album_path = file("data/photo_albums.json") + if(fexists(album_path)) + return json_decode(file2text(album_path)) + +///Loads up the photo frames source file. +/datum/controller/subsystem/persistence/proc/get_photo_frames() + var/frame_path = file("data/photo_frames.json") + if(fexists(frame_path)) + return json_decode(file2text(frame_path)) + +/// Removes the identifier of a persistent photo frame from the json. +/datum/controller/subsystem/persistence/proc/remove_photo_frames(identifier) + var/frame_path = file("data/photo_frames.json") + if(!fexists(frame_path)) + return + + var/frame_json = json_decode(file2text(frame_path)) + frame_json -= identifier + + frame_json = json_encode(frame_json) + fdel(frame_path) + WRITE_FILE(frame_path, frame_json) + +///Loads photo albums, and populates them; also loads and applies frames to picture frames. +/datum/controller/subsystem/persistence/proc/load_photo_persistence() + var/album_path = file("data/photo_albums.json") + var/frame_path = file("data/photo_frames.json") + if(fexists(album_path)) + var/list/json = json_decode(file2text(album_path)) + if(json.len) + for(var/i in photo_albums) + var/obj/item/storage/photo_album/A = i + if(!A.persistence_id) + continue + if(json[A.persistence_id]) + A.populate_from_id_list(json[A.persistence_id]) + + if(fexists(frame_path)) + var/list/json = json_decode(file2text(frame_path)) + if(json.len) + for(var/i in photo_frames) + var/obj/structure/sign/picture_frame/PF = i + if(!PF.persistence_id) + continue + if(json[PF.persistence_id]) + PF.load_from_id(json[PF.persistence_id]) + +///Saves the contents of photo albums and the picture frames. +/datum/controller/subsystem/persistence/proc/save_photo_persistence() + var/album_path = file("data/photo_albums.json") + var/frame_path = file("data/photo_frames.json") + + var/list/frame_json = list() + var/list/album_json = list() + + if(fexists(album_path)) + album_json = json_decode(file2text(album_path)) + fdel(album_path) + + for(var/i in photo_albums) + var/obj/item/storage/photo_album/A = i + if(!istype(A) || !A.persistence_id) + continue + var/list/L = A.get_picture_id_list() + album_json[A.persistence_id] = L + + album_json = json_encode(album_json) + + WRITE_FILE(album_path, album_json) + + if(fexists(frame_path)) + frame_json = json_decode(file2text(frame_path)) + fdel(frame_path) + + for(var/i in photo_frames) + var/obj/structure/sign/picture_frame/F = i + if(!istype(F) || !F.persistence_id) + continue + frame_json[F.persistence_id] = F.get_photo_id() + + frame_json = json_encode(frame_json) + + WRITE_FILE(frame_path, frame_json) + diff --git a/code/controllers/subsystem/persistence/recipes.dm b/code/controllers/subsystem/persistence/recipes.dm new file mode 100644 index 00000000000000..84145b26aabc37 --- /dev/null +++ b/code/controllers/subsystem/persistence/recipes.dm @@ -0,0 +1,39 @@ +///Loads all randomized recipes. +/datum/controller/subsystem/persistence/proc/load_randomized_recipes() + var/json_file = file("data/RandomizedChemRecipes.json") + var/json + if(fexists(json_file)) + json = json_decode(file2text(json_file)) + + for(var/randomized_type in subtypesof(/datum/chemical_reaction/randomized)) + var/datum/chemical_reaction/randomized/R = new randomized_type + var/loaded = FALSE + if(R.persistent && json) + var/list/recipe_data = json["[R.type]"] + if(recipe_data) + if(R.LoadOldRecipe(recipe_data) && (daysSince(R.created) <= R.persistence_period)) + loaded = TRUE + if(!loaded) //We do not have information for whatever reason, just generate new one + if(R.persistent) + log_game("Resetting persistent [randomized_type] random recipe.") + R.GenerateRecipe() + + if(!R.HasConflicts()) //Might want to try again if conflicts happened in the future. + add_chemical_reaction(R) + else + log_game("Randomized recipe [randomized_type] resulted in conflicting recipes.") + +///Saves all randomized recipes. +/datum/controller/subsystem/persistence/proc/save_randomized_recipes() + var/json_file = file("data/RandomizedChemRecipes.json") + var/list/file_data = list() + + //asert globchems done + for(var/randomized_type in subtypesof(/datum/chemical_reaction/randomized)) + var/datum/chemical_reaction/randomized/R = get_chemical_reaction(randomized_type) //ew, would be nice to add some simple tracking + if(R?.persistent) + var/list/recipe_data = R.SaveOldRecipe() + file_data["[R.type]"] = recipe_data + + fdel(json_file) + WRITE_FILE(json_file, json_encode(file_data)) diff --git a/code/controllers/subsystem/persistence/scars.dm b/code/controllers/subsystem/persistence/scars.dm new file mode 100644 index 00000000000000..fa378f24dd4376 --- /dev/null +++ b/code/controllers/subsystem/persistence/scars.dm @@ -0,0 +1,17 @@ +///Saves all scars for everyone's original characters +/datum/controller/subsystem/persistence/proc/save_scars() + for(var/i in GLOB.joined_player_list) + var/mob/living/carbon/human/ending_human = get_mob_by_ckey(i) + if(!istype(ending_human) || !ending_human.mind?.original_character_slot_index || !ending_human.client?.prefs.read_preference(/datum/preference/toggle/persistent_scars)) + continue + + var/mob/living/carbon/human/original_human = ending_human.mind.original_character.resolve() + + if(!original_human) + continue + + if(original_human.stat == DEAD || !original_human.all_scars || original_human != ending_human) + original_human.save_persistent_scars(TRUE) + else + original_human.save_persistent_scars() + diff --git a/code/controllers/subsystem/persistence/tattoos.dm b/code/controllers/subsystem/persistence/tattoos.dm new file mode 100644 index 00000000000000..45dd31c7f5c94a --- /dev/null +++ b/code/controllers/subsystem/persistence/tattoos.dm @@ -0,0 +1,55 @@ +///Loads all tattoos, and select a few based on the amount of prisoner spawn positions. +/datum/controller/subsystem/persistence/proc/load_prisoner_tattoos() + var/json_file = file(PRISONER_TATTOO_SAVE_FILE) + if(!fexists(json_file)) + return + var/list/json = json_decode(file2text(json_file)) + if(!json) + return + + if(json["version"] < TATTOO_PERSISTENCE_VERSION) + update_prisoner_tattoos(json) + + var/datum/job/prisoner_datum = SSjob.name_occupations[JOB_PRISONER] + if(!prisoner_datum) + return + var/iterations_allowed = prisoner_datum.spawn_positions + + var/list/entries = json["entries"] + if(entries.len) + for(var/index in 1 to iterations_allowed) + prison_tattoos_to_use += list(entries[rand(1, entries.len)]) + + log_world("Loaded [prison_tattoos_to_use.len] prison tattoos") + +///Saves all tattoos, so they can appear on prisoners in future rounds +/datum/controller/subsystem/persistence/proc/save_prisoner_tattoos() + var/json_file = file(PRISONER_TATTOO_SAVE_FILE) + var/list/saved_data = list() + var/list/entries = list() + + if(fexists(json_file)) + var/list/old_json = json_decode(file2text(json_file)) + if(old_json) + entries += old_json["entries"] //Save the old if its there + + entries += prison_tattoos_to_save + + saved_data["version"] = ENGRAVING_PERSISTENCE_VERSION + saved_data["entries"] = entries + + fdel(json_file) + WRITE_FILE(json_file, json_encode(saved_data)) + +///This proc can update entries if the format has changed at some point. +/datum/controller/subsystem/persistence/proc/update_prisoner_tattoos(json) + for(var/tattoo_entry in json["entries"]) + continue //no versioning yet + + //Save it to the file + var/json_file = file(PRISONER_TATTOO_SAVE_FILE) + fdel(json_file) + WRITE_FILE(json_file, json_encode(json)) + + return json + diff --git a/code/controllers/subsystem/persistence/trophies.dm b/code/controllers/subsystem/persistence/trophies.dm new file mode 100644 index 00000000000000..515ed386085011 --- /dev/null +++ b/code/controllers/subsystem/persistence/trophies.dm @@ -0,0 +1,125 @@ +///trophy data datum, for admin manipulation +/datum/trophy_data + ///path of the item the trophy will try to mimic, null if path_string is invalid + var/path + ///the message that appears under the item + var/message + ///the key of the one who placed the item in the trophy case + var/placer_key + +/// Loads the trophies from the source file, and places a few in trophy display cases. +/datum/controller/subsystem/persistence/proc/load_trophies() + var/list/raw_saved_trophies = list() + if(fexists("data/npc_saves/TrophyItems.json")) + var/json_file = file("data/npc_saves/TrophyItems.json") + if(!fexists(json_file)) + return + var/list/json = json_decode(file2text(json_file)) + if(!json) + return + raw_saved_trophies = json["data"] + fdel("data/npc_saves/TrophyItems.json") + else + var/json_file = file("data/trophy_items.json") + if(!fexists(json_file)) + return + var/list/json = json_decode(file2text(json_file)) + if(!json) + return + raw_saved_trophies = json["data"] + + for(var/raw_json in raw_saved_trophies) + var/datum/trophy_data/parsed_trophy_data = new + parsed_trophy_data.load_from_json(raw_json) + saved_trophies += parsed_trophy_data + + set_up_trophies() + +/datum/trophy_data/proc/load_from_json(list/json_data) + path = json_data["path"] + message = json_data["message"] + placer_key = json_data["placer_key"] + +/datum/trophy_data/proc/to_json() + var/list/new_data = list() + new_data["path"] = path + new_data["message"] = message + new_data["placer_key"] = placer_key + new_data["is_valid"] = text2path(path) ? TRUE : FALSE + return new_data + +/// Returns a list for the admin trophy panel. +/datum/controller/subsystem/persistence/proc/trophy_ui_data() + var/list/ui_data = list() + for(var/datum/trophy_data/data in saved_trophies) + var/list/pdata = data.to_json() + pdata["ref"] = REF(data) + ui_data += list(pdata) + + return ui_data + + +/// Puts trophies into trophy cases. +/datum/controller/subsystem/persistence/proc/set_up_trophies() + + var/list/valid_trophies = list() + + for(var/datum/trophy_data/data in saved_trophies) + + if(!data) //sanity for incorrect deserialization + continue + + var/path = text2path(data.path) + if(!path) //If the item no longer exist, ignore it + continue + + valid_trophies += data + + for(var/obj/structure/displaycase/trophy/trophy_case in GLOB.trophy_cases) + if(!valid_trophies.len) + break + + if(trophy_case.showpiece) + continue + + trophy_case.set_up_trophy(pick_n_take(valid_trophies)) + +///Collects trophies from all existing trophy cases. +/datum/controller/subsystem/persistence/proc/collect_trophies() + for(var/trophy_case in GLOB.trophy_cases) + save_trophy(trophy_case) + + var/json_file = file("data/trophy_items.json") + var/list/file_data = list() + var/list/converted_data = list() + + for(var/datum/trophy_data/data in saved_trophies) + converted_data += list(data.to_json()) + + converted_data = remove_duplicate_trophies(converted_data) + + file_data["data"] = converted_data + fdel(json_file) + WRITE_FILE(json_file, json_encode(file_data)) + +///gets the list of json trophies, and deletes the ones with an identical path and message +/datum/controller/subsystem/persistence/proc/remove_duplicate_trophies(list/trophies) + var/list/ukeys = list() + . = list() + for(var/trophy in trophies) + var/tkey = "[trophy["path"]]-[trophy["message"]]" + if(ukeys[tkey]) + continue + else + . += list(trophy) + ukeys[tkey] = TRUE + +///If there is a trophy in the trophy case, saved it, if the trophy was not a holo trophy and has a message attached. +/datum/controller/subsystem/persistence/proc/save_trophy(obj/structure/displaycase/trophy/trophy_case) + if(!trophy_case.holographic_showpiece && trophy_case.showpiece && trophy_case.trophy_message) + var/datum/trophy_data/data = new + data.path = trophy_case.showpiece.type + data.message = trophy_case.trophy_message + data.placer_key = trophy_case.placer_key + saved_trophies += data + diff --git a/code/controllers/subsystem/persistent_paintings.dm b/code/controllers/subsystem/persistent_paintings.dm index 4eb77bd21be8ca..35656e2a56d4d8 100644 --- a/code/controllers/subsystem/persistent_paintings.dm +++ b/code/controllers/subsystem/persistent_paintings.dm @@ -113,6 +113,11 @@ SUBSYSTEM_DEF(persistent_paintings) /// A list of /datum/paintings saved or ready to be saved this round. var/list/paintings = list() + /// A list of paintings' data for paintings that are currently stored in the library. + var/list/cached_painting_data = list() + /// A list of paintings' data for paintings that are currently stored in the library, with admin metadata + var/list/admin_painting_data = list() + ///The list of available frame reskins (they are purely cosmetic) and the associated patronage amount required for them. var/list/frame_types_by_patronage_tier = list( "simple" = 0, @@ -127,8 +132,8 @@ SUBSYSTEM_DEF(persistent_paintings) "gold" = PATRONAGE_EXCELLENT_FRAME, "diamond" = PATRONAGE_AMAZING_FRAME, "rainbow" = PATRONAGE_SUPERB_FRAME, - "supermatter" = PATRONAGE_LEGENDARY_FRAME - ) + "supermatter" = PATRONAGE_LEGENDARY_FRAME, + ) /datum/controller/subsystem/persistent_paintings/Initialize() var/json_file = file("data/paintings.json") @@ -142,8 +147,29 @@ SUBSYSTEM_DEF(persistent_paintings) for(var/obj/structure/sign/painting/painting_frame as anything in painting_frames) painting_frame.load_persistent() + cache_paintings() + return SS_INIT_SUCCESS +/datum/controller/subsystem/persistent_paintings/proc/cache_paintings() + cached_painting_data = list() + admin_painting_data = list() + + for(var/datum/painting/painting as anything in paintings) + cached_painting_data += list(list( + "title" = painting.title, + "creator" = painting.creator_name, + "md5" = painting.md5, + "ref" = REF(painting), + "width" = painting.width, + "height" = painting.height, + "ratio" = painting.width/painting.height, + )) + + var/list/pdata = painting.to_json() + pdata["ref"] = REF(painting) + admin_painting_data += pdata + /** * Generates painting data ready to be consumed by ui. * Args: @@ -152,31 +178,27 @@ SUBSYSTEM_DEF(persistent_paintings) * * search_text : text to search for if the PAINTINGS_FILTER_SEARCH_TITLE or PAINTINGS_FILTER_SEARCH_CREATOR filters are enabled. */ /datum/controller/subsystem/persistent_paintings/proc/painting_ui_data(filter=NONE, admin=FALSE, search_text) - . = list() var/searching = filter & (PAINTINGS_FILTER_SEARCH_TITLE|PAINTINGS_FILTER_SEARCH_CREATOR) && search_text - for(var/datum/painting/painting as anything in paintings) - if(filter & PAINTINGS_FILTER_AI_PORTRAIT && ((painting.width != 24 && painting.width != 23) || (painting.height != 24 && painting.height != 23))) + + if(!searching) + return admin ? admin_painting_data : cached_painting_data + + var/list/filtered_paintings = list() + var/list/searched_paintings = admin ? admin_painting_data : cached_painting_data + + for(var/painting as anything in searched_paintings) + if(filter & PAINTINGS_FILTER_AI_PORTRAIT && ((painting["width"] != 24 && painting["width"] != 23) || (painting["height"] != 24 && painting["height"] != 23))) continue if(searching) var/haystack_text = "" if(filter & PAINTINGS_FILTER_SEARCH_TITLE) - haystack_text = painting.title + haystack_text = painting["title"] else if(filter & PAINTINGS_FILTER_SEARCH_CREATOR) - haystack_text = painting.creator_name + haystack_text = painting["creator"] if(!findtext(haystack_text, search_text)) continue - if(admin) - var/list/pdata = painting.to_json() - pdata["ref"] = REF(painting) - . += list(pdata) - else - . += list(list( - "title" = painting.title, - "creator" = painting.creator_name, - "md5" = painting.md5, - "ref" = REF(painting), - "ratio" = painting.width/painting.height, - )) + filtered_paintings += painting + return filtered_paintings /// Returns paintings with given tag. /datum/controller/subsystem/persistent_paintings/proc/get_paintings_with_tag(tag_name) @@ -309,6 +331,7 @@ SUBSYSTEM_DEF(persistent_paintings) var/payload = json_encode(all_data) fdel(json_file) WRITE_FILE(json_file, payload) + cache_paintings() #undef PAINTINGS_DATA_FORMAT_VERSION #undef PATRONAGE_OK_FRAME diff --git a/code/controllers/subsystem/processing/ai_behaviors.dm b/code/controllers/subsystem/processing/ai_behaviors.dm index 4ec698db32bbcc..e92da2474bb736 100644 --- a/code/controllers/subsystem/processing/ai_behaviors.dm +++ b/code/controllers/subsystem/processing/ai_behaviors.dm @@ -8,9 +8,12 @@ PROCESSING_SUBSYSTEM_DEF(ai_behaviors) wait = 1 ///List of all ai_behavior singletons, key is the typepath while assigned value is a newly created instance of the typepath. See SetupAIBehaviors() var/list/ai_behaviors + ///List of all targeting_strategy singletons, key is the typepath while assigned value is a newly created instance of the typepath. See SetupAIBehaviors() + var/list/targeting_strategies /datum/controller/subsystem/processing/ai_behaviors/Initialize() SetupAIBehaviors() + SetupTargetingStrats() return SS_INIT_SUCCESS /datum/controller/subsystem/processing/ai_behaviors/proc/SetupAIBehaviors() @@ -18,3 +21,9 @@ PROCESSING_SUBSYSTEM_DEF(ai_behaviors) for(var/behavior_type in subtypesof(/datum/ai_behavior)) var/datum/ai_behavior/ai_behavior = new behavior_type ai_behaviors[behavior_type] = ai_behavior + +/datum/controller/subsystem/processing/ai_behaviors/proc/SetupTargetingStrats() + targeting_strategies = list() + for(var/target_type in subtypesof(/datum/targeting_strategy)) + var/datum/targeting_strategy/target_start = new target_type + targeting_strategies[target_type] = target_start diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index c34d97b28f9c45..8d8e9a82136622 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -20,7 +20,7 @@ GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list( list(/datum/quirk/mute, /datum/quirk/softspoken), list(/datum/quirk/poor_aim, /datum/quirk/bighands), list(/datum/quirk/bilingual, /datum/quirk/foreigner), - list(/datum/quirk/spacer_born, /datum/quirk/paraplegic, /datum/quirk/item_quirk/settler), + list(/datum/quirk/spacer_born, /datum/quirk/item_quirk/settler), list(/datum/quirk/photophobia, /datum/quirk/nyctophobia), list(/datum/quirk/item_quirk/settler, /datum/quirk/freerunning), list(/datum/quirk/numb, /datum/quirk/selfaware), diff --git a/code/controllers/subsystem/queuelinks.dm b/code/controllers/subsystem/queuelinks.dm new file mode 100644 index 00000000000000..6a3b8288821624 --- /dev/null +++ b/code/controllers/subsystem/queuelinks.dm @@ -0,0 +1,68 @@ +/atom/proc/MatchedLinks(id, list/partners) + +SUBSYSTEM_DEF(queuelinks) + name = "Queue Links" + flags = SS_NO_FIRE + init_order = INIT_ORDER_QUEUELINKS + ///assoc list of pending queues, id = /datum/queue_link + var/list/queues = list() + +/datum/controller/subsystem/queuelinks/Initialize() + return SS_INIT_SUCCESS + +///Creates or adds to a queue with the id supplied, if the queue is now or above the size of the queue, calls MatchedLinks and clears queue. +/// queues with a size of 0 wait never pop until something is added with an actual queue_max +/datum/controller/subsystem/queuelinks/proc/add_to_queue(atom/what, id, queue_max = 0) + if(!isatom(what)) + CRASH("Attempted to add a non-atom to queue; [what]!") + if(isnull(id)) + CRASH("Attempted to add to queue with no ID; [what]") + + var/datum/queue_link/link + if(isnull(queues[id])) + link = new /datum/queue_link(id) + queues[id] = link + else + link = queues[id] + + if(link.add(what, queue_max)) + queues -= id + +/datum/queue_link + /// atoms in our queue + var/list/partners = list() + /// how much length until we pop, only incrementable, 0 means the queue will not pop until a maximum is set + var/queue_max = 0 + /// id + var/id + +/datum/queue_link/New(new_id) + id = new_id + return ..() + +///adds an atom to the queue, if we are popping this returns TRUE +/datum/queue_link/proc/add(atom/what, max = 0) + . = FALSE + if(what in partners) + return + partners += what + + if(queue_max != 0 && max != 0 && max != queue_max) + CRASH("Tried to change queue size to [max] from [queue_max]!") + else if(!queue_max) + queue_max = max + + if(!queue_max || length(partners) < queue_max) + return + + pop() + return TRUE + +/datum/queue_link/proc/pop() + for(var/atom/item as anything in partners) + item.MatchedLinks(id, partners) + qdel(src) + +/datum/queue_link/Destroy() + . = ..() + partners = null diff --git a/code/controllers/subsystem/security_level.dm b/code/controllers/subsystem/security_level.dm index b82a113d4fa543..df5ea642ce3701 100644 --- a/code/controllers/subsystem/security_level.dm +++ b/code/controllers/subsystem/security_level.dm @@ -39,6 +39,9 @@ SUBSYSTEM_DEF(security_level) if(!selected_level) CRASH("set_level was called with an invalid security level([new_level])") + if(SSnightshift.can_fire && (selected_level.number_level >= SEC_LEVEL_RED || current_security_level.number_level >= SEC_LEVEL_RED)) + SSnightshift.next_fire = world.time + 7 SECONDS // Fire nightshift after the security level announcement is complete + level_announce(selected_level, current_security_level.number_level) // We want to announce BEFORE updating to the new level SSsecurity_level.current_security_level = selected_level @@ -53,7 +56,6 @@ SUBSYSTEM_DEF(security_level) SSshuttle.emergency.alert_coeff_change(selected_level.shuttle_call_time_mod) SEND_SIGNAL(src, COMSIG_SECURITY_LEVEL_CHANGED, selected_level.number_level) - SSnightshift.check_nightshift() SSblackbox.record_feedback("tally", "security_level_changes", 1, selected_level.name) /** diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index eee808e9f4e74f..b1ebf3d586cfc7 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -100,9 +100,6 @@ SUBSYSTEM_DEF(shuttle) /// Wishlist items made by crew for cargo to purchase at their leisure. var/list/request_list = list() - /// A listing of previously delivered supply packs. - var/list/order_history = list() - /// A list of job accesses that are able to purchase any shuttles. var/list/has_purchase_shuttle_access @@ -265,13 +262,27 @@ SUBSYSTEM_DEF(shuttle) message_admins(msg) log_shuttle("[msg] Alive: [alive], Roundstart: [total], Threshold: [threshold]") emergency_no_recall = TRUE - priority_announce("Catastrophic casualties detected: crisis shuttle protocols activated - jamming recall signals across all frequencies.") + priority_announce( + text = "Catastrophic casualties detected: crisis shuttle protocols activated - jamming recall signals across all frequencies.", + title = "Emergency Shuttle Dispatched", + sound = ANNOUNCER_SHUTTLECALLED, + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "orange", + ) if(emergency.timeLeft(1) > emergency_call_time * ALERT_COEFF_AUTOEVAC_CRITICAL) emergency.request(null, set_coefficient = ALERT_COEFF_AUTOEVAC_CRITICAL) /datum/controller/subsystem/shuttle/proc/block_recall(lockout_timer) + if(isnull(lockout_timer)) + CRASH("Emergency shuttle block was called, but missing a value for the lockout duration") if(admin_emergency_no_recall) - priority_announce("Error!", "Emergency Shuttle Uplink Alert", ANNOUNCER_SHUTTLE) // SKYRAT EDIT CHANGE - Announcer Sounds + priority_announce( + text = "Emergency shuttle uplink interference detected, shuttle call disabled while the system reinitializes. Estimated restore in [DisplayTimeText(lockout_timer, round_seconds_to = 60)].", + title = "Uplink Interference", + sound = ANNOUNCER_SHUTTLE, // SKYRAT EDIT CHANGE - Announcer Sounds - ORIGINAL: sound = 'sound/misc/announce_dig.ogg', + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "grey", + ) addtimer(CALLBACK(src, PROC_REF(unblock_recall)), lockout_timer) return emergency_no_recall = TRUE @@ -279,7 +290,13 @@ SUBSYSTEM_DEF(shuttle) /datum/controller/subsystem/shuttle/proc/unblock_recall() if(admin_emergency_no_recall) - priority_announce("Error!", "Emergency Shuttle Uplink Alert", ANNOUNCER_SHUTTLE) // SKYRAT EDIT CHANGE - Announcer Sounds + priority_announce( + text= "Emergency shuttle uplink services are now back online.", + title = "Uplink Restored", + sound = ANNOUNCER_SHUTTLE, // SKYRAT EDIT CHANGE - Announcer Sounds - ORIGINAL: sound = 'sound/misc/announce_dig.ogg', + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "green", + ) return emergency_no_recall = FALSE @@ -519,15 +536,23 @@ SUBSYSTEM_DEF(shuttle) emergency.mode = SHUTTLE_STRANDED emergency.timer = null emergency.sound_played = FALSE - priority_announce("Hostile environment detected. \ - Departure has been postponed indefinitely pending \ - conflict resolution.", null, 'sound/misc/notice1.ogg', ANNOUNCEMENT_TYPE_PRIORITY) + priority_announce( + text = "Departure has been postponed indefinitely pending conflict resolution.", + title = "Hostile Environment Detected", + sound = 'sound/misc/notice1.ogg', + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "grey", + ) if(!emergency_no_escape && (emergency.mode == SHUTTLE_STRANDED)) emergency.mode = SHUTTLE_DOCKED emergency.setTimer(emergency_dock_time) - priority_announce("Hostile environment resolved. \ - You have 3 minutes to board the Emergency Shuttle.", - null, ANNOUNCER_SHUTTLEDOCK, ANNOUNCEMENT_TYPE_PRIORITY) + priority_announce( + text = "You have [DisplayTimeText(emergency_dock_time)] to board the emergency shuttle.", + title = "Hostile Environment Resolved", + sound = 'sound/misc/announce_dig.ogg', + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "green", + ) //try to move/request to dock_home if possible, otherwise dock_away. Mainly used for admin buttons /datum/controller/subsystem/shuttle/proc/toggleShuttle(shuttle_id, dock_home, dock_away, timed) @@ -717,8 +742,6 @@ SUBSYSTEM_DEF(shuttle) shopping_list = SSshuttle.shopping_list if (istype(SSshuttle.request_list)) request_list = SSshuttle.request_list - if (istype(SSshuttle.order_history)) - order_history = SSshuttle.order_history if (istype(SSshuttle.shuttle_loan)) shuttle_loan = SSshuttle.shuttle_loan diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 15a4aed4adbf75..e68ee9ee1f2f4b 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -66,7 +66,7 @@ SUBSYSTEM_DEF(vote) // Remove AFK or clientless non-voters. for(var/non_voter_ckey in non_voters) var/client/non_voter_client = non_voters[non_voter_ckey] - if(!non_voter_client || non_voter_client.is_afk()) + if(!istype(non_voter_client) || non_voter_client.is_afk()) non_voters -= non_voter_ckey // Now get the result of the vote. diff --git a/code/datums/achievements/misc_achievements.dm b/code/datums/achievements/misc_achievements.dm index f83f2cde7b0a18..8ae3da33e3a3a5 100644 --- a/code/datums/achievements/misc_achievements.dm +++ b/code/datums/achievements/misc_achievements.dm @@ -135,11 +135,11 @@ database_id = MEDAL_COSMOS_ASCENSION icon = "cosmicascend" -/datum/award/achievement/misc/knock_ascension - name = "Secrets behind the Spider Door" +/datum/award/achievement/misc/lock_ascension + name = "Secrets of the Locked Labyrinth" desc = "You managed to open a gate into the mansus." - database_id = MEDAL_KNOCK_ASCENSION - icon = "knockascend" + database_id = MEDAL_LOCK_ASCENSION + icon = "lockascend" /datum/award/achievement/misc/grand_ritual_finale name = "Archmage" diff --git a/code/datums/actions/cooldown_action.dm b/code/datums/actions/cooldown_action.dm index a7e0603461a77c..ed4309c36e1cb5 100644 --- a/code/datums/actions/cooldown_action.dm +++ b/code/datums/actions/cooldown_action.dm @@ -177,6 +177,8 @@ /// Starts a cooldown time for other abilities that share a cooldown with this. Has some niche usage with more complicated attack ai! /// Will use default cooldown time if an override is not specified /datum/action/cooldown/proc/StartCooldownOthers(override_cooldown_time) + if(!length(owner.actions)) + return // Possible if they have an action they don't control for(var/datum/action/cooldown/shared_ability in owner.actions - src) if(!(shared_cooldown & shared_ability.shared_cooldown)) continue diff --git a/code/datums/actions/mobs/charge.dm b/code/datums/actions/mobs/charge.dm index 7fb56209777123..0c73145770ea41 100644 --- a/code/datums/actions/mobs/charge.dm +++ b/code/datums/actions/mobs/charge.dm @@ -156,17 +156,23 @@ SSexplosions.med_mov_atom += target INVOKE_ASYNC(src, PROC_REF(DestroySurroundings), source) - hit_target(source, target, charge_damage) - -/datum/action/cooldown/mob_cooldown/charge/proc/hit_target(atom/movable/source, atom/target, damage_dealt) - if(!isliving(target)) - return - var/mob/living/living_target = target - living_target.visible_message("[source] slams into [living_target]!", "[source] tramples you into the ground!") - source.forceMove(get_turf(living_target)) - living_target.apply_damage(damage_dealt, BRUTE, wound_bonus = CANT_WOUND) - playsound(get_turf(living_target), 'sound/effects/meteorimpact.ogg', 100, TRUE) - shake_camera(living_target, 4, 3) + try_hit_target(source, target) + +/// Attempt to hit someone with our charge +/datum/action/cooldown/mob_cooldown/charge/proc/try_hit_target(atom/movable/source, atom/target) + if (can_hit_target(source, target)) + hit_target(source, target, charge_damage) + +/// Returns true if we're allowed to charge into this target +/datum/action/cooldown/mob_cooldown/charge/proc/can_hit_target(atom/movable/source, atom/target) + return isliving(target) + +/// Actually hit someone +/datum/action/cooldown/mob_cooldown/charge/proc/hit_target(atom/movable/source, mob/living/target, damage_dealt) + target.visible_message(span_danger("[source] slams into [target]!"), span_userdanger("[source] tramples you into the ground!")) + target.apply_damage(damage_dealt, BRUTE, wound_bonus = CANT_WOUND) + playsound(get_turf(target), 'sound/effects/meteorimpact.ogg', 100, TRUE) + shake_camera(target, 4, 3) shake_camera(source, 2, 3) /datum/action/cooldown/mob_cooldown/charge/basic_charge @@ -187,18 +193,21 @@ /datum/action/cooldown/mob_cooldown/charge/basic_charge/do_charge_indicator(atom/charger, atom/charge_target) charger.Shake(shake_pixel_shift, shake_pixel_shift, shake_duration) +/datum/action/cooldown/mob_cooldown/charge/basic_charge/can_hit_target(atom/movable/source, atom/target) + if(!isliving(target)) + if(!target.density || target.CanPass(source, get_dir(target, source))) + return FALSE + return TRUE + return ..() + /datum/action/cooldown/mob_cooldown/charge/basic_charge/hit_target(atom/movable/source, atom/target, damage_dealt) var/mob/living/living_source if(isliving(source)) living_source = source if(!isliving(target)) - if(!target.density || target.CanPass(source, get_dir(target, source))) - return source.visible_message(span_danger("[source] smashes into [target]!")) - if(!living_source) - return - living_source.Stun(recoil_duration, ignore_canstun = TRUE) + living_source?.Stun(recoil_duration, ignore_canstun = TRUE) return var/mob/living/living_target = target @@ -208,10 +217,9 @@ living_source.Stun(recoil_duration, ignore_canstun = TRUE) return - living_target.visible_message(span_danger("[source] charges on [living_target]!"), span_userdanger("[source] charges into you!")) + living_target.visible_message(span_danger("[source] charges into [living_target]!"), span_userdanger("[source] charges into you!")) living_target.Knockdown(knockdown_duration) - /datum/status_effect/tired_post_charge id = "tired_post_charge" duration = 1 SECONDS diff --git a/code/datums/actions/mobs/fire_breath.dm b/code/datums/actions/mobs/fire_breath.dm index 45b6538c01836e..b3673b2f96cf93 100644 --- a/code/datums/actions/mobs/fire_breath.dm +++ b/code/datums/actions/mobs/fire_breath.dm @@ -37,7 +37,7 @@ var/list/turfs = get_line(owner, target_turf) - get_turf(owner) INVOKE_ASYNC(src, PROC_REF(progressive_fire_line), turfs) -/// Creates fire with a delay on the list of targetted turfs +/// Creates fire with a delay on the list of targeted turfs /datum/action/cooldown/mob_cooldown/fire_breath/proc/progressive_fire_line(list/burn_turfs) if (QDELETED(owner) || owner.stat == DEAD) return diff --git a/code/datums/actions/mobs/personality_commune.dm b/code/datums/actions/mobs/personality_commune.dm new file mode 100644 index 00000000000000..26cf4834492044 --- /dev/null +++ b/code/datums/actions/mobs/personality_commune.dm @@ -0,0 +1,56 @@ +// This can probably be changed to use mind linker at some point +/datum/action/personality_commune + name = "Personality Commune" + desc = "Sends thoughts to your alternate consciousness." + background_icon_state = "bg_spell" + button_icon = 'icons/mob/actions/actions_spells.dmi' + button_icon_state = "telepathy" + overlay_icon_state = "bg_spell_border" + + /// Fluff text shown when a message is sent to the pair + var/fluff_text = span_boldnotice("You hear an echoing voice in the back of your head...") + +/datum/action/personality_commune/New(Target) + . = ..() + if(!istype(target, /datum/brain_trauma/severe/split_personality)) + stack_trace("[type] was created on a target that isn't a /datum/brain_trauma/severe/split_personality, this doesn't work.") + qdel(src) + +/datum/action/personality_commune/Grant(mob/grant_to) + if(!istype(grant_to, /mob/living/split_personality)) + return + + return ..() + +/datum/action/personality_commune/Trigger(trigger_flags) + . = ..() + if(!.) + return FALSE + + var/datum/brain_trauma/severe/split_personality/trauma = target + var/mob/living/split_personality/non_controller = usr + var/client/non_controller_client = non_controller.client + + var/to_send = tgui_input_text(non_controller, "What would you like to tell your other self?", "Commune") + if(QDELETED(src) || QDELETED(trauma) || !to_send) + return FALSE + + var/mob/living/carbon/human/personality_body = trauma.owner + if(personality_body.client == non_controller_client) // We took control + return FALSE + + var/user_message = span_boldnotice("You concentrate and send thoughts to your other self:") + var/user_message_body = span_notice("[to_send]") + + to_chat(non_controller, "[user_message] [user_message_body]") + + personality_body.balloon_alert(personality_body, "you hear a voice") + to_chat(personality_body, "[fluff_text] [user_message_body]") + + log_directed_talk(non_controller, personality_body, to_send, LOG_SAY, "[name]") + for(var/dead_mob in GLOB.dead_mob_list) + if(!isobserver(dead_mob)) + continue + to_chat(dead_mob, "[FOLLOW_LINK(dead_mob, non_controller)] [span_boldnotice("[non_controller] [name]:")] [span_notice("\"[to_send]\" to")] [span_name("[trauma]")]") + + return TRUE diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index f5af1409f9a9f2..a8c118303f32d0 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -619,6 +619,7 @@ multiple modular subtrees with behaviors // We found the value that's been deleted, it was an assoc value. Clear it out entirely else if(associated_value == source) next_to_clear -= inner_value + SEND_SIGNAL(pawn, COMSIG_AI_BLACKBOARD_KEY_CLEARED(inner_value)) index += 1 diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm index 91ba7ec489415d..21b141feff801e 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm @@ -2,10 +2,10 @@ action_cooldown = 0.2 SECONDS // We gotta check unfortunately often because we're in a race condition with nextmove behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION -/datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) . = ..() - if(!controller.blackboard_key_exists(targetting_datum_key)) - CRASH("No target datum was supplied in the blackboard for [controller.pawn]") + if(!controller.blackboard[targeting_strategy_key]) + CRASH("No targeting strategy was supplied in the blackboard for [controller.pawn]") //Hiding location is priority var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key] @@ -14,7 +14,7 @@ set_movement_target(controller, target) -/datum/ai_behavior/basic_melee_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_melee_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) if (isliving(controller.pawn)) var/mob/living/pawn = controller.pawn if (world.time < pawn.next_move) @@ -22,15 +22,15 @@ . = ..() var/mob/living/basic/basic_mob = controller.pawn - //targetting datum will kill the action if not real anymore + //targeting strategy will kill the action if not real anymore var/atom/target = controller.blackboard[target_key] - var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] + var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) - if(!targetting_datum.can_attack(basic_mob, target)) + if(!targeting_strategy.can_attack(basic_mob, target)) finish_action(controller, FALSE, target_key) return - var/hiding_target = targetting_datum.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something! + var/hiding_target = targeting_strategy.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something! controller.set_blackboard_key(hiding_location_key, hiding_target) @@ -40,7 +40,7 @@ basic_mob.melee_attack(target) -/datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key) . = ..() if(!succeeded) controller.clear_blackboard_key(target_key) @@ -54,30 +54,30 @@ ///do we care about avoiding friendly fire? var/avoid_friendly_fire = FALSE -/datum/ai_behavior/basic_ranged_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_ranged_attack/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) . = ..() var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key] if(QDELETED(target)) return FALSE set_movement_target(controller, target) -/datum/ai_behavior/basic_ranged_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_ranged_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) var/mob/living/basic/basic_mob = controller.pawn - //targetting datum will kill the action if not real anymore + //targeting strategy will kill the action if not real anymore var/atom/target = controller.blackboard[target_key] - var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] + var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) - if(!targetting_datum.can_attack(basic_mob, target, chase_range)) + if(!targeting_strategy.can_attack(basic_mob, target, chase_range)) finish_action(controller, FALSE, target_key) return - var/atom/hiding_target = targetting_datum.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something! + var/atom/hiding_target = targeting_strategy.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something! var/atom/final_target = hiding_target ? hiding_target : target if(!can_see(basic_mob, final_target, required_distance)) return - if(avoid_friendly_fire && check_friendly_in_path(basic_mob, target, targetting_datum)) + if(avoid_friendly_fire && check_friendly_in_path(basic_mob, target, targeting_strategy)) adjust_position(basic_mob, target) return ..() @@ -85,17 +85,17 @@ basic_mob.RangedAttack(final_target) return ..() //only start the cooldown when the shot is shot -/datum/ai_behavior/basic_ranged_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_ranged_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key) . = ..() if(!succeeded) controller.clear_blackboard_key(target_key) -/datum/ai_behavior/basic_ranged_attack/proc/check_friendly_in_path(mob/living/source, atom/target, datum/targetting_datum/targetting_datum) +/datum/ai_behavior/basic_ranged_attack/proc/check_friendly_in_path(mob/living/source, atom/target, datum/targeting_strategy/targeting_strategy) var/list/turfs_list = calculate_trajectory(source, target) for(var/turf/possible_turf as anything in turfs_list) for(var/mob/living/potential_friend in possible_turf) - if(!targetting_datum.can_attack(source, potential_friend)) + if(!targeting_strategy.can_attack(source, potential_friend)) return TRUE return FALSE diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/nearest_targetting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/nearest_targeting.dm similarity index 100% rename from code/datums/ai/basic_mobs/basic_ai_behaviors/nearest_targetting.dm rename to code/datums/ai/basic_mobs/basic_ai_behaviors/nearest_targeting.dm diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/set_travel_destination.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/set_travel_destination.dm new file mode 100644 index 00000000000000..207df4424577d9 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/set_travel_destination.dm @@ -0,0 +1,13 @@ +/datum/ai_behavior/set_travel_destination + +/datum/ai_behavior/set_travel_destination/perform(seconds_per_tick, datum/ai_controller/controller, target_key, location_key) + . = ..() + var/atom/target = controller.blackboard[target_key] + + if(QDELETED(target)) + finish_action(controller, FALSE, target_key) + return + + controller.set_blackboard_key(location_key, target) + + finish_action(controller, TRUE, target_key) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm similarity index 82% rename from code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm rename to code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm index 376f62a5855b53..435b9cb1ef3d04 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm @@ -7,16 +7,16 @@ /// Static typecache list of potentially dangerous objs var/static/list/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha)) -/datum/ai_behavior/find_potential_targets/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/find_potential_targets/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) . = ..() var/mob/living/living_mob = controller.pawn - var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] + var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) - if(!targetting_datum) + if(!targeting_strategy) CRASH("No target datum was supplied in the blackboard for [controller.pawn]") var/atom/current_target = controller.blackboard[target_key] - if (targetting_datum.can_attack(living_mob, current_target, vision_range)) + if (targeting_strategy.can_attack(living_mob, current_target, vision_range)) finish_action(controller, succeeded = FALSE) return @@ -37,7 +37,7 @@ var/list/filtered_targets = list() for(var/atom/pot_target in potential_targets) - if(targetting_datum.can_attack(living_mob, pot_target))//Can we attack it? + if(targeting_strategy.can_attack(living_mob, pot_target))//Can we attack it? filtered_targets += pot_target continue @@ -48,7 +48,7 @@ var/atom/target = pick_final_target(controller, filtered_targets) controller.set_blackboard_key(target_key, target) - var/atom/potential_hiding_location = targetting_datum.find_hidden_mobs(living_mob, target) + var/atom/potential_hiding_location = targeting_strategy.find_hidden_mobs(living_mob, target) if(potential_hiding_location) //If they're hiding inside of something, we need to know so we can go for that instead initially. controller.set_blackboard_key(hiding_location_key, potential_hiding_location) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm index f5e4f74a1fecc3..e162cc612990a2 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm @@ -18,7 +18,7 @@ . = ..() var/obj/machinery/atmospherics/components/unary/vent_pump/entry_vent = controller.blackboard[target_key] || controller.blackboard[BB_ENTRY_VENT_TARGET] var/mob/living/cached_pawn = controller.pawn - if(HAS_TRAIT(cached_pawn, TRAIT_MOVE_VENTCRAWLING) || !controller.blackboard[BB_CURRENTLY_TARGETTING_VENT] || !is_vent_valid(entry_vent)) + if(HAS_TRAIT(cached_pawn, TRAIT_MOVE_VENTCRAWLING) || !controller.blackboard[BB_CURRENTLY_TARGETING_VENT] || !is_vent_valid(entry_vent)) return if(!cached_pawn.can_enter_vent(entry_vent, provide_feedback = FALSE)) // we're an AI we scoff at feedback @@ -30,7 +30,7 @@ finish_action(controller, FALSE, target_key) return - controller.set_blackboard_key(BB_CURRENTLY_TARGETTING_VENT, FALSE) // must be done here because we have a do_after sleep in handle_ventcrawl unfortunately and double dipping could lead to erroneous suicide pill calls. + controller.set_blackboard_key(BB_CURRENTLY_TARGETING_VENT, FALSE) // must be done here because we have a do_after sleep in handle_ventcrawl unfortunately and double dipping could lead to erroneous suicide pill calls. cached_pawn.handle_ventcrawl(entry_vent) if(!HAS_TRAIT(cached_pawn, TRAIT_MOVE_VENTCRAWLING)) //something failed and we ARE NOT IN THE VENT even though the earlier check said we were good to go! odd. finish_action(controller, FALSE, target_key) @@ -134,5 +134,5 @@ controller.clear_blackboard_key(target_key) controller.clear_blackboard_key(BB_ENTRY_VENT_TARGET) controller.clear_blackboard_key(BB_EXIT_VENT_TARGET) - controller.set_blackboard_key(BB_CURRENTLY_TARGETTING_VENT, FALSE) // just in case + controller.set_blackboard_key(BB_CURRENTLY_TARGETING_VENT, FALSE) // just in case diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/wounded_targetting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/wounded_targeting.dm similarity index 94% rename from code/datums/ai/basic_mobs/basic_ai_behaviors/wounded_targetting.dm rename to code/datums/ai/basic_mobs/basic_ai_behaviors/wounded_targeting.dm index 8535554e54b468..46037fdc076ee8 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/wounded_targetting.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/wounded_targeting.dm @@ -7,5 +7,5 @@ living_targets += filtered_targets if(living_targets.len) sortTim(living_targets, GLOBAL_PROC_REF(cmp_mob_health)) - return living_targets[1] + return pop(living_targets) return ..() diff --git a/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm index c3d334165d95c3..4116900435460c 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm @@ -12,19 +12,19 @@ var/mob/living/pawn = controller.pawn if (LAZYLEN(pawn.do_afters)) return - controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) /// Attack something which is already adjacent to us without moving /datum/ai_behavior/basic_melee_attack/opportunistic action_cooldown = 0.2 SECONDS // We gotta check unfortunately often because we're in a race condition with nextmove behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION -/datum/ai_behavior/basic_melee_attack/opportunistic/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) - if (!controller.blackboard_key_exists(targetting_datum_key)) +/datum/ai_behavior/basic_melee_attack/opportunistic/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) + if (!controller.blackboard_key_exists(targeting_strategy_key)) CRASH("No target datum was supplied in the blackboard for [controller.pawn]") return controller.blackboard_key_exists(target_key) -/datum/ai_behavior/basic_melee_attack/opportunistic/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_melee_attack/opportunistic/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) var/atom/movable/atom_pawn = controller.pawn if(!atom_pawn.CanReach(controller.blackboard[target_key])) finish_action(controller, TRUE, target_key) // Don't clear target diff --git a/code/datums/ai/basic_mobs/basic_subtrees/attack_obstacle_in_path.dm b/code/datums/ai/basic_mobs/basic_subtrees/attack_obstacle_in_path.dm index 9f1053f29d3f29..7059bec93fe2fa 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/attack_obstacle_in_path.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/attack_obstacle_in_path.dm @@ -74,7 +74,7 @@ return FALSE if (basic_mob.see_invisible < object.invisibility) return FALSE - var/list/whitelist = basic_mob.ai_controller.blackboard[BB_OBSTACLE_TARGETTING_WHITELIST] + var/list/whitelist = basic_mob.ai_controller.blackboard[BB_OBSTACLE_TARGETING_WHITELIST] if(whitelist && !is_type_in_typecache(object, whitelist)) return FALSE diff --git a/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm index 47f4155ac45529..4d5319bca86e77 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm @@ -1,19 +1,19 @@ /// Add or remove people to our retaliation shitlist just on an arbitrary whim /datum/ai_planning_subtree/capricious_retaliate /// Blackboard key which tells us how to select valid targets - var/targetting_datum_key = BB_TARGETTING_DATUM + var/targeting_strategy_key = BB_TARGETING_STRATEGY /// Whether we should skip checking faction for our decision var/ignore_faction = TRUE /datum/ai_planning_subtree/capricious_retaliate/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - controller.queue_behavior(/datum/ai_behavior/capricious_retaliate, targetting_datum_key, ignore_faction) + controller.queue_behavior(/datum/ai_behavior/capricious_retaliate, targeting_strategy_key, ignore_faction) /// Add or remove people to our retaliation shitlist just on an arbitrary whim /datum/ai_behavior/capricious_retaliate action_cooldown = 1 SECONDS -/datum/ai_behavior/capricious_retaliate/perform(seconds_per_tick, datum/ai_controller/controller, targetting_datum_key, ignore_faction) +/datum/ai_behavior/capricious_retaliate/perform(seconds_per_tick, datum/ai_controller/controller, targeting_strategy_key, ignore_faction) . = ..() var/atom/pawn = controller.pawn if (controller.blackboard_key_exists(BB_BASIC_MOB_RETALIATE_LIST)) @@ -35,10 +35,10 @@ var/aggro_range = controller.blackboard[BB_AGGRO_RANGE] || 9 var/list/potential_targets = hearers(aggro_range, get_turf(pawn)) - pawn if (!length(potential_targets)) - failed_targetting(controller, pawn, ignore_faction) + failed_targeting(controller, pawn, ignore_faction) return - var/datum/targetting_datum/target_helper = controller.blackboard[targetting_datum_key] + var/datum/targeting_strategy/target_helper = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) var/mob/living/final_target = null if (ignore_faction) @@ -49,7 +49,7 @@ final_target = test_target if (isnull(final_target)) - failed_targetting(controller, pawn, ignore_faction) + failed_targeting(controller, pawn, ignore_faction) return controller.insert_blackboard_key_lazylist(BB_BASIC_MOB_RETALIATE_LIST, final_target) @@ -57,7 +57,7 @@ finish_action(controller, TRUE, ignore_faction) /// Called if we try but fail to target something -/datum/ai_behavior/capricious_retaliate/proc/failed_targetting(datum/ai_controller/controller, atom/pawn, ignore_faction) +/datum/ai_behavior/capricious_retaliate/proc/failed_targeting(datum/ai_controller/controller, atom/pawn, ignore_faction) finish_action(controller, FALSE, ignore_faction) pawn.visible_message(span_notice("[pawn] grumbles.")) // We're pissed off but with no outlet to vent our frustration upon diff --git a/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm index 4f901745eeea5e..4a2f5b476c7590 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm @@ -20,7 +20,7 @@ return SUBTREE_RETURN_FINISH_PLANNING //we gotta get out of here. /// Try to escape from your current target, without performing any other actions. -/// Reads from some fleeing-specific targetting keys rather than the current mob target. +/// Reads from some fleeing-specific targeting keys rather than the current mob target. /datum/ai_planning_subtree/flee_target/from_flee_key target_key = BB_BASIC_MOB_FLEE_TARGET hiding_place_key = BB_BASIC_MOB_FLEE_TARGET_HIDING_LOCATION diff --git a/code/datums/ai/basic_mobs/basic_subtrees/go_for_swim.dm b/code/datums/ai/basic_mobs/basic_subtrees/go_for_swim.dm new file mode 100644 index 00000000000000..12c77119f3e182 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/go_for_swim.dm @@ -0,0 +1,59 @@ +#define DEFAULT_TIME_SWIMMER 30 SECONDS + +///subtree to go and swim! +/datum/ai_planning_subtree/go_for_swim + +/datum/ai_planning_subtree/go_for_swim/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(controller.blackboard_key_exists(BB_SWIM_ALTERNATE_TURF)) + controller.queue_behavior(/datum/ai_behavior/travel_towards/swimming, BB_SWIM_ALTERNATE_TURF) + + if(isnull(controller.blackboard[BB_KEY_SWIM_TIME])) + controller.set_blackboard_key(BB_KEY_SWIM_TIME, DEFAULT_TIME_SWIMMER) + + var/mob/living/living_pawn = controller.pawn + var/turf/our_turf = get_turf(living_pawn) + + // we have been taken out of water! + controller.set_blackboard_key(BB_CURRENTLY_SWIMMING, iswaterturf(our_turf)) + + if(controller.blackboard[BB_KEY_SWIM_TIME] < world.time) + controller.queue_behavior(/datum/ai_behavior/find_and_set/swim_alternate, BB_SWIM_ALTERNATE_TURF, /turf/open) + return + + // have some fun in the water + if(controller.blackboard[BB_CURRENTLY_SWIMMING] && SPT_PROB(5, seconds_per_tick)) + controller.queue_behavior(/datum/ai_behavior/perform_emote, "splashes water all around!") + + +///find land if its time to get out of water, otherwise find water +/datum/ai_behavior/find_and_set/swim_alternate + +/datum/ai_behavior/find_and_set/swim_alternate/search_tactic(datum/ai_controller/controller, locate_path, search_range) + var/mob/living/living_pawn = controller.pawn + if(QDELETED(living_pawn)) + return null + var/look_for_land = controller.blackboard[BB_CURRENTLY_SWIMMING] + var/list/possible_turfs = list() + for(var/turf/possible_turf in oview(search_range, living_pawn)) + if(isclosedturf(possible_turf) || isspaceturf(possible_turf) || isopenspaceturf(possible_turf)) + continue + if(possible_turf.is_blocked_turf()) + continue + if(look_for_land == iswaterturf(possible_turf)) + continue + possible_turfs += possible_turf + + if(!length(possible_turfs)) + return null + + return(pick(possible_turfs)) + +/datum/ai_behavior/travel_towards/swimming + clear_target = TRUE + +/datum/ai_behavior/travel_towards/swimming/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + var/time_to_add = controller.blackboard[BB_KEY_SWIMMER_COOLDOWN] ? controller.blackboard[BB_KEY_SWIMMER_COOLDOWN] : DEFAULT_TIME_SWIMMER + controller.set_blackboard_key(BB_KEY_SWIM_TIME, world.time + time_to_add ) + +#undef DEFAULT_TIME_SWIMMER diff --git a/code/datums/ai/basic_mobs/basic_subtrees/opportunistic_ventcrawler.dm b/code/datums/ai/basic_mobs/basic_subtrees/opportunistic_ventcrawler.dm index 63a745305b201d..240272d1ef48a1 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/opportunistic_ventcrawler.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/opportunistic_ventcrawler.dm @@ -15,6 +15,6 @@ controller.queue_behavior(/datum/ai_behavior/travel_towards, BB_ENTRY_VENT_TARGET) return - controller.set_blackboard_key(BB_CURRENTLY_TARGETTING_VENT, TRUE) + controller.set_blackboard_key(BB_CURRENTLY_TARGETING_VENT, TRUE) controller.queue_behavior(/datum/ai_behavior/crawl_through_vents, BB_ENTRY_VENT_TARGET) return SUBTREE_RETURN_FINISH_PLANNING // we are going into this vent... no distractions diff --git a/code/datums/ai/basic_mobs/basic_subtrees/prepare_travel_to_destination.dm b/code/datums/ai/basic_mobs/basic_subtrees/prepare_travel_to_destination.dm new file mode 100644 index 00000000000000..2718ca630ff7af --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/prepare_travel_to_destination.dm @@ -0,0 +1,23 @@ + +///Subtree that checks if we are on the target atom's tile, and sets it as a travel target if not +///The target is taken from the blackboard. This one always requires a specific implementation. +/datum/ai_planning_subtree/prepare_travel_to_destination + var/target_key + var/travel_destination_key = BB_TRAVEL_DESTINATION + +/datum/ai_planning_subtree/prepare_travel_to_destination/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/atom/target = controller.blackboard[target_key] + + //Target is deleted, or we are already standing on it + if(QDELETED(target) || (isturf(target) && controller.pawn.loc == target) || (target.loc == controller.pawn.loc)) + return + + //Already set with this value, return + if(controller.blackboard[target_key] == controller.blackboard[travel_destination_key]) + return + + controller.queue_behavior(/datum/ai_behavior/set_travel_destination, target_key, travel_destination_key) + return //continue planning regardless of success + +/datum/ai_planning_subtree/prepare_travel_to_destination/trader + target_key = BB_SHOP_SPOT diff --git a/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm b/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm index be395f3dfe49d2..95a125eea5ce5d 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm @@ -14,30 +14,30 @@ . = ..() if(!controller.blackboard_key_exists(target_key)) return - controller.queue_behavior(attack_behavior, target_key, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION, max_range, min_range) + controller.queue_behavior(attack_behavior, target_key, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION, max_range, min_range) /// How often will we try to perform our ranged attack? /datum/ai_behavior/ranged_skirmish action_cooldown = 1 SECONDS -/datum/ai_behavior/ranged_skirmish/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, max_range, min_range) +/datum/ai_behavior/ranged_skirmish/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key, max_range, min_range) . = ..() var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key] return !QDELETED(target) -/datum/ai_behavior/ranged_skirmish/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, max_range, min_range) +/datum/ai_behavior/ranged_skirmish/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key, max_range, min_range) . = ..() var/atom/target = controller.blackboard[target_key] if (QDELETED(target)) finish_action(controller, succeeded = FALSE) return - var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] - if(!targetting_datum.can_attack(controller.pawn, target)) + var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) + if(!targeting_strategy.can_attack(controller.pawn, target)) finish_action(controller, succeeded = FALSE) return - var/hiding_target = targetting_datum.find_hidden_mobs(controller.pawn, target) + var/hiding_target = targeting_strategy.find_hidden_mobs(controller.pawn, target) controller.set_blackboard_key(hiding_location_key, hiding_target) target = hiding_target || target diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm index 210aaf0aa8b26f..5b1f5ffbff9ed5 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm @@ -8,7 +8,7 @@ . = ..() if(!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) return - controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) if (end_planning) return SUBTREE_RETURN_FINISH_PLANNING //we are going into battle...no distractions. @@ -20,5 +20,5 @@ . = ..() if(!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) return - controller.queue_behavior(ranged_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(ranged_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) return SUBTREE_RETURN_FINISH_PLANNING //we are going into battle...no distractions. diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm index 3fe1ada33ba994..6630f7d193d90f 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm @@ -5,11 +5,11 @@ . = ..() if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING]) return - controller.queue_behavior(/datum/ai_behavior/find_potential_targets/nearest, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/find_potential_targets/nearest, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) /// Find the nearest thing on our list of 'things which have done damage to me' and set it as the flee target /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee - var/targeting_key = BB_TARGETTING_DATUM + var/targeting_key = BB_TARGETING_STRATEGY /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() @@ -18,4 +18,4 @@ controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list/nearest, BB_BASIC_MOB_RETALIATE_LIST, BB_BASIC_MOB_CURRENT_TARGET, targeting_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key - targeting_key = BB_FLEE_TARGETTING_DATUM + targeting_key = BB_FLEE_TARGETING_STRATEGY diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm index ec4ef1863adc9b..1c7d8de9120ba3 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm @@ -2,7 +2,7 @@ /datum/ai_planning_subtree/simple_find_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - controller.queue_behavior(/datum/ai_behavior/find_potential_targets, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/find_potential_targets, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) // Prevents finding a target if a human is nearby /datum/ai_planning_subtree/simple_find_target/not_while_observed diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_wounded_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_wounded_target.dm index 8840c1ea3a76ce..7a230014d9ab2e 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_wounded_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_wounded_target.dm @@ -3,4 +3,4 @@ /datum/ai_planning_subtree/simple_find_wounded_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - controller.queue_behavior(/datum/ai_behavior/find_potential_targets/most_wounded, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/find_potential_targets/most_wounded, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm index 701f911d273250..55ec7387613170 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm @@ -2,7 +2,7 @@ /datum/ai_planning_subtree/target_retaliate operational_datums = list(/datum/element/ai_retaliate, /datum/component/ai_retaliate_advanced) /// Blackboard key which tells us how to select valid targets - var/targetting_datum_key = BB_TARGETTING_DATUM + var/targeting_strategy_key = BB_TARGETING_STRATEGY /// Blackboard key in which to store selected target var/target_key = BB_BASIC_MOB_CURRENT_TARGET /// Blackboard key in which to store selected target's hiding place @@ -12,16 +12,16 @@ /datum/ai_planning_subtree/target_retaliate/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targetting_datum_key, hiding_place_key, check_faction) + controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targeting_strategy_key, hiding_place_key, check_faction) /datum/ai_planning_subtree/target_retaliate/check_faction check_faction = TRUE /// Places a mob which you can see and who has recently attacked you into some 'run away from this' AI keys -/// Can use a different targetting datum than you use to select attack targets +/// Can use a different targeting strategy than you use to select attack targets /// Not required if fleeing is the only target behaviour or uses the same target datum /datum/ai_planning_subtree/target_retaliate/to_flee - targetting_datum_key = BB_FLEE_TARGETTING_DATUM + targeting_strategy_key = BB_FLEE_TARGETING_STRATEGY target_key = BB_BASIC_MOB_FLEE_TARGET hiding_place_key = BB_BASIC_MOB_FLEE_TARGET_HIDING_LOCATION @@ -34,11 +34,11 @@ /// How far can we see stuff? var/vision_range = 9 -/datum/ai_behavior/target_from_retaliate_list/perform(seconds_per_tick, datum/ai_controller/controller, shitlist_key, target_key, targetting_datum_key, hiding_location_key, check_faction) +/datum/ai_behavior/target_from_retaliate_list/perform(seconds_per_tick, datum/ai_controller/controller, shitlist_key, target_key, targeting_strategy_key, hiding_location_key, check_faction) . = ..() var/mob/living/living_mob = controller.pawn - var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] - if(!targetting_datum) + var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) + if(!targeting_strategy) CRASH("No target datum was supplied in the blackboard for [controller.pawn]") var/list/shitlist = controller.blackboard[shitlist_key] @@ -47,13 +47,13 @@ if (!check_faction) controller.set_blackboard_key(BB_TEMPORARILY_IGNORE_FACTION, TRUE) - if (!QDELETED(existing_target) && (locate(existing_target) in shitlist) && targetting_datum.can_attack(living_mob, existing_target, vision_range)) + if (!QDELETED(existing_target) && (locate(existing_target) in shitlist) && targeting_strategy.can_attack(living_mob, existing_target, vision_range)) finish_action(controller, succeeded = TRUE, check_faction = check_faction) return var/list/enemies_list = list() for(var/mob/living/potential_target as anything in shitlist) - if(!targetting_datum.can_attack(living_mob, potential_target, vision_range)) + if(!targeting_strategy.can_attack(living_mob, potential_target, vision_range)) continue enemies_list += potential_target @@ -65,7 +65,7 @@ var/atom/new_target = pick_final_target(controller, enemies_list) controller.set_blackboard_key(target_key, new_target) - var/atom/potential_hiding_location = targetting_datum.find_hidden_mobs(living_mob, new_target) + var/atom/potential_hiding_location = targeting_strategy.find_hidden_mobs(living_mob, new_target) if(potential_hiding_location) //If they're hiding inside of something, we need to know so we can go for that instead initially. controller.set_blackboard_key(hiding_location_key, potential_hiding_location) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm b/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm index d9ee3ef09182de..cd809804ba369e 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm @@ -1,7 +1,7 @@ /// Attempts to use a mob ability on a target /datum/ai_planning_subtree/targeted_mob_ability /// Blackboard key for the ability - var/ability_key = BB_TARGETTED_ACTION + var/ability_key = BB_TARGETED_ACTION /// Blackboard key for where the target ref is stored var/target_key = BB_BASIC_MOB_CURRENT_TARGET /// Behaviour to perform using ability diff --git a/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm b/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm index fb83b8f8684ade..5ceef67bedb26c 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm @@ -1,6 +1,6 @@ /** * Simple behaviours which simply try to use an ability whenever it is available. - * For something which wants a target try `targetted_mob_ability`. + * For something which wants a target try `targeted_mob_ability`. */ /datum/ai_planning_subtree/use_mob_ability /// Blackboard key for the ability diff --git a/code/datums/ai/basic_mobs/generic_controllers.dm b/code/datums/ai/basic_mobs/generic_controllers.dm index 208c1833add843..dae1b944dd321d 100644 --- a/code/datums/ai/basic_mobs/generic_controllers.dm +++ b/code/datums/ai/basic_mobs/generic_controllers.dm @@ -1,7 +1,7 @@ /// The most basic AI tree which just finds a guy and then runs at them to click them /datum/ai_controller/basic_controller/simple_hostile blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance @@ -14,7 +14,7 @@ /// Find a target, walk at target, attack intervening obstacles /datum/ai_controller/basic_controller/simple_hostile_obstacles blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/datums/ai/basic_mobs/pet_commands/pet_use_targetted_ability.dm b/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm similarity index 100% rename from code/datums/ai/basic_mobs/pet_commands/pet_use_targetted_ability.dm rename to code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm diff --git a/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm similarity index 79% rename from code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm rename to code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm index d8b7e49c23cdde..2505b87a717f96 100644 --- a/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm +++ b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm @@ -1,18 +1,19 @@ -///Datum for basic mobs to define what they can attack. -/datum/targetting_datum +///Datum for basic mobs to define what they can attack.GET_TARGETING_STRATEGY\((/[^,]*)\), +///Global, just like ai_behaviors +/datum/targeting_strategy ///Returns true or false depending on if the target can be attacked by the mob -/datum/targetting_datum/proc/can_attack(mob/living/living_mob, atom/target, vision_range) +/datum/targeting_strategy/proc/can_attack(mob/living/living_mob, atom/target, vision_range) return ///Returns something the target might be hiding inside of -/datum/targetting_datum/proc/find_hidden_mobs(mob/living/living_mob, atom/target) +/datum/targeting_strategy/proc/find_hidden_mobs(mob/living/living_mob, atom/target) var/atom/target_hiding_location if(istype(target.loc, /obj/structure/closet) || istype(target.loc, /obj/machinery/disposal) || istype(target.loc, /obj/machinery/sleeper)) target_hiding_location = target.loc return target_hiding_location -/datum/targetting_datum/basic +/datum/targeting_strategy/basic /// When we do our basic faction check, do we look for exact faction matches? var/check_factions_exactly = FALSE /// Whether we care for seeing the target or not @@ -22,7 +23,7 @@ /// If this blackboard key is TRUE, makes us only target wounded mobs var/target_wounded_key -/datum/targetting_datum/basic/can_attack(mob/living/living_mob, atom/the_target, vision_range) +/datum/targeting_strategy/basic/can_attack(mob/living/living_mob, atom/the_target, vision_range) var/datum/ai_controller/basic_controller/our_controller = living_mob.ai_controller if(isnull(our_controller)) @@ -82,29 +83,29 @@ return FALSE /// Returns true if the mob and target share factions -/datum/targetting_datum/basic/proc/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) +/datum/targeting_strategy/basic/proc/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) if (controller.blackboard[BB_ALWAYS_IGNORE_FACTION] || controller.blackboard[BB_TEMPORARILY_IGNORE_FACTION]) return FALSE return living_mob.faction_check_atom(the_target, exact_match = check_factions_exactly) /// Subtype more forgiving for items. /// Careful, this can go wrong and keep a mob hyper-focused on an item it can't lose aggro on -/datum/targetting_datum/basic/allow_items +/datum/targeting_strategy/basic/allow_items -/datum/targetting_datum/basic/allow_items/can_attack(mob/living/living_mob, atom/the_target, vision_range) +/datum/targeting_strategy/basic/allow_items/can_attack(mob/living/living_mob, atom/the_target, vision_range) . = ..() if(isitem(the_target)) // trust fall exercise return TRUE /// Subtype which searches for mobs of a size relative to ours -/datum/targetting_datum/basic/of_size +/datum/targeting_strategy/basic/of_size /// If true, we will return mobs which are smaller than us. If false, larger. var/find_smaller = TRUE /// If true, we will return mobs which are the same size as us. var/inclusive = TRUE -/datum/targetting_datum/basic/of_size/can_attack(mob/living/owner, atom/target, vision_range) +/datum/targeting_strategy/basic/of_size/can_attack(mob/living/owner, atom/target, vision_range) if(!isliving(target)) return FALSE . = ..() @@ -119,14 +120,14 @@ return !find_smaller // This is just using the default values but the subtype makes it clearer -/datum/targetting_datum/basic/of_size/ours_or_smaller +/datum/targeting_strategy/basic/of_size/ours_or_smaller -/datum/targetting_datum/basic/of_size/larger +/datum/targeting_strategy/basic/of_size/larger find_smaller = FALSE inclusive = FALSE /// Makes the mob only attack their own faction. Useful mostly if their attacks do something helpful (e.g. healing touch). -/datum/targetting_datum/basic/same_faction +/datum/targeting_strategy/basic/same_faction -/datum/targetting_datum/basic/same_faction/faction_check(mob/living/living_mob, mob/living/the_target) +/datum/targeting_strategy/basic/same_faction/faction_check(mob/living/living_mob, mob/living/the_target) return !..() // inverts logic to ONLY target mobs that share a faction diff --git a/code/datums/ai/basic_mobs/targetting_datums/dont_target_friends.dm b/code/datums/ai/basic_mobs/targeting_strategies/dont_target_friends.dm similarity index 55% rename from code/datums/ai/basic_mobs/targetting_datums/dont_target_friends.dm rename to code/datums/ai/basic_mobs/targeting_strategies/dont_target_friends.dm index e2081bf308e9cf..1b52c4986bb4f6 100644 --- a/code/datums/ai/basic_mobs/targetting_datums/dont_target_friends.dm +++ b/code/datums/ai/basic_mobs/targeting_strategies/dont_target_friends.dm @@ -1,12 +1,12 @@ /// Don't target an atom in our friends list (or turfs), anything else is fair game -/datum/targetting_datum/basic/not_friends +/datum/targeting_strategy/basic/not_friends /// Stop regarding someone as a valid target once they pass this stat level, setting it to DEAD means you will happily attack corpses var/attack_until_past_stat = HARD_CRIT /// If we can try to closed turfs or not var/attack_closed_turf = FALSE ///Returns true or false depending on if the target can be attacked by the mob -/datum/targetting_datum/basic/not_friends/can_attack(mob/living/living_mob, atom/target, vision_range) +/datum/targeting_strategy/basic/not_friends/can_attack(mob/living/living_mob, atom/target, vision_range) if(attack_closed_turf && isclosedturf(target)) return TRUE @@ -16,16 +16,16 @@ return ..() ///friends dont care about factions -/datum/targetting_datum/basic/not_friends/faction_check(mob/living/living_mob, mob/living/the_target) +/datum/targeting_strategy/basic/not_friends/faction_check(mob/living/living_mob, mob/living/the_target) return FALSE -/datum/targetting_datum/basic/not_friends/attack_closed_turfs +/datum/targeting_strategy/basic/not_friends/attack_closed_turfs attack_closed_turf = TRUE -/// Subtype that allows us to target items while deftly avoiding attacking our allies. Be careful when it comes to targetting items as an AI could get trapped targetting something it can't destroy. -/datum/targetting_datum/basic/not_friends/allow_items +/// Subtype that allows us to target items while deftly avoiding attacking our allies. Be careful when it comes to targeting items as an AI could get trapped targeting something it can't destroy. +/datum/targeting_strategy/basic/not_friends/allow_items -/datum/targetting_datum/basic/not_friends/allow_items/can_attack(mob/living/living_mob, atom/the_target, vision_range) +/datum/targeting_strategy/basic/not_friends/allow_items/can_attack(mob/living/living_mob, atom/the_target, vision_range) . = ..() if(isitem(the_target)) // trust fall exercise diff --git a/code/datums/ai/basic_mobs/targeting_strategies/with_object.dm b/code/datums/ai/basic_mobs/targeting_strategies/with_object.dm new file mode 100644 index 00000000000000..7cc76d3010c906 --- /dev/null +++ b/code/datums/ai/basic_mobs/targeting_strategies/with_object.dm @@ -0,0 +1,29 @@ +/** + * Find mobs who are holding the bb configurable object type + * + * This is an extension of basic targeting behaviour, that allows you to + * only target the mob if they have a specific item in their hand. + * + */ +/datum/targeting_strategy/basic/holding_object + /// BB key that holds the target typepath to use + var/target_item_key = BB_TARGET_HELD_ITEM + +///Returns true or false depending on if the target can be attacked by the mob +/datum/targeting_strategy/basic/holding_object/can_attack(mob/living/living_mob, atom/target, vision_range) + var/datum/ai_controller/controller = living_mob.ai_controller + var/object_type_path = controller.blackboard[target_item_key] + + if (object_type_path == null) + return FALSE // no op + if(!ismob(target)) + return FALSE // no hands no problems + + // Look at me, type casting like a grown up + var/mob/targetmob = target + // Check if our parent behaviour agrees we can attack this target (we ignore faction by default) + var/can_attack = ..() + if(can_attack && targetmob.is_holding_item_of_type(object_type_path)) + return TRUE // they have the item + // No valid target + return FALSE diff --git a/code/datums/ai/basic_mobs/targetting_datums/with_object.dm b/code/datums/ai/basic_mobs/targetting_datums/with_object.dm deleted file mode 100644 index 91e99bb4a221cc..00000000000000 --- a/code/datums/ai/basic_mobs/targetting_datums/with_object.dm +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Find mobs who are holding the configurable object type - * - * This is an extension of basic targeting behaviour, that allows you to - * only target the mob if they have a specific item in their hand. - * - */ -/datum/targetting_datum/basic/holding_object - // We will find mobs who are holding this object in their hands - var/object_type_path = null - -/** - * Create an instance of the holding object targeting datum - * - * * object_type_path Pass an object type path, this will be compared to the items - * in targets hands to filter the target list. - */ -/datum/targetting_datum/basic/holding_object/New(object_type_path) - if (!ispath(object_type_path)) - stack_trace("trying to create an item targeting datum with no valid typepath") - // Leaving object type as null will make this basically a noop - return - src.object_type_path = object_type_path - -///Returns true or false depending on if the target can be attacked by the mob -/datum/targetting_datum/basic/holding_object/can_attack(mob/living/living_mob, atom/target, vision_range) - if (object_type_path == null) - return FALSE // no op - if(!ismob(target)) - return FALSE // no hands no problems - - // Look at me, type casting like a grown up - var/mob/targetmob = target - // Check if our parent behaviour agrees we can attack this target (we ignore faction by default) - var/can_attack = ..() - if(can_attack && targetmob.is_holding_item_of_type(object_type_path)) - return TRUE // they have the item - // No valid target - return FALSE diff --git a/code/datums/ai/dog/dog_behaviors.dm b/code/datums/ai/dog/dog_behaviors.dm index 6c9cb779bb3bd7..c7723eab1a182a 100644 --- a/code/datums/ai/dog/dog_behaviors.dm +++ b/code/datums/ai/dog/dog_behaviors.dm @@ -7,18 +7,18 @@ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM required_distance = 3 -/datum/ai_behavior/basic_melee_attack/dog/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_melee_attack/dog/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) controller.behavior_cooldowns[src] = world.time + action_cooldown var/mob/living/living_pawn = controller.pawn if(!(isturf(living_pawn.loc) || HAS_TRAIT(living_pawn, TRAIT_AI_BAGATTACK))) // Void puppies can attack from inside bags - finish_action(controller, FALSE, target_key, targetting_datum_key, hiding_location_key) + finish_action(controller, FALSE, target_key, targeting_strategy_key, hiding_location_key) return // Unfortunately going to repeat this check in parent call but what can you do var/atom/target = controller.blackboard[target_key] - var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] - if (!targetting_datum.can_attack(living_pawn, target)) - finish_action(controller, FALSE, target_key, targetting_datum_key, hiding_location_key) + var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) + if (!targeting_strategy.can_attack(living_pawn, target)) + finish_action(controller, FALSE, target_key, targeting_strategy_key, hiding_location_key) return if (!living_pawn.Adjacent(target)) diff --git a/code/datums/ai/dog/dog_controller.dm b/code/datums/ai/dog/dog_controller.dm index a95e3d57b6b200..6710fa9eb7650a 100644 --- a/code/datums/ai/dog/dog_controller.dm +++ b/code/datums/ai/dog/dog_controller.dm @@ -2,7 +2,7 @@ blackboard = list( BB_DOG_HARASS_HARM = TRUE, BB_VISION_RANGE = AI_DOG_VISION_RANGE, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, ) ai_movement = /datum/ai_movement/basic_avoidance idle_behavior = /datum/idle_behavior/idle_dog @@ -19,9 +19,11 @@ blackboard = list( BB_DOG_HARASS_HARM = TRUE, BB_VISION_RANGE = AI_DOG_VISION_RANGE, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, - // Find nearby mobs with tongs in hand. - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/holding_object(/obj/item/kitchen/tongs), + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, + // Find nearby mobs ... + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/holding_object, + // With tongs in hand! + BB_TARGET_HELD_ITEM = /obj/item/kitchen/tongs, BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/pet/dog), BB_BABIES_CHILD_TYPES = list(/mob/living/basic/pet/dog/corgi/puppy = 95, /mob/living/basic/pet/dog/corgi/puppy/void = 5), ) @@ -31,7 +33,7 @@ /datum/ai_planning_subtree/make_babies, // Ian WILL prioritise sex over following your instructions /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/dog_harassment, - // Find targets to run away from (uses the targetting datum from above) + // Find targets to run away from (uses the targeting strategy from above) /datum/ai_planning_subtree/simple_find_target, // Flee from that target /datum/ai_planning_subtree/flee_target, diff --git a/code/datums/ai/dog/dog_subtrees.dm b/code/datums/ai/dog/dog_subtrees.dm index 66198b61ac305f..62f63da54bdd0e 100644 --- a/code/datums/ai/dog/dog_subtrees.dm +++ b/code/datums/ai/dog/dog_subtrees.dm @@ -4,27 +4,27 @@ /datum/ai_planning_subtree/dog_harassment/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) if(!SPT_PROB(10, seconds_per_tick)) return - controller.queue_behavior(/datum/ai_behavior/find_hated_dog_target, BB_DOG_HARASS_TARGET, BB_PET_TARGETTING_DATUM) + controller.queue_behavior(/datum/ai_behavior/find_hated_dog_target, BB_DOG_HARASS_TARGET, BB_PET_TARGETING_STRATEGY) var/atom/harass_target = controller.blackboard[BB_DOG_HARASS_TARGET] if (isnull(harass_target)) return - controller.queue_behavior(/datum/ai_behavior/basic_melee_attack/dog, BB_DOG_HARASS_TARGET, BB_PET_TARGETTING_DATUM) + controller.queue_behavior(/datum/ai_behavior/basic_melee_attack/dog, BB_DOG_HARASS_TARGET, BB_PET_TARGETING_STRATEGY) return SUBTREE_RETURN_FINISH_PLANNING /datum/ai_behavior/find_hated_dog_target -/datum/ai_behavior/find_hated_dog_target/setup(datum/ai_controller/controller, target_key, targetting_datum_key) +/datum/ai_behavior/find_hated_dog_target/setup(datum/ai_controller/controller, target_key, targeting_strategy_key) . = ..() var/mob/living/dog = controller.pawn - var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] + var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) for(var/mob/living/iter_living in oview(2, dog)) if(iter_living.stat != CONSCIOUS || !HAS_TRAIT(iter_living, TRAIT_HATED_BY_DOGS)) continue if(!isnull(dog.buckled)) dog.audible_message(span_notice("[dog] growls at [iter_living], yet [dog.p_they()] [dog.p_are()] much too comfy to move."), hearing_distance = COMBAT_MESSAGE_RANGE) continue - if(!targetting_datum.can_attack(dog, iter_living)) + if(!targeting_strategy.can_attack(dog, iter_living)) continue dog.audible_message(span_warning("[dog] growls at [iter_living], seemingly annoyed by [iter_living.p_their()] presence."), hearing_distance = COMBAT_MESSAGE_RANGE) diff --git a/code/datums/ai/generic/find_and_set.dm b/code/datums/ai/generic/find_and_set.dm index 43337674969b16..8ecc6df7cfbbb5 100644 --- a/code/datums/ai/generic/find_and_set.dm +++ b/code/datums/ai/generic/find_and_set.dm @@ -135,3 +135,20 @@ if (nearby_bodies.len) return pick(nearby_bodies) + +/** + * A variant that looks for a human who is not dead or incapacitated, and has a mind + */ +/datum/ai_behavior/find_and_set/conscious_person + +/datum/ai_behavior/find_and_set/conscious_person/search_tactic(datum/ai_controller/controller, locate_path, search_range) + var/list/customers = list() + for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn)) + if(IS_DEAD_OR_INCAP(target) || !target.mind) + continue + customers += target + + if(customers.len) + return pick(customers) + + return null diff --git a/code/datums/ai/idle_behaviors/idle_random_walk.dm b/code/datums/ai/idle_behaviors/idle_random_walk.dm index d99957f419bb16..8924da5c30bb0f 100644 --- a/code/datums/ai/idle_behaviors/idle_random_walk.dm +++ b/code/datums/ai/idle_behaviors/idle_random_walk.dm @@ -10,7 +10,10 @@ if(SPT_PROB(walk_chance, seconds_per_tick) && (living_pawn.mobility_flags & MOBILITY_MOVE) && isturf(living_pawn.loc) && !living_pawn.pulledby) var/move_dir = pick(GLOB.alldirs) - living_pawn.Move(get_step(living_pawn, move_dir), move_dir) + var/turf/destination_turf = get_step(living_pawn, move_dir) + if(!destination_turf?.can_cross_safely(living_pawn)) + return + living_pawn.Move(destination_turf, move_dir) /datum/idle_behavior/idle_random_walk/less_walking walk_chance = 10 @@ -25,6 +28,20 @@ return return ..() +/// Only walk if we are not on the target's location +/datum/idle_behavior/idle_random_walk/not_while_on_target + ///What is the spot we have to stand on? + var/target_key + +/datum/idle_behavior/idle_random_walk/not_while_on_target/perform_idle_behavior(seconds_per_tick, datum/ai_controller/controller) + var/atom/target = controller.blackboard[target_key] + + //Don't move, if we are are already standing on it + if(!QDELETED(target) && ((isturf(target) && controller.pawn.loc == target) || (target.loc == controller.pawn.loc))) + return + + return ..() + /// walk randomly however stick near a target /datum/idle_behavior/walk_near_target /// chance to walk @@ -55,7 +72,7 @@ var/turf/possible_step = get_step(living_pawn, direction) if(get_dist(possible_step, target) > minimum_distance) continue - if(possible_step.is_blocked_turf()) + if(possible_step.is_blocked_turf() || !possible_step.can_cross_safely(living_pawn)) continue possible_turfs += possible_step diff --git a/code/datums/ai/learn_ai.md b/code/datums/ai/learn_ai.md index 9906806cfbd578..e4e8a712cf0bfe 100644 --- a/code/datums/ai/learn_ai.md +++ b/code/datums/ai/learn_ai.md @@ -25,7 +25,7 @@ First, let's look at the blackboard. ```dm /datum/ai_controller/basic/cow blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items(), + BB_TARGETING_STRATEGY = new /datum/targeting_strategy/basic/allow_items(), BB_BASIC_MOB_TIP_REACTING = FALSE, BB_BASIC_MOB_TIPPER = null, ) @@ -81,7 +81,7 @@ Okay, so we have blackboard variables, which are considered by subtrees to plan //now we know we have a target but should let a hostile subtree plan attacking humans. let's check if it's actually food if(target in wanted) - controller.queue_behavior(/datum/ai_behavior/basic_melee_attack, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/basic_melee_attack, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) return SUBTREE_RETURN_FINISH_PLANNING //this prevents further subtrees from planning since we want to focus on eating the food ``` @@ -94,7 +94,7 @@ And one of those behaviors, `basic_melee_attack`. As I have been doing so far, I //flag tells the AI it needs to have a movement target to work, and since it doesn't have "AI_BEHAVIOR_MOVE_AND_PERFORM", it won't call perform() every 0.6 seconds until it is in melee range. Smart! behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT -/datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) . = ..() //all this is doing in setup is setting the movement target. setup is called once when the behavior is first planned, and returning FALSE can cancel the behavior if something isn't right. @@ -107,20 +107,20 @@ And one of those behaviors, `basic_melee_attack`. As I have been doing so far, I controller.current_movement_target = target ///perform will run every "action_cooldown" deciseconds as long as the conditions are good for it to do so (we set "AI_BEHAVIOR_REQUIRE_MOVEMENT", so it won't perform until in range). -/datum/ai_behavior/basic_melee_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_melee_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) . = ..() var/mob/living/basic/basic_mob = controller.pawn - //targetting datum will kill the action if not real anymore + //targeting strategy will kill the action if not real anymore var/datum/weakref/weak_target = controller.blackboard[target_key] var/atom/target = weak_target?.resolve() - var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] + var/datum/targeting_strategy/targeting_strategy = controller.blackboard[targeting_strategy_key] - if(!targetting_datum.can_attack(basic_mob, target)) + if(!targeting_strategy.can_attack(basic_mob, target)) ///We have a target that is no longer valid to attack. Remember that returning doesn't end the behavior, JUST this single performance. So we call "finish_action" with whether it succeeded in doing what it wanted to do (it didn't, so FALSE) and the blackboard keys passed into this behavior. finish_action(controller, FALSE, target_key) return //don't forget to end the performance too - var/hiding_target = targetting_datum.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something! + var/hiding_target = targeting_strategy.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something! controller.blackboard[hiding_location_key] = hiding_target @@ -131,7 +131,7 @@ And one of those behaviors, `basic_melee_attack`. As I have been doing so far, I basic_mob.melee_attack(target) ///and so the action has ended. we can now clean up the AI's blackboard based on the success of the action, and the keys passed in. -/datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key) . = ..() ///if the behavior failed, the target is no longer valid, so we should lose aggro of them. We remove the target_key (which could be anything, it's whatever key was passed into the behavior by the subtree) from the blackboard. Couldn't do THAT with normal variables! if(!succeeded) diff --git a/code/datums/ai/movement/_ai_movement.dm b/code/datums/ai/movement/_ai_movement.dm index 2b734ca24a920e..dac9ecac00164f 100644 --- a/code/datums/ai/movement/_ai_movement.dm +++ b/code/datums/ai/movement/_ai_movement.dm @@ -24,37 +24,49 @@ if(controller.pathing_attempts >= max_pathing_attempts) controller.CancelActions() -///Should the movement be allowed to happen? As of writing this, MOVELOOP_SKIP_STEP is defined as (1<<0) so be careful on using (return TRUE) or (can_move = TRUE; return can_move) +///Should the movement be allowed to happen? /datum/ai_movement/proc/allowed_to_move(datum/move_loop/source) + SHOULD_BE_PURE(TRUE) + var/atom/movable/pawn = source.moving var/datum/ai_controller/controller = source.extra_info - source.delay = controller.movement_delay var/can_move = TRUE - if(controller.ai_traits & STOP_MOVING_WHEN_PULLED && pawn.pulledby) //Need to store more state. Annoying. + if((controller.ai_traits & STOP_MOVING_WHEN_PULLED) && pawn.pulledby) //Need to store more state. Annoying. can_move = FALSE if(!isturf(pawn.loc)) //No moving if not on a turf can_move = FALSE + if(isliving(pawn)) + var/mob/living/pawn_mob = pawn + if(!(pawn_mob.mobility_flags & MOBILITY_MOVE)) + can_move = FALSE + + return can_move + +///Anything to do before moving; any checks if the pawn should be able to move should be placed in allowed_to_move() and called by this proc +/datum/ai_movement/proc/pre_move(datum/move_loop/source) + SIGNAL_HANDLER + SHOULD_NOT_OVERRIDE(TRUE) + + var/datum/ai_controller/controller = source.extra_info + // Check if this controller can actually run, so we don't chase people with corpses if(!controller.able_to_run()) controller.CancelActions() qdel(source) //stop moving return MOVELOOP_SKIP_STEP - //Why doesn't this return TRUE or can_move? - //MOVELOOP_SKIP_STEP is defined as (1<<0) and TRUE are defined as the same "1", returning TRUE would be the equivalent of skipping the move - if(can_move) + source.delay = controller.movement_delay + + // Why doesn't this return TRUE? + // MOVELOOP_SKIP_STEP is defined as (1<<0) and TRUE are defined as the same "1", returning TRUE would be the equivalent of skipping the move + if(allowed_to_move(source)) return increment_pathing_failures(controller) return MOVELOOP_SKIP_STEP -///Anything to do before moving; any checks if the pawn should be able to move should be placed in allowed_to_move() and called by this proc -/datum/ai_movement/proc/pre_move(datum/move_loop/source) - SIGNAL_HANDLER - return allowed_to_move(source) - //Anything to do post movement /datum/ai_movement/proc/post_move(datum/move_loop/source, succeeded) SIGNAL_HANDLER diff --git a/code/datums/ai/movement/ai_movement_basic_avoidance.dm b/code/datums/ai/movement/ai_movement_basic_avoidance.dm index 371fb9dbc4bdf7..6b48f1b5e9e1f1 100644 --- a/code/datums/ai/movement/ai_movement_basic_avoidance.dm +++ b/code/datums/ai/movement/ai_movement_basic_avoidance.dm @@ -16,10 +16,8 @@ /datum/ai_movement/basic_avoidance/allowed_to_move(datum/move_loop/has_target/dist_bound/source) . = ..() var/turf/target_turf = get_step_towards(source.moving, source.target) - - if(is_type_in_typecache(target_turf, GLOB.dangerous_turfs)) - . = FALSE - return . + if(!target_turf?.can_cross_safely(source.moving)) + return FALSE /// Move immediately and don't update our facing /datum/ai_movement/basic_avoidance/backstep diff --git a/code/datums/ai/movement/ai_movement_complete_stop.dm b/code/datums/ai/movement/ai_movement_complete_stop.dm index 7805eeb3f6f656..f47b202b5a1b6f 100644 --- a/code/datums/ai/movement/ai_movement_complete_stop.dm +++ b/code/datums/ai/movement/ai_movement_complete_stop.dm @@ -12,4 +12,4 @@ RegisterSignal(loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(pre_move)) /datum/ai_movement/complete_stop/allowed_to_move(datum/move_loop/source) - return // no movement allowed + return FALSE diff --git a/code/datums/ai/movement/ai_movement_dumb.dm b/code/datums/ai/movement/ai_movement_dumb.dm index a38024ff2cc8d9..06ac4bdd10c4cb 100644 --- a/code/datums/ai/movement/ai_movement_dumb.dm +++ b/code/datums/ai/movement/ai_movement_dumb.dm @@ -14,7 +14,5 @@ /datum/ai_movement/dumb/allowed_to_move(datum/move_loop/has_target/source) . = ..() var/turf/target_turf = get_step_towards(source.moving, source.target) - - if(is_type_in_typecache(target_turf, GLOB.dangerous_turfs)) - . = FALSE - return . + if(!target_turf?.can_cross_safely(source.moving)) + return FALSE diff --git a/code/datums/brain_damage/creepy_trauma.dm b/code/datums/brain_damage/creepy_trauma.dm index 0203a78b2f7d24..1b19b4744cb75c 100644 --- a/code/datums/brain_damage/creepy_trauma.dm +++ b/code/datums/brain_damage/creepy_trauma.dm @@ -67,6 +67,7 @@ /datum/brain_trauma/special/obsessed/on_lose() ..() owner.mind.remove_antag_datum(/datum/antagonist/obsessed) + owner.clear_mood_event("creeping") if(obsession) UnregisterSignal(obsession, COMSIG_MOB_EYECONTACT) diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 48fabd701f45b4..61175593ce4d7f 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -83,8 +83,7 @@ var/mob/living/owner var/bubble_icon = "default" - var/datum/action/innate/imaginary_join/join - var/datum/action/innate/imaginary_hide/hide + /mob/camera/imaginary_friend/Login() . = ..() @@ -105,10 +104,11 @@ */ /mob/camera/imaginary_friend/Initialize(mapload) . = ..() - join = new - join.Grant(src) - hide = new - hide.Grant(src) + var/static/list/grantable_actions = list( + /datum/action/innate/imaginary_join, + /datum/action/innate/imaginary_hide, + ) + grant_actions_by_list(grantable_actions) /// Links this imaginary friend to the provided mob /mob/camera/imaginary_friend/proc/attach_to_owner(mob/living/imaginary_friend_owner) diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm index ed3e91707b99d8..81d354a19e841c 100644 --- a/code/datums/brain_damage/special.dm +++ b/code/datums/brain_damage/special.dm @@ -107,6 +107,10 @@ . = ..() QDEL_IN(src, 30 SECONDS) +/obj/effect/client_image_holder/bluespace_stream/generate_image() + . = ..() + apply_wibbly_filters(.) + /obj/effect/client_image_holder/bluespace_stream/Destroy() if(!QDELETED(linked_to)) qdel(linked_to) diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm index e5890a5fa9b869..faa05a6bd28ea1 100644 --- a/code/datums/brain_damage/split_personality.dm +++ b/code/datums/brain_damage/split_personality.dm @@ -25,11 +25,11 @@ /datum/brain_trauma/severe/split_personality/proc/make_backseats() stranger_backseat = new(owner, src) - var/datum/action/cooldown/spell/personality_commune/stranger_spell = new(src) + var/datum/action/personality_commune/stranger_spell = new(src) stranger_spell.Grant(stranger_backseat) owner_backseat = new(owner, src) - var/datum/action/cooldown/spell/personality_commune/owner_spell = new(src) + var/datum/action/personality_commune/owner_spell = new(src) owner_spell.Grant(owner_backseat) /// Attempts to get a ghost to play the personality @@ -256,13 +256,20 @@ gain_text = span_warning("Crap, that was one drink too many. You black out...") lose_text = "You wake up very, very confused and hungover. All you can remember is drinking a lot of alcohol... what happened?" poll_role = "blacked out drunkard" + random_gain = FALSE /// Duration of effect, tracked in seconds, not deciseconds. qdels when reaching 0. var/duration_in_seconds = 180 /datum/brain_trauma/severe/split_personality/blackout/on_gain() . = ..() RegisterSignal(owner, COMSIG_ATOM_SPLASHED, PROC_REF(on_splashed)) - notify_ghosts("[owner] is blacking out!", source = owner, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Bro I'm not even drunk right now") + notify_ghosts( + "[owner] is blacking out!", + source = owner, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Bro I'm not even drunk right now", + ) /datum/brain_trauma/severe/split_personality/blackout/on_lose() . = ..() diff --git a/code/datums/components/appearance_on_aggro.dm b/code/datums/components/appearance_on_aggro.dm index 33a3d7c2e90d65..8c0df88e6fdbc4 100644 --- a/code/datums/components/appearance_on_aggro.dm +++ b/code/datums/components/appearance_on_aggro.dm @@ -45,7 +45,6 @@ return current_target = target - RegisterSignal(target, COMSIG_QDELETING, PROC_REF(on_clear_target)) if (!isnull(aggro_overlay) || !isnull(aggro_state)) source.update_appearance(UPDATE_ICON) if (!isnull(alpha_on_aggro)) @@ -61,7 +60,6 @@ revert_appearance(parent) /datum/component/appearance_on_aggro/proc/revert_appearance(mob/living/source) - UnregisterSignal(current_target, COMSIG_QDELETING) current_target = null if (!isnull(aggro_overlay) || !isnull(aggro_state)) source.update_appearance(UPDATE_ICON) diff --git a/code/datums/components/bumpattack.dm b/code/datums/components/bumpattack.dm index ec8cd272a44626..a305b43c25bb75 100644 --- a/code/datums/components/bumpattack.dm +++ b/code/datums/components/bumpattack.dm @@ -64,7 +64,7 @@ var/obj/item/our_weapon = proxy_weapon || parent if(!istype(our_weapon)) CRASH("[our_weapon] somehow failed istype") - if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_BUMP_ATTACK)) + if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_BUMP_ATTACK)) TIMER_COOLDOWN_START(src, COOLDOWN_BUMP_ATTACK, attack_cooldown) INVOKE_ASYNC(target, TYPE_PROC_REF(/atom, attackby), our_weapon, bumper) bumper.visible_message(span_danger("[bumper] charges into [target], attacking with [our_weapon]!"), span_danger("You charge into [target], attacking with [our_weapon]!"), vision_distance = COMBAT_MESSAGE_RANGE) diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm index 94a943b42c8fd0..a8b64f428d9a5d 100644 --- a/code/datums/components/crafting/ranged_weapon.dm +++ b/code/datums/components/crafting/ranged_weapon.dm @@ -206,6 +206,36 @@ time = 5 SECONDS category = CAT_WEAPON_RANGED +/datum/crafting_recipe/rebarxbow + name = "Heated Rebar Crossbow" + result = /obj/item/gun/ballistic/rifle/rebarxbow + reqs = list( + /obj/item/stack/rods = 6, + /obj/item/stack/cable_coil = 12, + /obj/item/inducer = 1, + ) + blacklist = list( + /obj/item/inducer/sci, + ) + tool_behaviors = list(TOOL_WELDER) + time = 5 SECONDS + category = CAT_WEAPON_RANGED + +/datum/crafting_recipe/rebarxbowforced + name = "Forced Rebar Crossbow" + desc = "Get an extra shot in your crossbow... for a chance of shooting yourself when you fire it." + result = /obj/item/gun/ballistic/rifle/rebarxbow/forced + reqs = list( + /obj/item/gun/ballistic/rifle/rebarxbow = 1, + ) + blacklist = list( + /obj/item/gun/ballistic/rifle/rebarxbow/forced, + /obj/item/gun/ballistic/rifle/rebarxbow/syndie, + ) + tool_behaviors = list(TOOL_CROWBAR) + time = 1 SECONDS + category = CAT_WEAPON_RANGED + /datum/crafting_recipe/pipegun_prime name = "Regal Pipegun" always_available = FALSE diff --git a/code/datums/components/crafting/weapon_ammo.dm b/code/datums/components/crafting/weapon_ammo.dm index 437bfaa2e92029..44b8055b3ff94b 100644 --- a/code/datums/components/crafting/weapon_ammo.dm +++ b/code/datums/components/crafting/weapon_ammo.dm @@ -12,6 +12,17 @@ time = 0.5 SECONDS category = CAT_WEAPON_AMMO +/datum/crafting_recipe/rebarsyndie + name = "jagged iron rod" + result = /obj/item/ammo_casing/rebar/syndie + reqs = list( + /obj/item/stack/rods = 1, + ) + tool_behaviors = list(TOOL_WIRECUTTER) + time = 0.5 SECONDS + always_available = FALSE + category = CAT_WEAPON_AMMO + /datum/crafting_recipe/pulseslug name = "Pulse Slug Shell" result = /obj/item/ammo_casing/shotgun/pulseslug diff --git a/code/datums/components/cult_ritual_item.dm b/code/datums/components/cult_ritual_item.dm index 6d098ecc44e3a4..a155e904c7ff6f 100644 --- a/code/datums/components/cult_ritual_item.dm +++ b/code/datums/components/cult_ritual_item.dm @@ -368,11 +368,22 @@ if(!check_if_in_ritual_site(cultist, cult_team)) return FALSE var/area/summon_location = get_area(cultist) - priority_announce("Figments from an eldritch god are being summoned by [cultist.real_name] into [summon_location.get_original_area_name()] from an unknown dimension. Disrupt the ritual at all costs!", "Central Command Higher Dimensional Affairs", sound = 'sound/ambience/antag/bloodcult/bloodcult_scribe.ogg', has_important_message = TRUE) + priority_announce( + text = "Figments from an eldritch god are being summoned by [cultist.real_name] into [summon_location.get_original_area_name()] from an unknown dimension. Disrupt the ritual at all costs!", + sound = 'sound/ambience/antag/bloodcult/bloodcult_scribe.ogg', + sender_override = "[command_name()] Higher Dimensional Affairs", + has_important_message = TRUE, + ) for(var/shielded_turf in spiral_range_turfs(1, cultist, 1)) LAZYADD(shields, new /obj/structure/emergency_shield/cult/narsie(shielded_turf)) - notify_ghosts("[cultist] has begun scribing a Nar'Sie rune!", source = cultist, action = NOTIFY_ORBIT, header = "Maranax Infirmux!") + notify_ghosts( + "[cultist] has begun scribing a Nar'Sie rune!", + source = cultist, + action = NOTIFY_ORBIT, + header = "Maranax Infirmux!", + notify_flags = NOTIFY_CATEGORY_NOFLASH, + ) return TRUE diff --git a/code/datums/components/damage_chain.dm b/code/datums/components/damage_chain.dm new file mode 100644 index 00000000000000..be61ec68a33cc1 --- /dev/null +++ b/code/datums/components/damage_chain.dm @@ -0,0 +1,112 @@ +/** + * Draws a line between you and another atom, hurt anyone stood in the line + */ +/datum/component/damage_chain + dupe_mode = COMPONENT_DUPE_ALLOWED + /// How often do we attempt to deal damage? + var/tick_interval + /// Tracks when we can next deal damage + COOLDOWN_DECLARE(tick_cooldown) + /// Damage inflicted per tick + var/damage_per_tick + /// Type of damage to inflict + var/damage_type + /// Optional callback which checks if we can damage the target + var/datum/callback/validate_target + /// Optional callback for additional visuals or text display when dealing damage + var/datum/callback/chain_damage_feedback + /// We will fire the damage feedback callback on every x successful attacks + var/feedback_interval + /// How many successful attacks have we made? + var/successful_attacks = 0 + /// Time between making any attacks at which we just reset the successful attack counter + var/reset_feedback_timer = 0 + /// Our chain + var/datum/beam/chain + +/datum/component/damage_chain/Initialize( + atom/linked_to, + max_distance = 7, + beam_icon = 'icons/effects/beam.dmi', + beam_state = "medbeam", + beam_type = /obj/effect/ebeam, + tick_interval = 0.3 SECONDS, + damage_per_tick = 1.2, + damage_type = BURN, + datum/callback/validate_target = null, + datum/callback/chain_damage_feedback = null, + feedback_interval = 5, +) + . = ..() + if (!isatom(parent)) + return COMPONENT_INCOMPATIBLE + if (!isatom(linked_to)) + CRASH("Attempted to create [type] linking [parent.type] with non-atom [linked_to]!") + + src.tick_interval = tick_interval + src.damage_per_tick = damage_per_tick + src.damage_type = damage_type + src.validate_target = validate_target + src.chain_damage_feedback = chain_damage_feedback + src.feedback_interval = feedback_interval + + var/atom/atom_parent = parent + chain = atom_parent.Beam(linked_to, icon = beam_icon, icon_state = beam_state, beam_type = beam_type, maxdistance = max_distance) + RegisterSignal(chain, COMSIG_QDELETING, PROC_REF(end_beam)) + START_PROCESSING(SSfastprocess, src) + +/datum/component/damage_chain/RegisterWithParent() + RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(end_beam)) // We actually don't really use many signals it's all processing + +/datum/component/damage_chain/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_LIVING_DEATH) + +/datum/component/damage_chain/Destroy(force, silent) + if (!QDELETED(chain)) + UnregisterSignal(chain, COMSIG_QDELETING) + QDEL_NULL(chain) + chain = null + STOP_PROCESSING(SSfastprocess, src) + return ..() + +/// Destroy ourself +/datum/component/damage_chain/proc/end_beam() + SIGNAL_HANDLER + qdel(src) + +/datum/component/damage_chain/process(seconds_per_tick) + var/successful_hit = FALSE + var/list/target_turfs = list() + for(var/obj/effect/ebeam/chainpart in chain.elements) + if (isnull(chainpart) || !chainpart.x || !chainpart.y || !chainpart.z) + continue + var/turf/overlaps = get_turf_pixel(chainpart) + target_turfs |= overlaps + if(overlaps == get_turf(chain.origin) || overlaps == get_turf(chain.target)) + continue + for(var/turf/nearby_turf in circle_range(overlaps, 1)) + target_turfs |= nearby_turf + + for(var/turf/hit_turf as anything in target_turfs) + for(var/mob/living/victim in hit_turf) + if (victim == parent || victim.stat == DEAD) + continue + if (!isnull(validate_target) && !validate_target.Invoke(victim)) + continue + if (successful_attacks == 0) + chain_damage_feedback?.Invoke(victim) + victim.apply_damage(damage_per_tick, damage_type, wound_bonus = CANT_WOUND) + successful_hit = TRUE + + if (isnull(chain_damage_feedback)) + return + if (successful_hit) + successful_attacks++ + reset_feedback_timer = addtimer(CALLBACK(src, PROC_REF(reset_feedback)), 10 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE|TIMER_DELETE_ME) + if (successful_attacks > feedback_interval) + reset_feedback() + +/// Make it so that the next time we hit something we'll invoke the feedback callback +/datum/component/damage_chain/proc/reset_feedback() + successful_attacks = 0 + deltimer(reset_feedback_timer) diff --git a/code/datums/components/deadchat_control.dm b/code/datums/components/deadchat_control.dm index 48096e47670645..2a00b2f955dc60 100644 --- a/code/datums/components/deadchat_control.dm +++ b/code/datums/components/deadchat_control.dm @@ -39,7 +39,12 @@ if(deadchat_mode & ANARCHY_MODE) // Choose one, please. stack_trace("deadchat_control component added to [parent.type] with both democracy and anarchy modes enabled.") timerid = addtimer(CALLBACK(src, PROC_REF(democracy_loop)), input_cooldown, TIMER_STOPPABLE | TIMER_LOOP) - notify_ghosts("[parent] is now deadchat controllable!", source = parent, action = NOTIFY_ORBIT, header="Something Interesting!") + notify_ghosts( + "[parent] is now deadchat controllable!", + source = parent, + action = NOTIFY_ORBIT, + header = "Something Interesting!", + ) if(!ismob(parent) && !SSpoints_of_interest.is_valid_poi(parent)) SSpoints_of_interest.make_point_of_interest(parent) generated_point_of_interest = TRUE diff --git a/code/datums/components/direct_explosive_trap.dm b/code/datums/components/direct_explosive_trap.dm new file mode 100644 index 00000000000000..0d204f21a1ee7b --- /dev/null +++ b/code/datums/components/direct_explosive_trap.dm @@ -0,0 +1,85 @@ +/** + * Responds to certain signals and 'explodes' on the person using the item. + * Differs from `interaction_booby_trap` in that this doesn't actually explode, it just directly calls ex_act on one person. + */ +/datum/component/direct_explosive_trap + /// An optional mob to inform about explosions + var/mob/living/saboteur + /// Amount of force to apply + var/explosive_force + /// Colour for examine notification + var/glow_colour + /// Optional additional target checks before we go off + var/datum/callback/explosive_checks + /// Signals which set off the bomb, must pass a mob as the first non-source argument + var/list/triggering_signals + +/datum/component/direct_explosive_trap/Initialize( + mob/living/saboteur, + explosive_force = EXPLODE_HEAVY, + expire_time = 1 MINUTES, + glow_colour = COLOR_RED, + datum/callback/explosive_checks, + list/triggering_signals = list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BUMPED) +) + . = ..() + if (!isatom(parent)) + return COMPONENT_INCOMPATIBLE + src.saboteur = saboteur + src.explosive_force = explosive_force + src.glow_colour = glow_colour + src.explosive_checks = explosive_checks + src.triggering_signals = triggering_signals + + if (expire_time > 0) + addtimer(CALLBACK(src, PROC_REF(bomb_expired)), expire_time, TIMER_DELETE_ME) + +/datum/component/direct_explosive_trap/RegisterWithParent() + if (!(COMSIG_ATOM_EXAMINE in triggering_signals)) // Maybe you're being extra mean with this one + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined)) + RegisterSignals(parent, triggering_signals, PROC_REF(explode)) + if (!isnull(saboteur)) + RegisterSignal(saboteur, COMSIG_QDELETING, PROC_REF(on_bomber_deleted)) + +/datum/component/direct_explosive_trap/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_ATOM_EXAMINE) + triggering_signals) + if (!isnull(saboteur)) + UnregisterSignal(saboteur, COMSIG_QDELETING) + +/datum/component/direct_explosive_trap/Destroy(force, silent) + if (isnull(saboteur)) + return ..() + UnregisterSignal(saboteur, COMSIG_QDELETING) + saboteur = null + return ..() + +/// Called if we sit too long without going off +/datum/component/direct_explosive_trap/proc/bomb_expired() + if (!isnull(saboteur)) + to_chat(saboteur, span_bolddanger("Failure! Your trap didn't catch anyone this time...")) + qdel(src) + +/// Let people know something is up +/datum/component/direct_explosive_trap/proc/on_examined(datum/source, mob/user, text) + SIGNAL_HANDLER + text += span_holoparasite("It glows with a strange light...") + +/// Blow up +/datum/component/direct_explosive_trap/proc/explode(atom/source, mob/living/victim) + SIGNAL_HANDLER + if (!isliving(victim)) + return + if (!isnull(explosive_checks) && !explosive_checks.Invoke(victim)) + return + to_chat(victim, span_bolddanger("[source] was boobytrapped!")) + if (!isnull(saboteur)) + to_chat(saboteur, span_bolddanger("Success! Your trap on [source] caught [victim.name]!")) + playsound(source, 'sound/effects/explosion2.ogg', 200, TRUE) + new /obj/effect/temp_visual/explosion(get_turf(source)) + EX_ACT(victim, explosive_force) + qdel(src) + +/// Don't hang a reference to the person who placed the bomb +/datum/component/direct_explosive_trap/proc/on_bomber_deleted() + SIGNAL_HANDLER + saboteur = null diff --git a/code/datums/components/energized.dm b/code/datums/components/energized.dm index 64adeb5e9be6b5..41262e23efc6a5 100644 --- a/code/datums/components/energized.dm +++ b/code/datums/components/energized.dm @@ -106,7 +106,12 @@ return FALSE // Finally the interesting part where they ACTUALLY get hit! - notify_ghosts("[future_tram_victim] has fallen in the path of an oncoming tram!", source = future_tram_victim, action = NOTIFY_ORBIT, header = "Electrifying!") + notify_ghosts( + "[future_tram_victim] has fallen in the path of an oncoming tram!", + source = future_tram_victim, + action = NOTIFY_ORBIT, + header = "Electrifying!", + ) playsound(src, SFX_SPARKS, 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) source.audible_message(span_danger("[parent] makes a loud electric crackle!")) to_chat(future_tram_victim, span_userdanger("You hear a loud electric crackle!")) diff --git a/code/datums/components/explode_on_attack.dm b/code/datums/components/explode_on_attack.dm new file mode 100644 index 00000000000000..0560184f2ba0a8 --- /dev/null +++ b/code/datums/components/explode_on_attack.dm @@ -0,0 +1,40 @@ +/** + * Bombs the user after an attack + */ +/datum/component/explode_on_attack + /// range of bomb impact + var/impact_range + /// should we be destroyed after the explosion? + var/destroy_on_explode + /// list of mobs we wont bomb on attack + var/list/mob_type_dont_bomb + +/datum/component/explode_on_attack/Initialize(impact_range = 1, destroy_on_explode = TRUE, list/mob_type_dont_bomb = list()) + if(!isliving(parent)) + return COMPONENT_INCOMPATIBLE + src.impact_range = impact_range + src.destroy_on_explode = destroy_on_explode + src.mob_type_dont_bomb = mob_type_dont_bomb + +/datum/component/explode_on_attack/RegisterWithParent() + RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(bomb_target)) + +/datum/component/explode_on_attack/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET) + + +/datum/component/explode_on_attack/proc/bomb_target(mob/living/owner, atom/victim) + SIGNAL_HANDLER + + if(!isliving(victim)) + return + + if(is_type_in_typecache(victim, mob_type_dont_bomb)) + return + + explosion(owner, light_impact_range = impact_range, explosion_cause = src) + + if(destroy_on_explode && owner) + qdel(owner) + return COMPONENT_HOSTILE_NO_ATTACK + diff --git a/code/datums/components/fishing_spot.dm b/code/datums/components/fishing_spot.dm index f88c27a7135306..05456380235afb 100644 --- a/code/datums/components/fishing_spot.dm +++ b/code/datums/components/fishing_spot.dm @@ -36,7 +36,7 @@ if(HAS_TRAIT(user,TRAIT_GONE_FISHING) || rod.currently_hooked_item) user.balloon_alert(user, "already fishing") return COMPONENT_NO_AFTERATTACK - var/denial_reason = fish_source.reason_we_cant_fish(rod, user) + var/denial_reason = fish_source.reason_we_cant_fish(rod, user, parent) if(denial_reason) to_chat(user, span_warning(denial_reason)) return COMPONENT_NO_AFTERATTACK diff --git a/code/datums/components/food/germ_sensitive.dm b/code/datums/components/food/germ_sensitive.dm index 22ba793c1ce3ad..d0acc49714ab59 100644 --- a/code/datums/components/food/germ_sensitive.dm +++ b/code/datums/components/food/germ_sensitive.dm @@ -25,7 +25,7 @@ GLOBAL_LIST_INIT(floor_diseases, list( RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examine)) RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(handle_movement)) - RegisterSignal(parent, COMSIG_ATOM_WASHED, PROC_REF(wash)) //Wash germs off dirty things + RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(wash)) //Wash germs off dirty things RegisterSignals(parent, list( COMSIG_ITEM_DROPPED, //Dropped into the world @@ -46,13 +46,13 @@ GLOBAL_LIST_INIT(floor_diseases, list( /datum/component/germ_sensitive/UnregisterFromParent() REMOVE_TRAIT(parent, TRAIT_GERM_SENSITIVE, REF(src)) UnregisterSignal(parent, list( + COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXAMINE, - COMSIG_MOVABLE_MOVED, - COMSIG_ATOM_WASHED, - COMSIG_ITEM_DROPPED, COMSIG_ATOM_EXITED, + COMSIG_COMPONENT_CLEAN_ACT, + COMSIG_ITEM_DROPPED, COMSIG_ITEM_PICKUP, - COMSIG_ATOM_ENTERED, + COMSIG_MOVABLE_MOVED, )) /datum/component/germ_sensitive/Destroy() @@ -117,8 +117,10 @@ GLOBAL_LIST_INIT(floor_diseases, list( parent.AddComponent(/datum/component/infective, new random_disease, weak = TRUE) /datum/component/germ_sensitive/proc/wash() + SIGNAL_HANDLER if(infective) infective = FALSE qdel(parent.GetComponent(/datum/component/infective)) + return COMPONENT_CLEANED #undef GERM_EXPOSURE_DELAY diff --git a/code/datums/components/food/ghost_edible.dm b/code/datums/components/food/ghost_edible.dm index 25207800a7426f..ff524ed7a1c715 100644 --- a/code/datums/components/food/ghost_edible.dm +++ b/code/datums/components/food/ghost_edible.dm @@ -23,7 +23,12 @@ src.bite_chance = bite_chance src.minimum_scale = minimum_scale initial_reagent_volume = atom_parent.reagents.total_volume - notify_ghosts("[parent] is edible by ghosts!", source = parent, action = NOTIFY_ORBIT, header="Something Tasty!") + notify_ghosts( + "[parent] is edible by ghosts!", + source = parent, + action = NOTIFY_ORBIT, + header="Something Tasty!", + ) /datum/component/ghost_edible/RegisterWithParent() START_PROCESSING(SSdcs, src) diff --git a/code/datums/components/healing_touch.dm b/code/datums/components/healing_touch.dm index a81de7ab04a787..cf6ef88f24d60f 100644 --- a/code/datums/components/healing_touch.dm +++ b/code/datums/components/healing_touch.dm @@ -8,10 +8,15 @@ * This intercepts the attack and starts a do_after if the target is in its allowed type list. */ /datum/component/healing_touch + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS /// How much brute damage to heal var/heal_brute /// How much burn damage to heal var/heal_burn + /// How much toxin damage to heal + var/heal_tox + /// How much oxygen damage to heal + var/heal_oxy /// How much stamina damage to heal var/heal_stamina /// Interaction will use this key, and be blocked while this key is in use @@ -26,8 +31,8 @@ var/valid_biotypes /// Which kinds of carbon limbs can we heal, has no effect on non-carbon mobs. Set to null if you don't care about excluding prosthetics. var/required_bodytype - /// How targetting yourself works, expects one of HEALING_TOUCH_ANYONE, HEALING_TOUCH_NOT_SELF, or HEALING_TOUCH_SELF_ONLY - var/self_targetting + /// How targeting yourself works, expects one of HEALING_TOUCH_ANYONE, HEALING_TOUCH_NOT_SELF, or HEALING_TOUCH_SELF_ONLY + var/self_targeting /// Text to print when action starts, replaces %SOURCE% with healer and %TARGET% with healed mob var/action_text /// Text to print when action completes, replaces %SOURCE% with healer and %TARGET% with healed mob @@ -36,10 +41,16 @@ var/show_health /// Color for the healing effect var/heal_color + /// Optional click modifier required + var/required_modifier + /// Callback to run after healing a mob + var/datum/callback/after_healed /datum/component/healing_touch/Initialize( heal_brute = 20, heal_burn = 20, + heal_tox = 0, + heal_oxy = 0, heal_stamina = 0, heal_time = 2 SECONDS, interaction_key = DOAFTER_SOURCE_HEAL_TOUCH, @@ -47,17 +58,21 @@ list/valid_targets_typecache = list(), valid_biotypes = MOB_ORGANIC | MOB_MINERAL, required_bodytype = BODYTYPE_ORGANIC, - self_targetting = HEALING_TOUCH_NOT_SELF, + self_targeting = HEALING_TOUCH_NOT_SELF, action_text = "%SOURCE% begins healing %TARGET%", complete_text = "%SOURCE% finishes healing %TARGET%", show_health = FALSE, heal_color = COLOR_HEALING_CYAN, + required_modifier = null, + datum/callback/after_healed = null, ) if (!isliving(parent)) return COMPONENT_INCOMPATIBLE src.heal_brute = heal_brute src.heal_burn = heal_burn + src.heal_tox = heal_tox + src.heal_oxy = heal_oxy src.heal_stamina = heal_stamina src.heal_time = heal_time src.interaction_key = interaction_key @@ -65,15 +80,25 @@ src.valid_targets_typecache = valid_targets_typecache.Copy() src.valid_biotypes = valid_biotypes src.required_bodytype = required_bodytype - src.self_targetting = self_targetting + src.self_targeting = self_targeting src.action_text = action_text src.complete_text = complete_text src.show_health = show_health src.heal_color = heal_color + src.required_modifier = required_modifier + src.after_healed = after_healed RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(try_healing)) // Players RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(try_healing)) // NPCs +// Let's populate this list as we actually use it, this thing has too many args +/datum/component/healing_touch/InheritComponent( + datum/component/new_component, + i_am_original, + heal_color, +) + src.heal_color = heal_color + /datum/component/healing_touch/UnregisterFromParent() UnregisterSignal(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) return ..() @@ -83,12 +108,15 @@ return ..() /// Validate our target, and interrupt the attack chain to start healing it if it is allowed -/datum/component/healing_touch/proc/try_healing(mob/living/healer, atom/target) +/datum/component/healing_touch/proc/try_healing(mob/living/healer, atom/target, proximity, modifiers) SIGNAL_HANDLER if (!isliving(target)) return - if (!is_type_in_typecache(target, valid_targets_typecache)) + if (!isnull(required_modifier) && !LAZYACCESS(modifiers, required_modifier)) + return + + if (length(valid_targets_typecache) && !is_type_in_typecache(target, valid_targets_typecache)) return // Fall back to attacking it if (extra_checks && !extra_checks.Invoke(healer, target)) @@ -98,7 +126,7 @@ healer.balloon_alert(healer, "busy!") return COMPONENT_CANCEL_ATTACK_CHAIN - switch (self_targetting) + switch (self_targeting) if (HEALING_TOUCH_NOT_SELF) if (target == healer) healer.balloon_alert(healer, "can't heal yourself!") @@ -131,6 +159,10 @@ return FALSE if (target.getStaminaLoss() > 0 && heal_stamina) return TRUE + if (target.getOxyLoss() > 0 && heal_oxy) + return TRUE + if (target.getToxLoss() > 0 && heal_tox) + return TRUE if (!iscarbon(target)) return (target.getBruteLoss() > 0 && heal_brute) || (target.getFireLoss() > 0 && heal_burn) var/mob/living/carbon/carbon_target = target @@ -154,12 +186,26 @@ if (complete_text) healer.visible_message(span_notice("[format_string(complete_text, healer, target)]")) - target.heal_overall_damage(brute = heal_brute, burn = heal_burn, stamina = heal_stamina, required_bodytype = required_bodytype) + var/healed = target.heal_overall_damage( + brute = heal_brute, + burn = heal_burn, + stamina = heal_stamina, + required_bodytype = required_bodytype, + updating_health = FALSE, + ) + healed += target.adjustOxyLoss(-heal_oxy, updating_health = FALSE, required_biotype = valid_biotypes) + healed += target.adjustToxLoss(-heal_tox, updating_health = FALSE, required_biotype = valid_biotypes) + if (healed <= 0) + return + + target.updatehealth() new /obj/effect/temp_visual/heal(get_turf(target), heal_color) + after_healed?.Invoke(target) - if(show_health && !iscarbon(target)) - var/formatted_string = format_string("%TARGET% now has [target.health]/[target.maxHealth] health.", healer, target) - to_chat(healer, span_danger(formatted_string)) + if(!show_health) + return + var/formatted_string = format_string("%TARGET% now has [health_percentage(target)] health.", healer, target) + to_chat(healer, span_danger(formatted_string)) /// Reformats the passed string with the replacetext keys /datum/component/healing_touch/proc/format_string(string, atom/source, atom/target) diff --git a/code/datums/components/life_link.dm b/code/datums/components/life_link.dm new file mode 100644 index 00000000000000..34cdd0504c6bc7 --- /dev/null +++ b/code/datums/components/life_link.dm @@ -0,0 +1,169 @@ +/** + * A mob with this component passes all damage (and healing) it takes to another mob, passed as a parameter + * Essentially we use another mob's health bar as our health bar + */ +/datum/component/life_link + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + /// Mob we pass all of our damage to + var/mob/living/host + /// Optional callback invoked when damage gets transferred + var/datum/callback/on_passed_damage + /// Optional callback invoked when the linked mob dies + var/datum/callback/on_linked_death + +/datum/component/life_link/Initialize(mob/living/host, datum/callback/on_passed_damage, datum/callback/on_linked_death) + . = ..() + if (!isliving(parent)) + return COMPONENT_INCOMPATIBLE + if (!istype(host)) + CRASH("Life link created on [parent.type] and attempted to link to invalid type [host?.type].") + register_host(host) + src.on_passed_damage = on_passed_damage + src.on_linked_death = on_linked_death + +/datum/component/life_link/RegisterWithParent() + RegisterSignal(parent, COMSIG_CARBON_LIMB_DAMAGED, PROC_REF(on_limb_damage)) + RegisterSignals(parent, COMSIG_LIVING_ADJUST_STANDARD_DAMAGE_TYPES, PROC_REF(on_damage_adjusted)) + RegisterSignal(parent, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(on_health_updated)) + RegisterSignal(parent, COMSIG_MOB_GET_STATUS_TAB_ITEMS, PROC_REF(on_status_tab_updated)) + if (!isnull(host)) + var/mob/living/living_parent = parent + living_parent.updatehealth() + +/datum/component/life_link/UnregisterFromParent() + unregister_host() + UnregisterSignal(parent, list(COMSIG_CARBON_LIMB_DAMAGED, COMSIG_LIVING_HEALTH_UPDATE, COMSIG_MOB_GET_STATUS_TAB_ITEMS) + COMSIG_LIVING_ADJUST_STANDARD_DAMAGE_TYPES) + +/datum/component/life_link/InheritComponent(datum/component/new_comp, i_am_original, mob/living/host, datum/callback/on_passed_damage, datum/callback/on_linked_death) + register_host(host) + +/// Set someone up as our new host +/datum/component/life_link/proc/register_host(mob/living/new_host) + unregister_host() + if (isnull(new_host)) + return + host = new_host + RegisterSignal(host, COMSIG_LIVING_DEATH, PROC_REF(on_host_died)) + RegisterSignal(host, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(on_health_updated)) + RegisterSignal(host, COMSIG_LIVING_REVIVE, PROC_REF(on_host_revived)) + RegisterSignal(host, COMSIG_QDELETING, PROC_REF(on_host_deleted)) + var/mob/living/living_parent = parent + living_parent.updatehealth() + +/// Drop someone from being our host +/datum/component/life_link/proc/unregister_host() + if (isnull(host)) + return + UnregisterSignal(host, list(COMSIG_LIVING_DEATH, COMSIG_LIVING_HEALTH_UPDATE, COMSIG_LIVING_REVIVE, COMSIG_QDELETING)) + host = null + +/// Called when your damage goes up or down +/datum/component/life_link/proc/on_damage_adjusted(mob/living/our_mob, type, amount, forced) + SIGNAL_HANDLER + if (forced) + return + amount *= our_mob.get_damage_mod(type) + switch (type) + if(BRUTE) + host.adjustBruteLoss(amount, forced = TRUE) + if(BURN) + host.adjustFireLoss(amount, forced = TRUE) + if(TOX) + host.adjustToxLoss(amount, forced = TRUE) + if(OXY) + host.adjustOxyLoss(amount, forced = TRUE) + if(CLONE) + host.adjustCloneLoss(amount, forced = TRUE) + + on_passed_damage?.Invoke(our_mob, host, amount) + return COMPONENT_IGNORE_CHANGE + +/// Called when someone hurts one of our limbs, bypassing normal damage adjustment +/datum/component/life_link/proc/on_limb_damage(mob/living/our_mob, limb, brute, burn) + SIGNAL_HANDLER + if (brute != 0) + host.adjustBruteLoss(brute, updating_health = FALSE) + if (burn != 0) + host.adjustFireLoss(burn, updating_health = FALSE) + if (brute != 0 || burn != 0) + host.updatehealth() + on_passed_damage?.Invoke(our_mob, host, brute + burn) + return COMPONENT_PREVENT_LIMB_DAMAGE + +/// Called when either the host or parent's health tries to update, update our displayed health +/datum/component/life_link/proc/on_health_updated() + SIGNAL_HANDLER + update_health_hud(parent) + update_med_hud_health(parent) + update_med_hud_status(parent) + +/// Update our parent's health display based on how harmed our host is +/datum/component/life_link/proc/update_health_hud(mob/living/mob_parent) + var/severity = 0 + var/healthpercent = health_percentage(host) + switch(healthpercent) + if(100 to INFINITY) + severity = 0 + if(85 to 100) + severity = 1 + if(70 to 85) + severity = 2 + if(55 to 70) + severity = 3 + if(40 to 55) + severity = 4 + if(25 to 40) + severity = 5 + else + severity = 6 + if(severity > 0) + mob_parent.overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity) + else + mob_parent.clear_fullscreen("brute") + if(mob_parent.hud_used?.healths) + mob_parent.hud_used.healths.maptext = MAPTEXT("
[round(healthpercent, 0.5)]%
") + +/// Update our health on the medical hud +/datum/component/life_link/proc/update_med_hud_health(mob/living/mob_parent) + var/image/holder = mob_parent.hud_list?[HEALTH_HUD] + if(isnull(holder)) + return + holder.icon_state = "hud[RoundHealth(host)]" + var/icon/size_check = icon(mob_parent.icon, mob_parent.icon_state, mob_parent.dir) + holder.pixel_y = size_check.Height() - world.icon_size + +/// Update our vital status on the medical hud +/datum/component/life_link/proc/update_med_hud_status(mob/living/mob_parent) + var/image/holder = mob_parent.hud_list?[STATUS_HUD] + if(isnull(holder)) + return + var/icon/size_check = icon(mob_parent.icon, mob_parent.icon_state, mob_parent.dir) + holder.pixel_y = size_check.Height() - world.icon_size + if(host.stat == DEAD || HAS_TRAIT(host, TRAIT_FAKEDEATH)) + holder.icon_state = "huddead" + else + holder.icon_state = "hudhealthy" + +/// When our status tab updates, draw how much HP our host has in there +/datum/component/life_link/proc/on_status_tab_updated(mob/living/source, list/items) + SIGNAL_HANDLER + var/healthpercent = health_percentage(host) + items += "Host Health: [round(healthpercent, 0.5)]%" + +/// Called when our host dies, we should die too +/datum/component/life_link/proc/on_host_died(mob/living/source, gibbed) + SIGNAL_HANDLER + on_linked_death?.Invoke(parent, host, gibbed) + var/mob/living/living_parent = parent + living_parent.death(gibbed) + +/// Called when our host undies, we should undie too +/datum/component/life_link/proc/on_host_revived(mob/living/source, full_heal_flags) + SIGNAL_HANDLER + var/mob/living/living_parent = parent + living_parent.revive(full_heal_flags) + +/// Called when +/datum/component/life_link/proc/on_host_deleted() + SIGNAL_HANDLER + qdel(src) diff --git a/code/datums/components/lock_on_cursor.dm b/code/datums/components/lock_on_cursor.dm index 0ccac6ee2f9234..30140dd95bd70b 100644 --- a/code/datums/components/lock_on_cursor.dm +++ b/code/datums/components/lock_on_cursor.dm @@ -8,13 +8,13 @@ */ /datum/component/lock_on_cursor dupe_mode = COMPONENT_DUPE_ALLOWED - /// Appearance to overlay onto whatever we are targetting + /// Appearance to overlay onto whatever we are targeting var/mutable_appearance/lock_appearance /// Current images we are displaying to the client var/list/image/lock_images /// Typecache of things we are allowed to target var/list/target_typecache - /// Cache of weakrefs to ignore targetting formatted as `list(weakref = TRUE)` + /// Cache of weakrefs to ignore targeting formatted as `list(weakref = TRUE)` var/list/immune_weakrefs /// Number of things we can target at once var/lock_amount diff --git a/code/datums/components/orbit_poll.dm b/code/datums/components/orbit_poll.dm index d9563aaab95b05..91b27d4b667971 100644 --- a/code/datums/components/orbit_poll.dm +++ b/code/datums/components/orbit_poll.dm @@ -47,13 +47,14 @@ var/message = custom_message || "[capitalize(src.title)] is looking for volunteers" - notify_ghosts("[message]. An orbiter will be chosen in [DisplayTimeText(timeout)].\n", \ - action = NOTIFY_ORBIT, \ - enter_link = "(Ignore)", \ - flashwindow = FALSE, \ - header = "Volunteers requested", \ - ignore_key = ignore_key, \ - source = parent \ + notify_ghosts( + "[message]. An orbiter will be chosen in [DisplayTimeText(timeout)].\n", + action = NOTIFY_ORBIT, + enter_link = "(Ignore)", + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Volunteers requested", + ignore_key = ignore_key, + source = parent, ) addtimer(CALLBACK(src, PROC_REF(end_poll)), timeout, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE|TIMER_DELETE_ME) diff --git a/code/datums/components/pet_commands/fetch.dm b/code/datums/components/pet_commands/fetch.dm index ae33983e1d00d3..fa0b3193a4475e 100644 --- a/code/datums/components/pet_commands/fetch.dm +++ b/code/datums/components/pet_commands/fetch.dm @@ -3,7 +3,7 @@ * Watch for someone throwing or pointing at something and then go get it and bring it back. * If it's food we might eat it instead. */ -/datum/pet_command/point_targetting/fetch +/datum/pet_command/point_targeting/fetch command_name = "Fetch" command_desc = "Command your pet to retrieve something you throw or point at." radial_icon = 'icons/mob/actions/actions_spells.dmi' @@ -16,22 +16,22 @@ /// If true, this is a poorly trained pet who will eat food you throw instead of bringing it back var/will_eat_targets = TRUE -/datum/pet_command/point_targetting/fetch/New(mob/living/parent) +/datum/pet_command/point_targeting/fetch/New(mob/living/parent) . = ..() if(isnull(parent)) return parent.AddElement(/datum/element/ai_held_item) // We don't remove this on destroy because they might still be holding something -/datum/pet_command/point_targetting/fetch/add_new_friend(mob/living/tamer) +/datum/pet_command/point_targeting/fetch/add_new_friend(mob/living/tamer) . = ..() RegisterSignal(tamer, COMSIG_MOB_THROW, PROC_REF(listened_throw)) -/datum/pet_command/point_targetting/fetch/remove_friend(mob/living/unfriended) +/datum/pet_command/point_targeting/fetch/remove_friend(mob/living/unfriended) . = ..() UnregisterSignal(unfriended, COMSIG_MOB_THROW) /// A friend has thrown something, if we're listening or at least not busy then go get it -/datum/pet_command/point_targetting/fetch/proc/listened_throw(mob/living/carbon/thrower) +/datum/pet_command/point_targeting/fetch/proc/listened_throw(mob/living/carbon/thrower) SIGNAL_HANDLER var/mob/living/parent = weak_parent.resolve() @@ -57,7 +57,7 @@ RegisterSignal(thrown_thing, COMSIG_MOVABLE_THROW_LANDED, PROC_REF(listen_throw_land)) /// A throw we were listening to has finished, see if it's in range for us to try grabbing it -/datum/pet_command/point_targetting/fetch/proc/listen_throw_land(obj/item/thrown_thing, datum/thrownthing/throwing_datum) +/datum/pet_command/point_targeting/fetch/proc/listen_throw_land(obj/item/thrown_thing, datum/thrownthing/throwing_datum) SIGNAL_HANDLER UnregisterSignal(thrown_thing, COMSIG_MOVABLE_THROW_LANDED) @@ -74,7 +74,7 @@ parent.ai_controller.set_blackboard_key(BB_FETCH_DELIVER_TO, throwing_datum.thrower) // Don't try and fetch turfs or anchored objects if someone points at them -/datum/pet_command/point_targetting/fetch/look_for_target(mob/living/pointing_friend, obj/item/pointed_atom) +/datum/pet_command/point_targeting/fetch/look_for_target(mob/living/pointing_friend, obj/item/pointed_atom) if (!istype(pointed_atom)) return FALSE if (pointed_atom.anchored) @@ -87,7 +87,7 @@ parent.ai_controller.set_blackboard_key(BB_FETCH_DELIVER_TO, pointing_friend) // Finally, plan our actions -/datum/pet_command/point_targetting/fetch/execute_action(datum/ai_controller/controller) +/datum/pet_command/point_targeting/fetch/execute_action(datum/ai_controller/controller) controller.queue_behavior(/datum/ai_behavior/forget_failed_fetches) var/atom/target = controller.blackboard[BB_CURRENT_PET_TARGET] diff --git a/code/datums/components/pet_commands/pet_command.dm b/code/datums/components/pet_commands/pet_command.dm index 7899ffce40ae51..7762b9b2aa8180 100644 --- a/code/datums/components/pet_commands/pet_command.dm +++ b/code/datums/components/pet_commands/pet_command.dm @@ -109,25 +109,25 @@ CRASH("Pet command execute action not implemented.") /** - * # Point Targetting Pet Command + * # Point Targeting Pet Command * As above but also listens for you pointing at something and marks it as a target */ -/datum/pet_command/point_targetting +/datum/pet_command/point_targeting /// Text describing an action we perform upon receiving a new target var/pointed_reaction - /// Blackboard key for targetting datum, this is likely going to need it - var/targetting_datum_key = BB_PET_TARGETTING_DATUM + /// Blackboard key for targeting strategy, this is likely going to need it + var/targeting_strategy_key = BB_PET_TARGETING_STRATEGY -/datum/pet_command/point_targetting/add_new_friend(mob/living/tamer) +/datum/pet_command/point_targeting/add_new_friend(mob/living/tamer) . = ..() RegisterSignal(tamer, COMSIG_MOB_POINTED, PROC_REF(look_for_target)) -/datum/pet_command/point_targetting/remove_friend(mob/living/unfriended) +/datum/pet_command/point_targeting/remove_friend(mob/living/unfriended) . = ..() UnregisterSignal(unfriended, COMSIG_MOB_POINTED) /// Target the pointed atom for actions -/datum/pet_command/point_targetting/proc/look_for_target(mob/living/friend, atom/pointed_atom) +/datum/pet_command/point_targeting/proc/look_for_target(mob/living/friend, atom/pointed_atom) SIGNAL_HANDLER var/mob/living/parent = weak_parent.resolve() diff --git a/code/datums/components/pet_commands/pet_commands_basic.dm b/code/datums/components/pet_commands/pet_commands_basic.dm index 68a20fa77f2fde..a1587acef19eec 100644 --- a/code/datums/components/pet_commands/pet_commands_basic.dm +++ b/code/datums/components/pet_commands/pet_commands_basic.dm @@ -98,11 +98,27 @@ parent.emote("spin") return SUBTREE_RETURN_FINISH_PLANNING +/** + * # Pet Command: Use ability + * Use an an ability that does not require any targets + */ +/datum/pet_command/untargeted_ability + ///untargeted ability we will use + var/ability_key + +/datum/pet_command/untargeted_ability/execute_action(datum/ai_controller/controller) + var/datum/action/cooldown/ability = controller.blackboard[ability_key] + if(!ability?.IsAvailable()) + return + controller.queue_behavior(/datum/ai_behavior/use_mob_ability, ability_key) + controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) + return SUBTREE_RETURN_FINISH_PLANNING + /** * # Pet Command: Attack * Tells a pet to chase and bite the next thing you point at */ -/datum/pet_command/point_targetting/attack +/datum/pet_command/point_targeting/attack command_name = "Attack" command_desc = "Command your pet to attack things that you point out to it." radial_icon = 'icons/effects/effects.dmi' @@ -117,13 +133,13 @@ var/attack_behaviour = /datum/ai_behavior/basic_melee_attack // Refuse to target things we can't target, chiefly other friends -/datum/pet_command/point_targetting/attack/set_command_target(mob/living/parent, atom/target) +/datum/pet_command/point_targeting/attack/set_command_target(mob/living/parent, atom/target) if (!target) return var/mob/living/living_parent = parent if (!living_parent.ai_controller) return - var/datum/targetting_datum/targeter = living_parent.ai_controller.blackboard[targetting_datum_key] + var/datum/targeting_strategy/targeter = GET_TARGETING_STRATEGY(living_parent.ai_controller.blackboard[targeting_strategy_key]) if (!targeter) return if (!targeter.can_attack(living_parent, target)) @@ -131,21 +147,21 @@ return return ..() -/// Display feedback about not targetting something -/datum/pet_command/point_targetting/attack/proc/refuse_target(mob/living/parent, atom/target) +/// Display feedback about not targeting something +/datum/pet_command/point_targeting/attack/proc/refuse_target(mob/living/parent, atom/target) var/mob/living/living_parent = parent living_parent.balloon_alert_to_viewers("[refuse_reaction]") living_parent.visible_message(span_notice("[living_parent] refuses to attack [target].")) -/datum/pet_command/point_targetting/attack/execute_action(datum/ai_controller/controller) - controller.queue_behavior(attack_behaviour, BB_CURRENT_PET_TARGET, targetting_datum_key) +/datum/pet_command/point_targeting/attack/execute_action(datum/ai_controller/controller) + controller.queue_behavior(attack_behaviour, BB_CURRENT_PET_TARGET, targeting_strategy_key) return SUBTREE_RETURN_FINISH_PLANNING /** - * # Pet Command: Targetted Ability + * # Pet Command: targeted Ability * Tells a pet to use some kind of ability on the next thing you point at */ -/datum/pet_command/point_targetting/use_ability +/datum/pet_command/point_targeting/use_ability command_name = "Use ability" command_desc = "Command your pet to use one of its special skills on something that you point out to it." radial_icon = 'icons/mob/actions/actions_spells.dmi' @@ -156,7 +172,7 @@ /// Blackboard key where a reference to some kind of mob ability is stored var/pet_ability_key -/datum/pet_command/point_targetting/use_ability/execute_action(datum/ai_controller/controller) +/datum/pet_command/point_targeting/use_ability/execute_action(datum/ai_controller/controller) if (!pet_ability_key) return var/datum/action/cooldown/using_action = controller.blackboard[pet_ability_key] @@ -191,7 +207,7 @@ if(victim.stat > controller.blackboard[BB_TARGET_MINIMUM_STAT]) controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return - controller.queue_behavior(protect_behavior, BB_CURRENT_PET_TARGET, BB_PET_TARGETTING_DATUM) + controller.queue_behavior(protect_behavior, BB_CURRENT_PET_TARGET, BB_PET_TARGETING_STRATEGY) return SUBTREE_RETURN_FINISH_PLANNING /datum/pet_command/protect_owner/set_command_active(mob/living/parent, mob/living/victim) diff --git a/code/datums/components/plumbing/IV_drip.dm b/code/datums/components/plumbing/IV_drip.dm deleted file mode 100644 index e14c07a9fe002f..00000000000000 --- a/code/datums/components/plumbing/IV_drip.dm +++ /dev/null @@ -1,34 +0,0 @@ -///Component for IVs that tracks the current person being IV'd. Input received through plumbing is instead routed to the whoever is attached -/datum/component/plumbing/iv_drip - demand_connects = SOUTH - supply_connects = NORTH - - methods = INJECT - -/datum/component/plumbing/iv_drip/Initialize(start=TRUE, _ducting_layer, _turn_connects=TRUE, datum/reagents/custom_receiver) - . = ..() - - set_recipient_reagents_holder(null) - -/datum/component/plumbing/iv_drip/RegisterWithParent() - . = ..() - - RegisterSignal(parent, COMSIG_IV_ATTACH, PROC_REF(update_attached)) - RegisterSignal(parent, COMSIG_IV_DETACH, PROC_REF(clear_attached)) - -/datum/component/plumbing/iv_drip/UnregisterFromParent() - UnregisterSignal(parent, COMSIG_IV_ATTACH) - UnregisterSignal(parent, COMSIG_IV_DETACH) - -///When an IV is attached, we will use whoever is attached as our receiving container -/datum/component/plumbing/iv_drip/proc/update_attached(datum/source, mob/living/attachee) - SIGNAL_HANDLER - - if(attachee?.reagents) - set_recipient_reagents_holder(attachee.reagents) - -///IV has been detached, so clear the holder -/datum/component/plumbing/iv_drip/proc/clear_attached(datum/source) - SIGNAL_HANDLER - - set_recipient_reagents_holder(null) diff --git a/code/datums/components/plumbing/_plumbing.dm b/code/datums/components/plumbing/_plumbing.dm index 29858649e03b33..91d03dd9d0647a 100644 --- a/code/datums/components/plumbing/_plumbing.dm +++ b/code/datums/components/plumbing/_plumbing.dm @@ -100,7 +100,7 @@ //find the duct to take from var/datum/ductnet/net if(!ducts.Find(num2text(dir))) - return + return FALSE net = ducts[num2text(dir)] //find all valid suppliers in the duct @@ -110,7 +110,7 @@ valid_suppliers += supplier var/suppliersLeft = valid_suppliers.len if(!suppliersLeft) - return + return FALSE //take an equal amount from each supplier var/currentRequest @@ -119,6 +119,7 @@ currentRequest = (target_volume - reagents.total_volume) / suppliersLeft give.transfer_to(src, currentRequest, reagent, net) suppliersLeft-- + return TRUE ///returns TRUE when they can give the specified amount and reagent. called by process request /datum/component/plumbing/proc/can_give(amount, reagent, datum/ductnet/net) @@ -214,8 +215,11 @@ STOP_PROCESSING(SSplumbing, src) - for(var/duct_dir in ducts) - var/datum/ductnet/duct = ducts[duct_dir] + //remove_plumber() can remove all ducts at once if they all belong to the same pipenet + //for e.g. in case of circular connections + //so we check if we have ducts to remove after each iteration + while(ducts.len) + var/datum/ductnet/duct = ducts[ducts[1]] //for maps index 1 will return the 1st key duct.remove_plumber(src) active = FALSE @@ -394,6 +398,10 @@ demand_connects = NORTH supply_connects = SOUTH +/datum/component/plumbing/iv_drip + demand_connects = SOUTH + supply_connects = NORTH + /datum/component/plumbing/manifold/change_ducting_layer(obj/caller, obj/changer, new_layer) return diff --git a/code/datums/components/plumbing/reaction_chamber.dm b/code/datums/components/plumbing/reaction_chamber.dm index e76fb69ec1f9d8..d0aff2f50708c1 100644 --- a/code/datums/components/plumbing/reaction_chamber.dm +++ b/code/datums/components/plumbing/reaction_chamber.dm @@ -18,20 +18,21 @@ if(chamber.emptying) return + //take in reagents var/present_amount var/diff for(var/required_reagent in chamber.required_reagents) - //find how much amount is already present if at all + //find how much amount is already present if at all and get the reagent reference present_amount = 0 - for(var/datum/reagent/containg_reagent as anything in reagents.reagent_list) - if(required_reagent == containg_reagent.type) - present_amount = containg_reagent.volume + for(var/datum/reagent/present_reagent as anything in reagents.reagent_list) + if(required_reagent == present_reagent.type) + present_amount = present_reagent.volume break - //compute how much more is needed and round it - diff = chamber.required_reagents[required_reagent] - present_amount - if(diff >= 0.01) - process_request(min(diff, MACHINE_REAGENT_TRANSFER), required_reagent, dir) + //compute how much more is needed + diff = min(chamber.required_reagents[required_reagent] - present_amount, MACHINE_REAGENT_TRANSFER) + if(diff >= CHEMICAL_QUANTISATION_LEVEL) // the closest we can ask for so values like 0.9999 become 1 + process_request(diff, required_reagent, dir) return reagents.flags &= ~NO_REACT diff --git a/code/datums/components/plundering_attacks.dm b/code/datums/components/plundering_attacks.dm new file mode 100644 index 00000000000000..f55fa42b0717be --- /dev/null +++ b/code/datums/components/plundering_attacks.dm @@ -0,0 +1,54 @@ +/** + * Component that makes basic mobs' melee attacks steal money from the target's ID card. + * Plundered money is stored and dropped on death or removal of the component. + */ +/datum/component/plundering_attacks + /// How many credits do we steal per attack? + var/plunder_amount = 25 + /// How much plunder do we have stored? + var/plunder_stored = 0 + + +/datum/component/plundering_attacks/Initialize( + plunder_amount = 25, +) + . = ..() + if(!isbasicmob(parent)) + return COMPONENT_INCOMPATIBLE + + src.plunder_amount = plunder_amount + +/datum/component/plundering_attacks/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(attempt_plunder)) + RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(drop_plunder)) + +/datum/component/plundering_attacks/UnregisterFromParent() + . = ..() + UnregisterSignal(parent, list(COMSIG_HOSTILE_POST_ATTACKINGTARGET, COMSIG_LIVING_DEATH)) + drop_plunder() + +/datum/component/plundering_attacks/proc/attempt_plunder(mob/living/attacker, mob/living/carbon/human/target, success) + SIGNAL_HANDLER + if(!istype(target) || !success) + return + var/obj/item/card/id/id_card = target.wear_id?.GetID() + if(isnull(id_card)) + return + var/datum/bank_account/account_to_rob = id_card.registered_account + if(isnull(account_to_rob) || account_to_rob.account_balance == 0) + return + + var/amount_to_steal = plunder_amount + if(account_to_rob.account_balance < plunder_amount) //If there isn't enough, just take what's left + amount_to_steal = account_to_rob.account_balance + plunder_stored += amount_to_steal + account_to_rob.adjust_money(-amount_to_steal) + account_to_rob.bank_card_talk("Transaction confirmed! Transferred [amount_to_steal] credits to \!") + +/datum/component/plundering_attacks/proc/drop_plunder() + SIGNAL_HANDLER + if(plunder_stored == 0) + return + new /obj/item/holochip(get_turf(parent), plunder_stored) + plunder_stored = 0 diff --git a/code/datums/components/ranged_mob_full_auto.dm b/code/datums/components/ranged_mob_full_auto.dm new file mode 100644 index 00000000000000..a33b705d548505 --- /dev/null +++ b/code/datums/components/ranged_mob_full_auto.dm @@ -0,0 +1,203 @@ +#define AUTOFIRE_MOUSEUP 1 +#define AUTOFIRE_MOUSEDOWN 0 + +/// Allows a mob to autofire by holding down the cursor +/datum/component/ranged_mob_full_auto + /// Delay before attempting to fire again, note that this is just when we make attempts and is separate from mob's actual firing cooldown + var/autofire_shot_delay + /// Our client for click tracking + var/client/clicker + /// Are we currently firing? + var/is_firing = FALSE + /// This seems hacky but there can be two MouseDown() without a MouseUp() in between if the user holds click and uses alt+tab, printscreen or similar. + var/awaiting_status = AUTOFIRE_MOUSEDOWN + /// What are we currently shooting at? + var/atom/target + /// Where are we currently shooting at? + var/turf/target_loc + /// When will we next try to shoot? + COOLDOWN_DECLARE(next_shot_cooldown) + +/datum/component/ranged_mob_full_auto/Initialize(autofire_shot_delay = 0.5 SECONDS) + . = ..() + if (!isliving(parent)) + return COMPONENT_INCOMPATIBLE + + src.autofire_shot_delay = autofire_shot_delay + + var/mob/living/living_parent = parent + if (isnull(living_parent.client)) + return + on_gained_client(parent) + +/datum/component/ranged_mob_full_auto/RegisterWithParent() + RegisterSignal(parent, COMSIG_MOB_LOGIN, PROC_REF(on_gained_client)) + RegisterSignal(parent, COMSIG_MOB_LOGOUT, PROC_REF(on_lost_client)) + +/datum/component/ranged_mob_full_auto/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT)) + +/datum/component/ranged_mob_full_auto/process(seconds_per_tick) + if (!try_shooting()) + return PROCESS_KILL + +/// Try and take a shot, returns false if we are unable to do so and should stop trying +/datum/component/ranged_mob_full_auto/proc/try_shooting() + if (!is_firing) + return FALSE + if (!COOLDOWN_FINISHED(src, next_shot_cooldown)) + return TRUE // Don't fire but also keep processing + + var/mob/living/living_parent = parent + + if (isnull(target) || get_turf(target) != target_loc) // Target moved or got destroyed since we last aimed. + set_target(target_loc) + target = target_loc // So we keep firing on the emptied tile until we move our mouse and find a new target. + if (get_dist(living_parent, target) <= 0) + set_target(get_step(living_parent, living_parent.dir)) // Shoot in the direction faced if the mouse is on the same tile as we are. + target_loc = target + else if (!in_view_range(living_parent, target)) + stop_firing() + return FALSE // Can't see shit + + living_parent.face_atom(target) + COOLDOWN_START(src, next_shot_cooldown, autofire_shot_delay) + living_parent.RangedAttack(target) + return TRUE + +/// Setter for reference handling +/datum/component/ranged_mob_full_auto/proc/set_target(atom/new_target) + if (!isnull(target)) + UnregisterSignal(target, COMSIG_QDELETING) + target = new_target + if (!isnull(target)) + RegisterSignal(target, COMSIG_QDELETING, PROC_REF(on_target_deleted)) + +/// Don't hang references +/datum/component/ranged_mob_full_auto/proc/on_target_deleted() + SIGNAL_HANDLER + set_target(null) + +/// When we gain a client, start tracking clicks +/datum/component/ranged_mob_full_auto/proc/on_gained_client(mob/living/source) + SIGNAL_HANDLER + clicker = source.client + RegisterSignal(clicker, COMSIG_CLIENT_MOUSEDOWN, PROC_REF(on_mouse_down)) + +/// When we lose our client, stop functioning +/datum/component/ranged_mob_full_auto/proc/on_lost_client(mob/living/source) + SIGNAL_HANDLER + if (!isnull(clicker)) + UnregisterSignal(clicker, list(COMSIG_CLIENT_MOUSEDOWN, COMSIG_CLIENT_MOUSEDRAG, COMSIG_CLIENT_MOUSEUP)) + stop_firing() + clicker = null + +/// On mouse down start shooting! +/datum/component/ranged_mob_full_auto/proc/on_mouse_down(client/source, atom/target, turf/location, control, params) + SIGNAL_HANDLER + if (awaiting_status != AUTOFIRE_MOUSEDOWN) + return // Avoid a double mousedown with no mouseup + var/list/modifiers = params2list(params) + + if (LAZYACCESS(modifiers, SHIFT_CLICK)) + return + if (LAZYACCESS(modifiers, CTRL_CLICK)) + return + if (LAZYACCESS(modifiers, MIDDLE_CLICK)) + return + if (LAZYACCESS(modifiers, RIGHT_CLICK)) + return + if (LAZYACCESS(modifiers, ALT_CLICK)) + return + var/mob/living/living_parent = parent + if (!isturf(living_parent.loc) || living_parent.Adjacent(target)) + return + + if (isnull(location) || istype(target, /atom/movable/screen)) // Clicking on a screen object. + if (target.plane != CLICKCATCHER_PLANE) // The clickcatcher is a special case. We want the click to trigger then, under it. + return // If we click and drag on our worn backpack, for example, we want it to open instead. + set_target(parse_caught_click_modifiers(modifiers, get_turf(source.eye), source)) + params = list2params(modifiers) + if (isnull(target)) + CRASH("Failed to get the turf under clickcatcher") + + awaiting_status = AUTOFIRE_MOUSEUP + source.click_intercept_time = world.time // From this point onwards Click() will no longer be triggered. + if (is_firing) + stop_firing() + + set_target(target) + target_loc = get_turf(target) + INVOKE_ASYNC(src, PROC_REF(start_firing)) + +/// Start tracking mouse movement and processing our shots +/datum/component/ranged_mob_full_auto/proc/start_firing() + if (is_firing) + return + + is_firing = TRUE + if (!try_shooting()) // First one is immediate + stop_firing() + return + + clicker.mouse_override_icon = 'icons/effects/mouse_pointers/weapon_pointer.dmi' + clicker.mouse_pointer_icon = clicker.mouse_override_icon + + START_PROCESSING(SSprojectiles, src) + RegisterSignal(clicker, COMSIG_CLIENT_MOUSEUP, PROC_REF(on_mouse_up)) + RegisterSignal(clicker, COMSIG_CLIENT_MOUSEDRAG, PROC_REF(on_mouse_drag)) + +/// When the mouse moved let's try and shift our aim +/datum/component/ranged_mob_full_auto/proc/on_mouse_drag(client/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params) + SIGNAL_HANDLER + if (!isnull(over_location)) + set_target(over_object) + target_loc = get_turf(over_object) + return + + //This happens when the mouse is over an inventory or screen object, or on entering deep darkness, for example. + var/list/modifiers = params2list(params) + var/new_target = parse_caught_click_modifiers(modifiers, get_turf(source.eye), source) + params = list2params(modifiers) + + if (!isnull(new_target)) + set_target(new_target) + target_loc = new_target + return + + if (QDELETED(target)) //No new target acquired, and old one was deleted, get us out of here. + stop_firing() + CRASH("on_mouse_drag failed to get the turf under screen object [over_object.type]. Old target was incidentally QDELETED.") + + + set_target(get_turf(target)) //If previous target wasn't a turf, let's turn it into one to avoid locking onto a potentially moving target. + target_loc = target + CRASH("on_mouse_drag failed to get the turf under screen object [over_object.type]") + +/// When the mouse is released we should stop +/datum/component/ranged_mob_full_auto/proc/on_mouse_up() + SIGNAL_HANDLER + if (awaiting_status != AUTOFIRE_MOUSEUP) + return + stop_firing() + return COMPONENT_CLIENT_MOUSEUP_INTERCEPT + +/// Stop watching our mouse and processing shots +/datum/component/ranged_mob_full_auto/proc/stop_firing() + if (!is_firing) + return + + is_firing = FALSE + set_target(null) + target_loc = null + STOP_PROCESSING(SSprojectiles, src) + awaiting_status = AUTOFIRE_MOUSEDOWN + + if (isnull(clicker)) + return + UnregisterSignal(clicker, list(COMSIG_CLIENT_MOUSEDRAG, COMSIG_CLIENT_MOUSEUP)) + clicker.mouse_override_icon = null + clicker.mouse_pointer_icon = null + +#undef AUTOFIRE_MOUSEUP +#undef AUTOFIRE_MOUSEDOWN diff --git a/code/datums/components/recharging_attacks.dm b/code/datums/components/recharging_attacks.dm new file mode 100644 index 00000000000000..b9127c4e018bbc --- /dev/null +++ b/code/datums/components/recharging_attacks.dm @@ -0,0 +1,66 @@ +/// Reduces the cooldown of a given action upon landing attacks, critting, or killing mobs. +/datum/component/recharging_attacks + /// The target of the most recent attack + var/last_target + /// The stat of the most recently attacked mob + var/last_stat + /// The action to recharge when attacking + var/datum/action/cooldown/recharged_action + /// The amount of cooldown to refund on a successful attack + var/attack_refund + /// The amount of cooldown to refund when putting a target into critical + var/crit_refund + +/datum/component/recharging_attacks/Initialize( + datum/action/cooldown/recharged_action, + attack_refund = 1 SECONDS, + crit_refund = 5 SECONDS, +) + . = ..() + if (!isbasicmob(parent) || !istype(recharged_action)) + return COMPONENT_INCOMPATIBLE + src.recharged_action = recharged_action + src.attack_refund = attack_refund + src.crit_refund = crit_refund + +/datum/component/recharging_attacks/Destroy() + UnregisterSignal(recharged_action, COMSIG_QDELETING) + recharged_action = null + return ..() + +/datum/component/recharging_attacks/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(set_old_stat)) + RegisterSignal(parent, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(check_stat)) + RegisterSignal(recharged_action, COMSIG_QDELETING, PROC_REF(on_action_qdel)) + +/datum/component/recharging_attacks/UnregisterFromParent() + . = ..() + UnregisterSignal(parent, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_HOSTILE_POST_ATTACKINGTARGET)) + if(recharged_action) + UnregisterSignal(recharged_action, COMSIG_QDELETING) + +/datum/component/recharging_attacks/proc/set_old_stat(mob/attacker, mob/attacked) + SIGNAL_HANDLER + if(!isliving(attacked)) + return + last_target = attacked + last_stat = attacked.stat + +/datum/component/recharging_attacks/proc/check_stat(mob/living/attacker, mob/living/attacked, success) + SIGNAL_HANDLER + if(!isliving(attacked) || attacked != last_target || attacker.faction_check_atom(attacked)) + return + + var/final_refund = attack_refund + if(QDELETED(attacked) || (attacked.stat == DEAD && last_stat != DEAD)) //The target is dead and we killed them - full refund + final_refund = recharged_action.cooldown_time + else if(attacked.stat > CONSCIOUS && last_stat == CONSCIOUS) //We knocked the target unconscious - partial refund + final_refund = crit_refund + + recharged_action.next_use_time -= final_refund + recharged_action.build_all_button_icons() + +/datum/component/recharging_attacks/proc/on_action_qdel() + SIGNAL_HANDLER + qdel(src) diff --git a/code/datums/components/revenge_ability.dm b/code/datums/components/revenge_ability.dm index f03bc992276fc1..8d9faec52e0bc0 100644 --- a/code/datums/components/revenge_ability.dm +++ b/code/datums/components/revenge_ability.dm @@ -8,7 +8,7 @@ /// The ability to use when we are attacked var/datum/action/cooldown/ability /// Optional datum for validating targets - var/datum/targetting_datum/targetting + var/datum/targeting_strategy/targeting /// Trigger only if target is at least this far away var/min_range /// Trigger only if target is at least this close @@ -16,12 +16,12 @@ /// Target the ability at ourself instead of at the offender var/target_self -/datum/component/revenge_ability/Initialize(datum/action/cooldown/ability, datum/targetting_datum/targetting, min_range = 0, max_range = INFINITY, target_self = FALSE) +/datum/component/revenge_ability/Initialize(datum/action/cooldown/ability, datum/targeting_strategy/targeting, min_range = 0, max_range = INFINITY, target_self = FALSE) . = ..() if (!isliving(parent)) return COMPONENT_INCOMPATIBLE src.ability = ability - src.targetting = targetting + src.targeting = targeting src.min_range = min_range src.max_range = max_range src.target_self = target_self @@ -45,7 +45,7 @@ var/distance = get_dist(ability_user, attacker) if (distance < min_range || distance > max_range) return - if (targetting && !targetting.can_attack(victim, attacker)) + if (targeting && !targeting.can_attack(victim, attacker)) return INVOKE_ASYNC(ability, TYPE_PROC_REF(/datum/action/cooldown, InterceptClickOn), ability_user, null, (target_self) ? ability_user : attacker) diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm index 14358a5c5a3885..c8c969a8c6b5f6 100644 --- a/code/datums/components/riding/riding.dm +++ b/code/datums/components/riding/riding.dm @@ -26,12 +26,16 @@ var/list/directional_vehicle_layers = list() /// same as above but instead of layer you have a list(px, py) var/list/directional_vehicle_offsets = list() + /// planes of the rider + var/list/directional_rider_planes = list() /// allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence. var/list/allowed_turf_typecache /// allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence. var/list/forbid_turf_typecache /// We don't need roads where we're going if this is TRUE, allow normal movement in space tiles var/override_allow_spacemove = FALSE + /// can anyone other than the rider unbuckle the rider? + var/can_force_unbuckle = TRUE /** * Ride check flags defined for the specific riding component types, so we know if we need arms, legs, or whatever. @@ -55,7 +59,6 @@ if(potion_boost) vehicle_move_delay = round(CONFIG_GET(number/movedelay/run_delay) * 0.85, 0.01) - /datum/component/riding/RegisterWithParent() . = ..() RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, PROC_REF(vehicle_turned)) @@ -64,6 +67,10 @@ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(vehicle_moved)) RegisterSignal(parent, COMSIG_MOVABLE_BUMP, PROC_REF(vehicle_bump)) RegisterSignal(parent, COMSIG_BUCKLED_CAN_Z_MOVE, PROC_REF(riding_can_z_move)) + RegisterSignals(parent, GLOB.movement_type_addtrait_signals, PROC_REF(on_movement_type_trait_gain)) + RegisterSignals(parent, GLOB.movement_type_removetrait_signals, PROC_REF(on_movement_type_trait_loss)) + if(!can_force_unbuckle) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(force_unbuckle)) /** * This proc handles all of the proc calls to things like set_vehicle_dir_layer() that a type of riding datum needs to call on creation @@ -79,11 +86,18 @@ /datum/component/riding/proc/vehicle_mob_unbuckle(datum/source, mob/living/rider, force = FALSE) SIGNAL_HANDLER + handle_unbuckle(rider) + +/datum/component/riding/proc/handle_unbuckle(mob/living/rider) var/atom/movable/movable_parent = parent restore_position(rider) unequip_buckle_inhands(rider) rider.updating_glide_size = TRUE UnregisterSignal(rider, COMSIG_LIVING_TRY_PULL) + for (var/trait in GLOB.movement_type_trait_to_flag) + if (HAS_TRAIT(parent, trait)) + REMOVE_TRAIT(rider, trait, REF(src)) + REMOVE_TRAIT(rider, TRAIT_NO_FLOATING_ANIM, REF(src)) if(!movable_parent.has_buckled_mobs()) qdel(src) @@ -94,11 +108,17 @@ var/atom/movable/movable_parent = parent handle_vehicle_layer(movable_parent.dir) handle_vehicle_offsets(movable_parent.dir) + handle_rider_plane(movable_parent.dir) if(rider.pulling == source) rider.stop_pulling() RegisterSignal(rider, COMSIG_LIVING_TRY_PULL, PROC_REF(on_rider_try_pull)) + for (var/trait in GLOB.movement_type_trait_to_flag) + if (HAS_TRAIT(parent, trait)) + ADD_TRAIT(rider, trait, REF(src)) + ADD_TRAIT(rider, TRAIT_NO_FLOATING_ANIM, REF(src)) + /// This proc is called when the rider attempts to grab the thing they're riding, preventing them from doing so. /datum/component/riding/proc/on_rider_try_pull(mob/living/rider_pulling, atom/movable/target, force) SIGNAL_HANDLER @@ -118,9 +138,20 @@ . = AM.layer AM.layer = . +/datum/component/riding/proc/handle_rider_plane(dir) + var/atom/movable/movable_parent = parent + var/target_plane = directional_rider_planes["[dir]"] + if(isnull(target_plane)) + return + for(var/mob/buckled_mob in movable_parent.buckled_mobs) + SET_PLANE_EXPLICIT(buckled_mob, target_plane, movable_parent) + /datum/component/riding/proc/set_vehicle_dir_layer(dir, layer) directional_vehicle_layers["[dir]"] = layer +/datum/component/riding/proc/set_rider_dir_plane(dir, plane) + directional_rider_planes["[dir]"] = plane + /// This is called after the ridden atom is successfully moved and is used to handle icon stuff /datum/component/riding/proc/vehicle_moved(datum/source, oldloc, dir, forced) SIGNAL_HANDLER @@ -135,6 +166,7 @@ return // runtimed with piggy's without this, look into this more handle_vehicle_offsets(dir) handle_vehicle_layer(dir) + handle_rider_plane(dir) /// Turning is like moving /datum/component/riding/proc/vehicle_turned(datum/source, _old_dir, new_dir) @@ -222,11 +254,14 @@ //BUCKLE HOOKS /datum/component/riding/proc/restore_position(mob/living/buckled_mob) - if(buckled_mob) - buckled_mob.pixel_x = buckled_mob.base_pixel_x - buckled_mob.pixel_y = buckled_mob.base_pixel_y - if(buckled_mob.client) - buckled_mob.client.view_size.resetToDefault() + if(isnull(buckled_mob)) + return + buckled_mob.pixel_x = buckled_mob.base_pixel_x + buckled_mob.pixel_y = buckled_mob.base_pixel_y + var/atom/source = parent + SET_PLANE_EXPLICIT(buckled_mob, initial(buckled_mob.plane), source) + if(buckled_mob.client) + buckled_mob.client.view_size.resetToDefault() //MOVEMENT /datum/component/riding/proc/turf_check(turf/next, turf/current) @@ -273,3 +308,24 @@ /datum/component/riding/proc/riding_can_z_move(atom/movable/movable_parent, direction, turf/start, turf/destination, z_move_flags, mob/living/rider) SIGNAL_HANDLER return COMPONENT_RIDDEN_ALLOW_Z_MOVE + +/// Called when our vehicle gains a movement trait, so we can apply it to the riders +/datum/component/riding/proc/on_movement_type_trait_gain(atom/movable/source, trait) + SIGNAL_HANDLER + var/atom/movable/movable_parent = parent + for (var/mob/rider in movable_parent.buckled_mobs) + ADD_TRAIT(rider, trait, REF(src)) + +/// Called when our vehicle loses a movement trait, so we can remove it from the riders +/datum/component/riding/proc/on_movement_type_trait_loss(atom/movable/source, trait) + SIGNAL_HANDLER + var/atom/movable/movable_parent = parent + for (var/mob/rider in movable_parent.buckled_mobs) + REMOVE_TRAIT(rider, trait, REF(src)) + +/datum/component/riding/proc/force_unbuckle(atom/movable/source, mob/living/living_hitter) + SIGNAL_HANDLER + + if((living_hitter in source.buckled_mobs)) + return + return COMPONENT_CANCEL_ATTACK_CHAIN diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index 85aaee4ab7cef4..0ad6c1e4c7f897 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -11,7 +11,8 @@ var/can_be_driven = TRUE /// If TRUE, this creature's abilities can be triggered by the rider while mounted var/can_use_abilities = FALSE - var/list/shared_action_buttons = list() + /// list of blacklisted abilities that cant be shared + var/list/blacklist_abilities = list() /datum/component/riding/creature/Initialize(mob/living/riding_mob, force = FALSE, ride_check_flags = NONE, potion_boost = FALSE) if(!isliving(parent)) @@ -66,6 +67,8 @@ // for fireman carries, check if the ridden is stunned/restrained else if((ride_check_flags & CARRIER_NEEDS_ARM) && (HAS_TRAIT(living_parent, TRAIT_RESTRAINED) || living_parent.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB))) . = FALSE + else if((ride_check_flags & JUST_FRIEND_RIDERS) && !(living_parent.faction.Find(REF(rider)))) + . = FALSE if(. || !consequences) return @@ -162,6 +165,7 @@ for(var/mob/yeet_mob in user.buckled_mobs) force_dismount(yeet_mob, (!user.combat_mode)) // gentle on help, byeeee if not + /// If the ridden creature has abilities, and some var yet to be made is set to TRUE, the rider will be able to control those abilities /datum/component/riding/creature/proc/setup_abilities(mob/living/rider) if(!isliving(parent)) @@ -170,6 +174,8 @@ var/mob/living/ridden_creature = parent for(var/datum/action/action as anything in ridden_creature.actions) + if(is_type_in_list(action, blacklist_abilities)) + continue action.GiveAction(rider) /// Takes away the riding parent's abilities from the rider @@ -497,7 +503,7 @@ set_vehicle_dir_layer(WEST, ABOVE_MOB_LAYER) /datum/component/riding/creature/guardian/ride_check(mob/living/user, consequences = TRUE) - var/mob/living/simple_animal/hostile/guardian/charger = parent + var/mob/living/basic/guardian/charger = parent if(!istype(charger)) return ..() return charger.summoner == user @@ -512,6 +518,38 @@ set_vehicle_dir_layer(EAST, OBJ_LAYER) set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/creature/leaper + can_force_unbuckle = FALSE + can_use_abilities = TRUE + blacklist_abilities = list(/datum/action/cooldown/toggle_seethrough) + ride_check_flags = JUST_FRIEND_RIDERS + +/datum/component/riding/creature/leaper/handle_specials() + . = ..() + set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(17, 46), TEXT_SOUTH = list(17,51), TEXT_EAST = list(27, 46), TEXT_WEST = list(6, 46))) + set_rider_dir_plane(SOUTH, GAME_PLANE_UPPER) + set_rider_dir_plane(NORTH, GAME_PLANE) + set_rider_dir_plane(EAST, GAME_PLANE_UPPER) + set_rider_dir_plane(WEST, GAME_PLANE_UPPER) + +/datum/component/riding/creature/leaper/Initialize(mob/living/riding_mob, force = FALSE, ride_check_flags = NONE, potion_boost = FALSE) + . = ..() + RegisterSignal(riding_mob, COMSIG_MOB_POINTED, PROC_REF(attack_pointed)) + +/datum/component/riding/creature/leaper/proc/attack_pointed(mob/living/rider, atom/pointed) + SIGNAL_HANDLER + if(!isclosedturf(pointed)) + return + var/mob/living/basic/basic_parent = parent + if(!basic_parent.CanReach(pointed)) + return + basic_parent.melee_attack(pointed) + + +/datum/component/riding/leaper/handle_unbuckle(mob/living/rider) + . = ..() + UnregisterSignal(rider, COMSIG_MOB_POINTED) + //SKYRAT EDIT START: Human Riding Defines #undef OVERSIZED_OFFSET #undef OVERSIZED_SIDE_OFFSET diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm index be1d674eb4d0be..2119c8ad7e191d 100644 --- a/code/datums/components/slippery.dm +++ b/code/datums/components/slippery.dm @@ -1,17 +1,33 @@ -/// Slippery component, for making anything slippery. Of course. +/** + * # Slip behaviour component + * + * Add this component to an object to make it a slippery object, slippery objects make mobs that cross them fall over. + * Items with this component that get picked up may give their parent mob the slip behaviour. + * + * Here is a simple example of adding the component behaviour to an object.area + * + * AddComponent(/datum/component/slippery, 80, (NO_SLIP_WHEN_WALKING | SLIDE)) + * + * This adds slippery behaviour to the parent atom, with a 80 decisecond (~8 seconds) knockdown + * The lube flags control how the slip behaves, in this case, the mob wont slip if it's in walking mode (NO_SLIP_WHEN_WALKING) + * and if they do slip, they will slide a few tiles (SLIDE) + * + * + * This component has configurable behaviours, see the [Initialize proc for the argument listing][/datum/component/slippery/proc/Initialize]. + */ /datum/component/slippery dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS - /// If the slip forces you to drop held items. + /// If the slip forces the crossing mob to drop held items. var/force_drop_items = FALSE - /// How long the slip keeps you knocked down. + /// How long the slip keeps the crossing mob knocked over (they can still crawl and use weapons) for. var/knockdown_time = 0 - /// How long the slip paralyzes for. + /// How long the slip paralyzes (prevents the crossing mob doing anything) for. var/paralyze_time = 0 /// Flags for how slippery the parent is. See [__DEFINES/mobs.dm] var/lube_flags - /// Optional callback providing an additional chance to prevent slippage + /// Optional callback allowing you to define custom conditions for slipping var/datum/callback/can_slip_callback - /// A proc callback to call on slip. + /// Optional call back that is called when a mob slips on this component var/datum/callback/on_slip_callback /// If parent is an item, this is the person currently holding/wearing the parent (or the parent if no one is holding it) var/mob/living/holder @@ -30,6 +46,20 @@ /// The connect_loc_behalf component for the holder_connections list. var/datum/weakref/holder_connect_loc_behalf +/** + * Initialize the slippery component behaviour + * + * When applied to any atom in the game this will apply slipping behaviours to that atom + * + * Arguments: + * * knockdown - Length of time the knockdown applies (Deciseconds) + * * lube_flags - Controls the slip behaviour, they are listed starting [here][SLIDE] + * * datum/callback/on_slip_callback - Callback to define further custom controls on when slipping is applied + * * paralyze - length of time to paralyze the crossing mob for (Deciseconds) + * * force_drop - should the crossing mob drop items in it's hands or not + * * slot_whitelist - flags controlling where on a mob this item can be equipped to make the parent mob slippery full list [here][ITEM_SLOT_OCLOTHING] + * * datum/callback/on_slip_callback - Callback to add custom behaviours as the crossing mob is slipped + */ /datum/component/slippery/Initialize( knockdown, lube_flags = NONE, @@ -115,11 +145,12 @@ src.can_slip_callback = can_slip_callback if(slot_whitelist) src.slot_whitelist = slot_whitelist -/* +/** * The proc that does the sliping. Invokes the slip callback we have set. * - * source - the source of the signal - * AM - the atom/movable that is being slipped. + * Arguments + * * source - the source of the signal + * * arrived - the atom/movable that is being slipped. */ /datum/component/slippery/proc/Slip(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) SIGNAL_HANDLER @@ -137,14 +168,15 @@ if(victim.slip(knockdown_time, parent, lube_flags, paralyze_time, force_drop_items)) on_slip_callback?.Invoke(victim) -/* +/** * Gets called when COMSIG_ITEM_EQUIPPED is sent to parent. * This proc register slip signals to the equipper. * If we have a slot whitelist, we only register the signals if the slot is valid (ex: clown PDA only slips in ID or belt slot). * - * source - the source of the signal - * equipper - the mob we're equipping the slippery thing to - * slot - the slot we're equipping the slippery thing to on the equipper. + * Arguments + * * source - the source of the signal + * * equipper - the mob we're equipping the slippery thing to + * * slot - the slot we're equipping the slippery thing to on the equipper. */ /datum/component/slippery/proc/on_equip(datum/source, mob/equipper, slot) SIGNAL_HANDLER @@ -155,12 +187,13 @@ AddComponent(/datum/component/connect_loc_behalf, holder, holder_connections) RegisterSignal(holder, COMSIG_QDELETING, PROC_REF(holder_deleted)) -/* +/** * Detects if the holder mob is deleted. * If our holder mob is the holder set in this component, we null it. * - * source - the source of the signal - * possible_holder - the mob being deleted. + * Arguments: + * * source - the source of the signal + * * possible_holder - the mob being deleted. */ /datum/component/slippery/proc/holder_deleted(datum/source, datum/possible_holder) SIGNAL_HANDLER @@ -168,12 +201,13 @@ if(possible_holder == holder) holder = null -/* +/** * Gets called when COMSIG_ITEM_DROPPED is sent to parent. * Makes our holder mob un-slippery. * - * source - the source of the signal - * user - the mob that was formerly wearing our slippery item. + * Arguments: + * * source - the source of the signal + * * user - the mob that was formerly wearing our slippery item. */ /datum/component/slippery/proc/on_drop(datum/source, mob/user) SIGNAL_HANDLER @@ -185,12 +219,13 @@ holder = null -/* +/** * The slip proc, but for equipped items. * Slips the person who crossed us if we're lying down and unbuckled. * - * source - the source of the signal - * AM - the atom/movable that slipped on us. + * Arguments: + * * source - the source of the signal + * * arrived - the atom/movable that slipped on us. */ /datum/component/slippery/proc/Slip_on_wearer(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) SIGNAL_HANDLER diff --git a/code/datums/components/spirit_holding.dm b/code/datums/components/spirit_holding.dm index 82c37e8f26bbd4..37186825d621a2 100644 --- a/code/datums/components/spirit_holding.dm +++ b/code/datums/components/spirit_holding.dm @@ -7,7 +7,7 @@ ///bool on if this component is currently polling for observers to inhabit the item var/attempting_awakening = FALSE ///mob contained in the item. - var/mob/living/simple_animal/shade/bound_spirit + var/mob/living/basic/shade/bound_spirit /datum/component/spirit_holding/Initialize() if(!ismovable(parent)) //you may apply this to mobs, i take no responsibility for how that works out @@ -37,44 +37,40 @@ ///signal fired on self attacking parent /datum/component/spirit_holding/proc/on_attack_self(datum/source, mob/user) SIGNAL_HANDLER - INVOKE_ASYNC(src, PROC_REF(attempt_spirit_awaken), user) -/** - * attempt_spirit_awaken: called from on_attack_self, polls ghosts to possess the item in the form - * of a mob sitting inside the item itself - * - * Arguments: - * * awakener: user who interacted with the blade - */ -/datum/component/spirit_holding/proc/attempt_spirit_awaken(mob/awakener) + var/atom/thing = parent + if(attempting_awakening) - to_chat(awakener, span_warning("You are already trying to awaken [parent]!")) + thing.balloon_alert(user, "already channeling!") return if(!(GLOB.ghost_role_flags & GHOSTROLE_STATION_SENTIENCE)) - to_chat(awakener, span_warning("Anomalous otherworldly energies block you from awakening [parent]!")) + thing.balloon_alert(user, "spirits are unwilling!") + to_chat(user, span_warning("Anomalous otherworldly energies block you from awakening [parent]!")) return attempting_awakening = TRUE - to_chat(awakener, span_notice("You attempt to wake the spirit of [parent]...")) + thing.balloon_alert(user, "channeling...") - var/datum/callback/to_call = CALLBACK(src, PROC_REF(affix_spirit), awakener) + var/datum/callback/to_call = CALLBACK(src, PROC_REF(affix_spirit), user) parent.AddComponent(/datum/component/orbit_poll, \ ignore_key = POLL_IGNORE_POSSESSED_BLADE, \ job_bans = ROLE_PAI, \ to_call = to_call, \ - title = "Spirit of [awakener.real_name]'s blade", \ + title = "Spirit of [user.real_name]'s blade", \ ) - //Immediately unregister to prevent making a new spirit - UnregisterSignal(parent, COMSIG_ITEM_ATTACK_SELF) - /// On conclusion of the ghost poll /datum/component/spirit_holding/proc/affix_spirit(mob/awakener, mob/dead/observer/ghost) + var/atom/thing = parent + if(isnull(ghost)) - to_chat(awakener, span_warning("[parent] is dormant. Maybe you can try again later.")) + thing.balloon_alert(awakener, "silence...") attempting_awakening = FALSE return + // Immediately unregister to prevent making a new spirit + UnregisterSignal(parent, COMSIG_ITEM_ATTACK_SELF) + if(QDELETED(parent)) //if the thing that we're conjuring a spirit in has been destroyed, don't create a spirit to_chat(ghost, span_userdanger("The new vessel for your spirit has been destroyed! You remain an unbound ghost.")) return diff --git a/code/datums/components/supermatter_crystal.dm b/code/datums/components/supermatter_crystal.dm index 38968d1e3d1f5d..3c37bba33cb8dd 100644 --- a/code/datums/components/supermatter_crystal.dm +++ b/code/datums/components/supermatter_crystal.dm @@ -302,7 +302,12 @@ consumed_mob.investigate_log("has been dusted by [atom_source].", INVESTIGATE_DEATHS) if(istype(consumed_mob, /mob/living/simple_animal/parrot/poly)) // Dusting Poly creates a power surge force_event(/datum/round_event_control/supermatter_surge/poly, "Poly's revenge") - notify_ghosts("[consumed_mob] has been dusted by [atom_source]!", source = atom_source, action = NOTIFY_JUMP, header = "Polytechnical Difficulties") + notify_ghosts( + "[consumed_mob] has been dusted by [atom_source]!", + source = atom_source, + header = "Polytechnical Difficulties", + notify_flags = NOTIFY_CATEGORY_DEFAULT, + ) consumed_mob.dust(force = TRUE) matter_increase += 100 * object_size if(is_clown_job(consumed_mob.mind?.assigned_role)) diff --git a/code/datums/components/trader/trader.dm b/code/datums/components/trader/trader.dm new file mode 100644 index 00000000000000..b10041385277d5 --- /dev/null +++ b/code/datums/components/trader/trader.dm @@ -0,0 +1,457 @@ +#define TRADER_RADIAL_BUY "TRADER_RADIAL_BUY" +#define TRADER_RADIAL_SELL "TRADER_RADIAL_SELL" +#define TRADER_RADIAL_TALK "TRADER_RADIAL_TALK" +#define TRADER_RADIAL_LORE "TRADER_RADIAL_LORE" +#define TRADER_RADIAL_NO "TRADER_RADIAL_NO" +#define TRADER_RADIAL_YES "TRADER_RADIAL_YES" +#define TRADER_RADIAL_OUT_OF_STOCK "TRADER_RADIAL_OUT_OF_STOCK" +#define TRADER_RADIAL_DISCUSS_BUY "TRADER_RADIAL_DISCUSS_BUY" +#define TRADER_RADIAL_DISCUSS_SELL "TRADER_RADIAL_DISCUSS_SELL" + +#define TRADER_OPTION_BUY "Buy" +#define TRADER_OPTION_SELL "Sell" +#define TRADER_OPTION_TALK "Talk" +#define TRADER_OPTION_LORE "Lore" +#define TRADER_OPTION_NO "No" +#define TRADER_OPTION_YES "Yes" +#define TRADER_OPTION_BUYING "Buying?" +#define TRADER_OPTION_SELLING "Selling?" + +//The defines below show the index the info is located in the product_info entry list + +#define TRADER_PRODUCT_INFO_PRICE 1 +#define TRADER_PRODUCT_INFO_QUANTITY 2 +//Only valid for wanted_items +#define TRADER_PRODUCT_INFO_PRICE_MOD_DESCRIPTION 3 + +/** + * # Trader NPC Component + * Manages the barks and the stocks of the traders + * Also manages the interactive radial menu + */ +/datum/component/trader + + /** + * Format; list(TYPEPATH = list(PRICE, QUANTITY)) + * Associated list of items the NPC sells with how much they cost and the quantity available before a restock + * This list is filled by Initialize(), if you want to change the starting products, modify initial_products() + * * + */ + var/list/obj/item/products = list() + /** + * A list of wanted items that the trader would wish to buy, each typepath has a assigned value, quantity and additional flavor text + * + * CHILDREN OF TYPEPATHS INCLUDED IN WANTED_ITEMS WILL BE TREATED AS THE PARENT IF NO ENTRY EXISTS FOR THE CHILDREN + * + * As an additional note; if you include multiple children of a typepath; the typepath with the most children should be placed after all other typepaths + * Bad; list(/obj/item/milk = list(100, 1, ""), /obj/item/milk/small = list(50, 2, "")) + * Good; list(/obj/item/milk/small = list(50, 2, ""), /obj/item/milk = list(100, 1, "")) + * This is mainly because sell_item() uses a istype(item_being_sold, item_in_entry) to determine what parent should the child be automatically considered as + * If /obj/item/milk/small/spooky was being sold; /obj/item/milk/small would be the first to check against rather than /obj/item/milk + * + * Format; list(TYPEPATH = list(PRICE, QUANTITY, ADDITIONAL_DESCRIPTION)) + * Associated list of items able to be sold to the NPC with the money given for them. + * The price given should be the "base" price; any price manipulation based on variables should be done with apply_sell_price_mods() + * ADDITIONAL_DESCRIPTION is any additional text added to explain how the variables of the item effect the price; if it's stack based, it's final price depends how much is in the stack + * EX; /obj/item/stack/sheet/mineral/diamond = list(500, INFINITY, ", per 100 cm3 sheet of diamond") + * This list is filled by Initialize(), if you want to change the starting wanted items, modify initial_wanteds() + */ + var/list/wanted_items = list() + + ///Contains images of all radial icons + var/static/list/radial_icons_cache = list() + + ///Contains information of a specific trader + var/datum/trader_data/trader_data + +/* +Can accept both a type path, and an instance of a datum. Type path has priority. +*/ +/datum/component/trader/Initialize(trader_data_path = null, trader_data = null) + . = ..() + if(!isliving(parent)) + return COMPONENT_INCOMPATIBLE + + if(ispath(trader_data_path, /datum/trader_data)) + trader_data = new trader_data_path + if(isnull(trader_data)) + CRASH("Initialised trader component with no trader data.") + + src.trader_data = trader_data + + radial_icons_cache = list( + TRADER_RADIAL_BUY = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_buy"), + TRADER_RADIAL_SELL = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_sell"), + TRADER_RADIAL_TALK = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_talk"), + TRADER_RADIAL_LORE = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_lore"), + TRADER_RADIAL_DISCUSS_BUY = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_buying"), + TRADER_RADIAL_DISCUSS_SELL = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_selling"), + TRADER_RADIAL_YES = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_yes"), + TRADER_RADIAL_NO = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_no"), + TRADER_RADIAL_OUT_OF_STOCK = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_center"), + ) + + restock_products() + renew_item_demands() + +/datum/component/trader/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_hand)) + +/datum/component/trader/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_ATOM_ATTACK_HAND) + +///If our trader is alive, and the customer left clicks them with an empty hand without combat mode +/datum/component/trader/proc/on_attack_hand(atom/source, mob/living/carbon/customer) + SIGNAL_HANDLER + if(!can_trade(customer) || customer.combat_mode) + return + var/list/npc_options = list() + if(length(products)) + npc_options[TRADER_OPTION_BUY] = radial_icons_cache[TRADER_RADIAL_BUY] + if(length(wanted_items)) + npc_options[TRADER_OPTION_SELL] = radial_icons_cache[TRADER_RADIAL_SELL] + if(length(trader_data.say_phrases)) + npc_options[TRADER_OPTION_TALK] = radial_icons_cache[TRADER_RADIAL_TALK] + if(!length(npc_options)) + return + + var/mob/living/trader = parent + trader.face_atom(customer) + + INVOKE_ASYNC(src, PROC_REF(open_npc_options), customer, npc_options) + + return COMPONENT_CANCEL_ATTACK_CHAIN + +/** + * Generates a radial of the initial radials of the NPC + * Called via asynch, due to the sleep caused by show_radial_menu + * Arguments: + * * customer - (Mob REF) The mob trying to buy something + */ +/datum/component/trader/proc/open_npc_options(mob/living/carbon/customer, list/npc_options) + if(!can_trade(customer)) + return + var/npc_result = show_radial_menu(customer, parent, npc_options, custom_check = CALLBACK(src, PROC_REF(check_menu), customer), require_near = TRUE, tooltips = TRUE) + switch(npc_result) + if(TRADER_OPTION_BUY) + buy_item(customer) + if(TRADER_OPTION_SELL) + try_sell(customer) + if(TRADER_OPTION_TALK) + discuss(customer) + +/** + * Checks if the customer is ok to use the radial + * + * Checks if the customer is not a mob or is incapacitated or not adjacent to the source of the radial, in those cases returns FALSE, otherwise returns TRUE + * Arguments: + * * customer - (Mob REF) The mob checking the menu + */ +/datum/component/trader/proc/check_menu(mob/customer) + if(!istype(customer)) + return FALSE + if(IS_DEAD_OR_INCAP(customer) || !customer.Adjacent(parent)) + return FALSE + return TRUE + +/** + * Generates a radial of the items the NPC sells and lets the user try to buy one + * Arguments: + * * customer - (Mob REF) The mob trying to buy something + */ +/datum/component/trader/proc/buy_item(mob/customer) + if(!can_trade(customer)) + return + + if(!LAZYLEN(products)) + return + + var/list/display_names = list() + var/list/items = list() + var/list/product_info + + for(var/obj/item/thing as anything in products) + display_names["[initial(thing.name)]"] = thing + + if(!radial_icons_cache[thing]) + radial_icons_cache[thing] = image(icon = initial(thing.icon), icon_state = initial(thing.icon_state_preview) ? initial(thing.icon_state_preview) : initial(thing.icon_state)) + + var/image/item_image = radial_icons_cache[thing] + product_info = products[thing] + + if(product_info[TRADER_PRODUCT_INFO_QUANTITY] <= 0) //out of stock + item_image.overlays += radial_icons_cache[TRADER_RADIAL_OUT_OF_STOCK] + + items += list("[initial(thing.name)]" = item_image) + + var/pick = show_radial_menu(customer, parent, items, custom_check = CALLBACK(src, PROC_REF(check_menu), customer), require_near = TRUE, tooltips = TRUE) + if(!pick || !can_trade(customer)) + return + + var/obj/item/item_to_buy = display_names[pick] + var/mob/living/trader = parent + trader.face_atom(customer) + product_info = products[item_to_buy] + + if(!product_info[TRADER_PRODUCT_INFO_QUANTITY]) + trader.say("[initial(item_to_buy.name)] appears to be out of stock.") + return + + trader.say("It will cost you [product_info[TRADER_PRODUCT_INFO_PRICE]] [trader_data.currency_name] to buy \the [initial(item_to_buy.name)]. Are you sure you want to buy it?") + var/list/npc_options = list( + TRADER_OPTION_YES = radial_icons_cache[TRADER_RADIAL_YES], + TRADER_OPTION_NO = radial_icons_cache[TRADER_RADIAL_NO], + ) + + var/buyer_will_buy = show_radial_menu(customer, trader, npc_options, custom_check = CALLBACK(src, PROC_REF(check_menu), customer), require_near = TRUE, tooltips = TRUE) + if(buyer_will_buy != TRADER_OPTION_YES || !can_trade(customer)) + return + + trader.face_atom(customer) + + if(!spend_buyer_offhand_money(customer, product_info[TRADER_PRODUCT_INFO_PRICE])) + trader.say(trader_data.return_trader_phrase(NO_CASH_PHRASE)) + return + + item_to_buy = new item_to_buy(get_turf(customer)) + customer.put_in_hands(item_to_buy) + playsound(trader, trader_data.sell_sound, 50, TRUE) + log_econ("[item_to_buy] has been sold to [customer] (typepath used for product info; [item_to_buy.type]) by [trader] for [product_info[TRADER_PRODUCT_INFO_PRICE]] cash.") + product_info[TRADER_PRODUCT_INFO_QUANTITY] -= 1 + trader.say(trader_data.return_trader_phrase(BUY_PHRASE)) + +///Calculates the value of money in the hand of the buyer and spends it if it's sufficient +/datum/component/trader/proc/spend_buyer_offhand_money(mob/customer, the_cost) + var/value = 0 + var/obj/item/holochip/cash = customer.is_holding_item_of_type(/obj/item/holochip) + if(cash) + value += cash.credits + if((value >= the_cost) && cash) + return cash.spend(the_cost) + return FALSE //Purchase unsuccessful + +/** + * Tries to call sell_item on one of the customer's held items, if fail gives a chat message + * + * Gets both items in the customer's hands, and then tries to call sell_item on them, if both fail, he gives a chat message + * Arguments: + * * customer - (Mob REF) The mob trying to sell something + */ +/datum/component/trader/proc/try_sell(mob/customer) + if(!can_trade(customer)) + return + var/sold_item = FALSE + for(var/obj/item/an_item in customer.held_items) + if(sell_item(customer, an_item)) + sold_item = TRUE + break + if(!sold_item && can_trade(customer)) //only talk if you are not dead or in combat + var/mob/living/trader = parent + trader.say(trader_data.return_trader_phrase(ITEM_REJECTED_PHRASE)) + + +/** + * Checks if an item is in the list of wanted items and if it is after a Yes/No radial returns generate_cash with the value of the item for the NPC + * Arguments: + * * customer - (Mob REF) The mob trying to sell something + * * selling - (Item REF) The item being sold + */ +/datum/component/trader/proc/sell_item(mob/customer, obj/item/selling) + if(isnull(selling)) + return FALSE + var/list/product_info + //Keep track of the typepath; rather mundane but it's required for correctly modifying the wanted_items + //should a product be sellable because even if it doesn't have a entry because it's a child of a parent that is present on the list + var/typepath_for_product_info + + if(selling.type in wanted_items) + product_info = wanted_items[selling.type] + typepath_for_product_info = selling.type + else //Assume wanted_items is setup in the correct way; read wanted_items documentation for more info + for(var/typepath in wanted_items) + if(!istype(selling, typepath)) + continue + + product_info = wanted_items[typepath] + typepath_for_product_info = typepath + break + + if(!product_info) //Nothing interesting to sell + return FALSE + + var/mob/living/trader = parent + + if(product_info[TRADER_PRODUCT_INFO_QUANTITY] <= 0) + trader.say(trader_data.return_trader_phrase(TRADER_HAS_ENOUGH_ITEM_PHRASE)) + return FALSE + + var/cost = apply_sell_price_mods(selling, product_info[TRADER_PRODUCT_INFO_PRICE]) + if(cost <= 0) + trader.say(trader_data.return_trader_phrase(ITEM_IS_WORTHLESS_PHRASE)) + return FALSE + + trader.say(trader_data.return_trader_phrase(INTERESTED_PHRASE)) + trader.say("You will receive [cost] [trader_data.currency_name] for the [selling].") + var/list/npc_options = list( + TRADER_OPTION_YES = radial_icons_cache[TRADER_RADIAL_YES], + TRADER_OPTION_NO = radial_icons_cache[TRADER_RADIAL_NO], + ) + + trader.face_atom(customer) + + var/npc_result = show_radial_menu(customer, trader, npc_options, custom_check = CALLBACK(src, PROC_REF(check_menu), customer), require_near = TRUE, tooltips = TRUE) + if(!can_trade(customer)) + return + if(npc_result != TRADER_OPTION_YES) + trader.say(trader_data.return_trader_phrase(ITEM_SELLING_CANCELED_PHRASE)) + return TRUE + + trader.say(trader_data.return_trader_phrase(ITEM_SELLING_ACCEPTED_PHRASE)) + playsound(trader, trader_data.sell_sound, 50, TRUE) + log_econ("[selling] has been sold to [trader] (typepath used for product info; [typepath_for_product_info]) by [customer] for [cost] cash.") + exchange_sold_items(selling, cost, typepath_for_product_info) + generate_cash(cost, customer) + return TRUE + +/** + * Modifies the 'base' price of a item based on certain variables + * + * Arguments: + * * Reference to the item; this is the item being sold + * * Original cost; the original cost of the item, to be manipulated depending on the variables of the item, one example is using item.amount if it's a stack + */ +/datum/component/trader/proc/apply_sell_price_mods(obj/item/selling, original_cost) + if(isstack(selling)) + var/obj/item/stack/stackoverflow = selling + original_cost *= stackoverflow.amount + return original_cost + +/** + * Handles modifying/deleting the items to ensure that a proper amount is converted into cash; put into it's own proc to make the children of this not override a 30+ line sell_item() + * + * Arguments: + * * selling - (Item REF) this is the item being sold + * * value_exchanged_for - (Number) the "value", useful for a scenario where you want to remove enough items equal to the value + * * original_typepath - (Typepath) For scenarios where a children of a parent is being sold but we want to modify the parent's product information + */ +/datum/component/trader/proc/exchange_sold_items(obj/item/selling, value_exchanged_for, original_typepath) + var/list/product_info = wanted_items[original_typepath] + if(isstack(selling)) + var/obj/item/stack/the_stack = selling + var/actually_sold = min(the_stack.amount, product_info[TRADER_PRODUCT_INFO_QUANTITY]) + the_stack.use(actually_sold) + product_info[TRADER_PRODUCT_INFO_QUANTITY] -= (actually_sold) + else + qdel(selling) + product_info[TRADER_PRODUCT_INFO_QUANTITY] -= 1 + +/** + * Creates an item equal to the value set by the proc and puts it in the user's hands if possible + * Arguments: + * * value - A number; The amount of cash that will be on the holochip + * * customer - Reference to a mob; The mob we put the holochip in hands of + */ +/datum/component/trader/proc/generate_cash(value, mob/customer) + var/obj/item/holochip/chip = new /obj/item/holochip(get_turf(customer), value) + customer.put_in_hands(chip) + +///Talk about what items are being sold/wanted by the trader and in what quantity or lore +/datum/component/trader/proc/discuss(mob/customer) + var/list/npc_options = list( + TRADER_OPTION_LORE = radial_icons_cache[TRADER_RADIAL_LORE], + TRADER_OPTION_SELLING = radial_icons_cache[TRADER_RADIAL_DISCUSS_SELL], + TRADER_OPTION_BUYING = radial_icons_cache[TRADER_RADIAL_DISCUSS_BUY], + ) + var/pick = show_radial_menu(customer, parent, npc_options, custom_check = CALLBACK(src, PROC_REF(check_menu), customer), require_near = TRUE, tooltips = TRUE) + if(!can_trade(customer)) + return + switch(pick) + if(TRADER_OPTION_LORE) + var/mob/living/trader = parent + trader.say(trader_data.return_trader_phrase(TRADER_LORE_PHRASE)) + if(TRADER_OPTION_BUYING) + trader_buys_what(customer) + if(TRADER_OPTION_SELLING) + trader_sells_what(customer) + +///Displays to the customer what the trader is willing to buy and how much until a restock happens +/datum/component/trader/proc/trader_buys_what(mob/customer) + if(!can_trade(customer)) + return + if(!length(wanted_items)) + var/mob/living/trader = parent + trader.say(trader_data.return_trader_phrase(TRADER_NOT_BUYING_ANYTHING)) + return + + var/list/buy_info = list(span_green("I'm willing to buy the following:")) + + var/list/product_info + for(var/obj/item/thing as anything in wanted_items) + product_info = wanted_items[thing] + var/tern_op_result = (product_info[TRADER_PRODUCT_INFO_QUANTITY] == INFINITY ? "as many as I can." : "[product_info[TRADER_PRODUCT_INFO_QUANTITY]]") //Coder friendly string concat + if(product_info[TRADER_PRODUCT_INFO_QUANTITY] <= 0) //Zero demand + buy_info += span_notice("• [span_red("(DOESN'T WANT MORE)")] [initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [trader_data.currency_name][product_info[TRADER_PRODUCT_INFO_PRICE_MOD_DESCRIPTION]]; willing to buy [span_red("[tern_op_result]")] more.") + else + buy_info += span_notice("• [initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [trader_data.currency_name][product_info[TRADER_PRODUCT_INFO_PRICE_MOD_DESCRIPTION]]; willing to buy [span_green("[tern_op_result]")]") + + to_chat(customer, examine_block(buy_info.Join("\n"))) + +///Displays to the customer what the trader is selling and how much is in stock +/datum/component/trader/proc/trader_sells_what(mob/customer) + if(!can_trade(customer)) + return + var/mob/living/trader = parent + if(!length(products)) + trader.say(trader_data.return_trader_phrase(TRADER_NOT_SELLING_ANYTHING)) + return + var/list/sell_info = list(span_green("I'm currently selling the following:")) + var/list/product_info + for(var/obj/item/thing as anything in products) + product_info = products[thing] + var/tern_op_result = (product_info[TRADER_PRODUCT_INFO_QUANTITY] == INFINITY ? "an infinite amount" : "[product_info[TRADER_PRODUCT_INFO_QUANTITY]]") //Coder friendly string concat + if(product_info[TRADER_PRODUCT_INFO_QUANTITY] <= 0) //Out of stock + sell_info += span_notice("• [span_red("(OUT OF STOCK)")] [initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [trader_data.currency_name]; [span_red("[tern_op_result]")] left in stock") + else + sell_info += span_notice("• [initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [trader_data.currency_name]; [span_green("[tern_op_result]")] left in stock") + to_chat(customer, examine_block(sell_info.Join("\n"))) + +///Sets quantity of all products to initial(quanity); this proc is currently called during initialize +/datum/component/trader/proc/restock_products() + products = trader_data.initial_products.Copy() + +///Sets quantity of all wanted_items to initial(quanity); this proc is currently called during initialize +/datum/component/trader/proc/renew_item_demands() + wanted_items = trader_data.initial_wanteds.Copy() + +///Returns if the trader is conscious and its combat mode is disabled. +/datum/component/trader/proc/can_trade(mob/customer) + var/mob/living/trader = parent + if(trader.combat_mode) + trader.balloon_alert(customer, "in combat!") + return FALSE + if(IS_DEAD_OR_INCAP(trader)) + trader.balloon_alert(customer, "indisposed!") + return FALSE + return TRUE + +#undef TRADER_RADIAL_BUY +#undef TRADER_RADIAL_SELL +#undef TRADER_RADIAL_TALK +#undef TRADER_RADIAL_LORE +#undef TRADER_RADIAL_DISCUSS_BUY +#undef TRADER_RADIAL_DISCUSS_SELL +#undef TRADER_RADIAL_NO +#undef TRADER_RADIAL_YES +#undef TRADER_RADIAL_OUT_OF_STOCK +#undef TRADER_PRODUCT_INFO_PRICE +#undef TRADER_PRODUCT_INFO_QUANTITY +#undef TRADER_PRODUCT_INFO_PRICE_MOD_DESCRIPTION + +#undef TRADER_OPTION_BUY +#undef TRADER_OPTION_SELL +#undef TRADER_OPTION_TALK +#undef TRADER_OPTION_LORE +#undef TRADER_OPTION_NO +#undef TRADER_OPTION_YES +#undef TRADER_OPTION_BUYING +#undef TRADER_OPTION_SELLING diff --git a/code/datums/ductnet.dm b/code/datums/ductnet.dm index e4dd3959c22468..e97add695d9a35 100644 --- a/code/datums/ductnet.dm +++ b/code/datums/ductnet.dm @@ -43,6 +43,7 @@ for(var/dir in P.ducts) if(P.ducts[dir] == src) P.ducts -= dir + if(!ducts.len) //there were no ducts, so it was a direct connection. we destroy ourselves since a ductnet with only one plumber and no ducts is worthless destroy_network() diff --git a/code/datums/elements/ai_swap_combat_mode.dm b/code/datums/elements/ai_swap_combat_mode.dm new file mode 100644 index 00000000000000..2b7167000fcfa3 --- /dev/null +++ b/code/datums/elements/ai_swap_combat_mode.dm @@ -0,0 +1,66 @@ +/** + * Attached to a mob with an AI controller, updates combat mode when the affected mob acquires or loses targets + */ +/datum/element/ai_swap_combat_mode + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// The message we yell when we enter combat mode + var/list/battle_start_barks + /// A one liner said when we exit combat mode + var/list/battle_end_barks + /// The chance to yell the above lines + var/speech_chance + /// Target key + var/target_key + +/datum/element/ai_swap_combat_mode/Attach(datum/target, target_key, list/battle_start_barks = null, list/battle_end_barks = null) + . = ..() + if(!isliving(target)) + return ELEMENT_INCOMPATIBLE + var/mob/living/living_target = target + if(!living_target.ai_controller) + return ELEMENT_INCOMPATIBLE + + if(isnull(battle_start_barks)) + battle_start_barks = list("En Garde!",) + + if(isnull(battle_end_barks)) + battle_end_barks = list("Never should have come here",) + + src.battle_start_barks = battle_start_barks + src.battle_end_barks = battle_end_barks + src.target_key = target_key + RegisterSignal(target, COMSIG_AI_BLACKBOARD_KEY_SET(target_key), PROC_REF(on_target_gained)) + RegisterSignal(target, COMSIG_AI_BLACKBOARD_KEY_CLEARED(target_key), PROC_REF(on_target_cleared)) + +/datum/element/ai_swap_combat_mode/Detach(datum/source) + . = ..() + UnregisterSignal(source, list( + COMSIG_AI_BLACKBOARD_KEY_SET(target_key), + COMSIG_AI_BLACKBOARD_KEY_CLEARED(target_key), + )) + +/// When the mob gains a target, and it was not already in combat mode, enter it +/datum/element/ai_swap_combat_mode/proc/on_target_gained(mob/living/source) + SIGNAL_HANDLER + + if(swap_mode(source, TRUE)) + INVOKE_ASYNC(src, PROC_REF(speak_bark), source, battle_start_barks) + +/// When the mob loses its target, and it was not already out of combat mode, exit it +/datum/element/ai_swap_combat_mode/proc/on_target_cleared(mob/living/source) + SIGNAL_HANDLER + + if(swap_mode(source, FALSE)) + INVOKE_ASYNC(src, PROC_REF(speak_bark), source, battle_end_barks) + +///Says a quip, if the RNG allows it +/datum/element/ai_swap_combat_mode/proc/speak_bark(mob/living/source, line) + source.say(pick(line)) + +///If the combat mode would be changed into a different state, updates it and returns TRUE, otherwise returns FALSE +/datum/element/ai_swap_combat_mode/proc/swap_mode(mob/living/source, new_mode) + if(source.combat_mode == new_mode) + return FALSE + source.set_combat_mode(new_mode) + return TRUE diff --git a/code/datums/elements/cuffsnapping.dm b/code/datums/elements/cuffsnapping.dm index c0dfdcf60913b5..df445f4acc971f 100644 --- a/code/datums/elements/cuffsnapping.dm +++ b/code/datums/elements/cuffsnapping.dm @@ -7,7 +7,7 @@ * cuffsnapping attacks have a wounding bonus between severe and critical+10 wound thresholds. Without some serious wound protecting * armour this all but guarantees a wound of some sort. The attack is directed specifically at a limb and the limb takes the damage. * - * Requires the cutter_user to be aiming for either leg zone, which will be targetted specifically. They will than have a 3-second long + * Requires the cutter_user to be aiming for either leg zone, which will be targeted specifically. They will than have a 3-second long * do_after before executing the attack. * * cuffsnapping requires the target to either be on the floor, immobilised or buckled to something. And also to have an appropriate leg. diff --git a/code/datums/elements/dextrous.dm b/code/datums/elements/dextrous.dm index 526dfa974afd6c..681e2a9488d8c0 100644 --- a/code/datums/elements/dextrous.dm +++ b/code/datums/elements/dextrous.dm @@ -50,8 +50,10 @@ /// Try picking up items /datum/element/dextrous/proc/on_hand_clicked(mob/living/hand_haver, atom/target, proximity, modifiers) SIGNAL_HANDLER - if(!proximity) - return NONE + if (!proximity && target.loc != hand_haver) + var/obj/item/obj_item = target + if (istype(obj_item) && !obj_item.atom_storage && !(obj_item.item_flags & IN_STORAGE)) + return NONE if (!isitem(target) && hand_haver.combat_mode) return NONE if (LAZYACCESS(modifiers, RIGHT_CLICK)) diff --git a/code/datums/elements/door_pryer.dm b/code/datums/elements/door_pryer.dm index a17687407e39c1..b7f213b3856f6d 100644 --- a/code/datums/elements/door_pryer.dm +++ b/code/datums/elements/door_pryer.dm @@ -22,7 +22,7 @@ . = ..() UnregisterSignal(source, COMSIG_LIVING_UNARMED_ATTACK) -/// If we're targetting an airlock, open it +/// If we're targeting an airlock, open it /datum/element/door_pryer/proc/on_attack(mob/living/basic/attacker, atom/target, proximity_flag) SIGNAL_HANDLER if(!proximity_flag || !istype(target, /obj/machinery/door/airlock)) diff --git a/code/datums/elements/kneecapping.dm b/code/datums/elements/kneecapping.dm index 340938c430c35d..977268e94a10b9 100644 --- a/code/datums/elements/kneecapping.dm +++ b/code/datums/elements/kneecapping.dm @@ -7,7 +7,7 @@ * Kneecapping attacks have a wounding bonus between severe and critical+10 wound thresholds. Without some serious wound protecting * armour this all but guarantees a wound of some sort. The attack is directed specifically at a limb and the limb takes the damage. * - * Requires the attacker to be aiming for either leg zone, which will be targetted specifically. They will than have a 3-second long + * Requires the attacker to be aiming for either leg zone, which will be targeted specifically. They will than have a 3-second long * do_after before executing the attack. * * Kneecapping requires the target to either be on the floor, immobilised or buckled to something. And also to have an appropriate leg. diff --git a/code/datums/elements/light_eater.dm b/code/datums/elements/light_eater.dm index b4f7cf1042f3d4..50f88cb9e9b231 100644 --- a/code/datums/elements/light_eater.dm +++ b/code/datums/elements/light_eater.dm @@ -4,6 +4,10 @@ * The temporary equivalent is [/datum/component/light_eater] */ /datum/element/light_eater + var/static/list/blacklisted_areas = typecacheof(list( + /turf/open/space, + /turf/open/lava, + )) /datum/element/light_eater/Attach(datum/target) if(isatom(target)) @@ -83,8 +87,9 @@ * - [eater][/datum]: The light eater eating the morsel. This is the datum that the element is attached to that started this chain. */ /datum/element/light_eater/proc/devour(atom/morsel, datum/eater) - var/static/list/undevourable = typecacheof(list(/turf/open/space)) - if(is_type_in_typecache(morsel, undevourable)) + if(is_type_in_typecache(morsel, blacklisted_areas)) + return FALSE + if(istransparentturf(morsel)) return FALSE if(morsel.light_power <= 0 || morsel.light_range <= 0 || !morsel.light_on) return FALSE diff --git a/code/datums/elements/tear_wall.dm b/code/datums/elements/tear_wall.dm deleted file mode 100644 index 0d24bbda28985e..00000000000000 --- a/code/datums/elements/tear_wall.dm +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Attached to a basic mob that will then be able to tear down a wall after some time. - */ -/datum/element/tear_wall - element_flags = ELEMENT_BESPOKE - argument_hash_start_idx = 3 - /// The rate at which we can break regular walls - var/regular_tear_time - /// The rate at which we can break reinforced walls - var/reinforced_tear_time - -/datum/element/tear_wall/Attach(datum/target, regular_tear_time = 2 SECONDS, reinforced_tear_time = 4 SECONDS) - . = ..() - if(!isbasicmob(target)) - return ELEMENT_INCOMPATIBLE - - src.regular_tear_time = regular_tear_time - src.reinforced_tear_time = reinforced_tear_time - RegisterSignal(target, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(attack_wall)) - -/datum/element/bonus_damage/Detach(datum/source) - UnregisterSignal(source, COMSIG_HOSTILE_POST_ATTACKINGTARGET) - return ..() - -/// Checks if we are attacking a wall -/datum/element/tear_wall/proc/attack_wall(mob/living/basic/attacker, atom/target, success) - SIGNAL_HANDLER - - if(!iswallturf(target)) - return - var/turf/closed/wall/thewall = target - var/prying_time = regular_tear_time - if(istype(thewall, /turf/closed/wall/r_wall)) - prying_time = reinforced_tear_time - INVOKE_ASYNC(src, PROC_REF(async_attack_wall), attacker, thewall, prying_time) - -/// Performs taking down the wall -/datum/element/tear_wall/proc/async_attack_wall(mob/living/basic/attacker, turf/closed/wall/thewall, prying_time) - if(DOING_INTERACTION_WITH_TARGET(attacker, thewall)) - attacker.balloon_alert(attacker, "busy!") - return - to_chat(attacker, span_warning("You begin tearing through the wall...")) - playsound(attacker, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE) - if(do_after(attacker, prying_time, target = thewall)) - if(isopenturf(thewall)) - return - thewall.dismantle_wall(1) - playsound(attacker, 'sound/effects/meteorimpact.ogg', 100, TRUE) diff --git a/code/datums/elements/wall_tearer.dm b/code/datums/elements/wall_tearer.dm index e7ca4b3be96f25..75e892dc4cb856 100644 --- a/code/datums/elements/wall_tearer.dm +++ b/code/datums/elements/wall_tearer.dm @@ -20,7 +20,7 @@ /// What interaction key do we use for our interaction var/do_after_key -/datum/element/wall_tearer/Attach(datum/target, allow_reinforced = TRUE, tear_time = 4 SECONDS, reinforced_multiplier = 3, do_after_key = null) +/datum/element/wall_tearer/Attach(datum/target, allow_reinforced = TRUE, tear_time = 2 SECONDS, reinforced_multiplier = 2, do_after_key = null) . = ..() if (!isliving(target)) return ELEMENT_INCOMPATIBLE @@ -62,6 +62,7 @@ var/is_valid = validate_target(target, tearer) if (is_valid != WALL_TEAR_ALLOWED) return + tearer.do_attack_animation(target) target.AddComponent(/datum/component/torn_wall) is_valid = validate_target(target, tearer) // And now we might have just destroyed it if (is_valid == WALL_TEAR_ALLOWED) diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index 3ee251dfbabdf6..88db5948d536ae 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -110,7 +110,7 @@ // SKYRAT EDIT END var/tmp_sound = get_sound(user) - if(tmp_sound && should_play_sound(user, intentional) && !TIMER_COOLDOWN_CHECK(user, type)) + if(tmp_sound && should_play_sound(user, intentional) && TIMER_COOLDOWN_FINISHED(user, type)) TIMER_COOLDOWN_START(user, type, audio_cooldown) //SKYRAT EDIT CHANGE BEGIN //playsound(user, tmp_sound, 50, vary) - SKYRAT EDIT - ORIGINAL diff --git a/code/datums/mapgen/_MapGenerator.dm b/code/datums/mapgen/_MapGenerator.dm deleted file mode 100644 index cecc0c65d1ba41..00000000000000 --- a/code/datums/mapgen/_MapGenerator.dm +++ /dev/null @@ -1,10 +0,0 @@ -///This type is responsible for any map generation behavior that is done in areas, override this to allow for area-specific map generation. This generation is ran by areas in initialize. -/datum/map_generator - -///This proc will be ran by areas on Initialize, and provides the areas turfs as argument to allow for generation. -/datum/map_generator/proc/generate_terrain(list/turfs, area/generate_in) - return - -/// Populate terrain with flora, fauna, features and basically everything that isn't a turf -/datum/map_generator/proc/populate_terrain(list/turfs, area/generate_in) - return diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index 1bc6659dfba679..f8f05248b27fad 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -1,6 +1,6 @@ #define STRONG_PUNCH_COMBO "HH" #define LAUNCH_KICK_COMBO "HD" -#define DROP_KICK_COMBO "HG" +#define DROP_KICK_COMBO "DD" /datum/martial_art/the_sleeping_carp name = "The Sleeping Carp" @@ -8,18 +8,19 @@ allow_temp_override = FALSE help_verb = /mob/living/proc/sleeping_carp_help display_combos = TRUE + var/list/scarp_traits = list(TRAIT_NOGUNS, TRAIT_HARDLY_WOUNDED, TRAIT_NODISMEMBER, TRAIT_HEAVY_SLEEPER) /datum/martial_art/the_sleeping_carp/teach(mob/living/target, make_temporary = FALSE) . = ..() if(!.) return - target.add_traits(list(TRAIT_NOGUNS, TRAIT_HARDLY_WOUNDED, TRAIT_NODISMEMBER), SLEEPING_CARP_TRAIT) + target.add_traits(scarp_traits, SLEEPING_CARP_TRAIT) RegisterSignal(target, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) RegisterSignal(target, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(hit_by_projectile)) target.faction |= FACTION_CARP //:D /datum/martial_art/the_sleeping_carp/on_remove(mob/living/target) - target.remove_traits(list(TRAIT_NOGUNS, TRAIT_HARDLY_WOUNDED, TRAIT_NODISMEMBER), SLEEPING_CARP_TRAIT) + target.remove_traits(scarp_traits, SLEEPING_CARP_TRAIT) UnregisterSignal(target, COMSIG_ATOM_ATTACKBY) UnregisterSignal(target, COMSIG_ATOM_PRE_BULLET_ACT) target.faction -= FACTION_CARP //:( @@ -49,12 +50,12 @@ defender.visible_message(span_danger("[attacker] [atk_verb]s [defender]!"), \ span_userdanger("[attacker] [atk_verb]s you!"), null, null, attacker) to_chat(attacker, span_danger("You [atk_verb] [defender]!")) - playsound(get_turf(defender), 'sound/weapons/punch1.ogg', 25, TRUE, -1) + playsound(defender, 'sound/weapons/punch1.ogg', 25, TRUE, -1) log_combat(attacker, defender, "strong punched (Sleeping Carp)") defender.apply_damage(20, attacker.get_attack_type(), affecting) return -///Crashing Wave Kick: Punch Shove combo, throws people seven tiles backwards +///Crashing Wave Kick: Harm Disarm combo, throws people seven tiles backwards /datum/martial_art/the_sleeping_carp/proc/launchKick(mob/living/attacker, mob/living/defender) attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) defender.visible_message(span_warning("[attacker] kicks [defender] square in the chest, sending them flying!"), \ @@ -66,56 +67,80 @@ log_combat(attacker, defender, "launchkicked (Sleeping Carp)") return -///Keelhaul: Harm Grab combo, knocks people down, deals stamina damage while they're on the floor +///Keelhaul: Disarm Disarm combo, knocks people down and deals substantial stamina damage, and also discombobulates them. Knocks objects out of their hands if they're already on the ground. /datum/martial_art/the_sleeping_carp/proc/dropKick(mob/living/attacker, mob/living/defender) attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) playsound(get_turf(attacker), 'sound/effects/hit_kick.ogg', 50, TRUE, -1) if(defender.body_position == STANDING_UP) - defender.apply_damage(10, attacker.get_attack_type(), BODY_ZONE_HEAD, wound_bonus = CANT_WOUND) - defender.apply_damage(40, STAMINA, BODY_ZONE_HEAD) defender.Knockdown(4 SECONDS) defender.visible_message(span_warning("[attacker] kicks [defender] in the head, sending them face first into the floor!"), \ span_userdanger("You are kicked in the head by [attacker], sending you crashing to the floor!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) else - defender.apply_damage(5, attacker.get_attack_type(), BODY_ZONE_HEAD, wound_bonus = CANT_WOUND) - defender.apply_damage(40, STAMINA, BODY_ZONE_HEAD) defender.drop_all_held_items() defender.visible_message(span_warning("[attacker] kicks [defender] in the head!"), \ span_userdanger("You are kicked in the head by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) + defender.apply_damage(40, STAMINA) + defender.adjust_dizzy_up_to(10 SECONDS, 10 SECONDS) + defender.adjust_temp_blindness_up_to(2 SECONDS, 10 SECONDS) log_combat(attacker, defender, "dropkicked (Sleeping Carp)") return /datum/martial_art/the_sleeping_carp/grab_act(mob/living/attacker, mob/living/defender) + if(!can_deflect(attacker)) //allows for deniability + return ..() + add_to_streak("G", defender) if(check_streak(attacker, defender)) return TRUE - log_combat(attacker, defender, "grabbed (Sleeping Carp)") + var/grab_log_description = "grabbed" + attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) + playsound(defender, 'sound/weapons/punch1.ogg', 25, TRUE, -1) + if(defender.stat != DEAD && !defender.IsUnconscious() && defender.getStaminaLoss() >= 80) //We put our target to sleep. + defender.visible_message( + span_danger("[attacker] carefully pinch a nerve in [defender]'s neck, knocking them out cold"), + span_userdanger("[attacker] pinches something in your neck, and you fall unconscious!"), + ) + grab_log_description = "grabbed and nerve pinched" + defender.Unconscious(10 SECONDS) + defender.apply_damage(20, STAMINA) + log_combat(attacker, defender, "[grab_log_description] (Sleeping Carp)") return ..() /datum/martial_art/the_sleeping_carp/harm_act(mob/living/attacker, mob/living/defender) add_to_streak("H", defender) if(check_streak(attacker, defender)) return TRUE + var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected)) attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) var/atk_verb = pick("kick", "chop", "hit", "slam") defender.visible_message(span_danger("[attacker] [atk_verb]s [defender]!"), \ span_userdanger("[attacker] [atk_verb]s you!"), null, null, attacker) to_chat(attacker, span_danger("You [atk_verb] [defender]!")) - defender.apply_damage(rand(10,15), BRUTE, affecting, wound_bonus = CANT_WOUND) - playsound(get_turf(defender), 'sound/weapons/punch1.ogg', 25, TRUE, -1) + + defender.apply_damage(rand(10,15), attacker.get_attack_type(), affecting, wound_bonus = CANT_WOUND) + playsound(defender, 'sound/weapons/punch1.ogg', 25, TRUE, -1) log_combat(attacker, defender, "punched (Sleeping Carp)") + return TRUE /datum/martial_art/the_sleeping_carp/disarm_act(mob/living/attacker, mob/living/defender) + if(!can_deflect(attacker)) //allows for deniability + return ..() + add_to_streak("D", defender) if(check_streak(attacker, defender)) return TRUE + + attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) + playsound(defender, 'sound/weapons/punch1.ogg', 25, TRUE, -1) + defender.apply_damage(20, STAMINA) log_combat(attacker, defender, "disarmed (Sleeping Carp)") + return ..() /datum/martial_art/the_sleeping_carp/proc/can_deflect(mob/living/carp_user) - if(!can_use(carp_user) || !carp_user.throw_mode) + if(!can_use(carp_user) || !carp_user.combat_mode) return FALSE if(carp_user.incapacitated(IGNORE_GRAB)) //NO STUN return FALSE @@ -165,12 +190,13 @@ set category = "Sleeping Carp" to_chat(usr, "You retreat inward and recall the teachings of the Sleeping Carp...\n\ - [span_notice("Gnashing Teeth")]: Punch Punch. Deal additional damage every second (consecutive) punch!\n\ + [span_notice("Gnashing Teeth")]: Punch Punch. Deal additional damage every second (consecutive) punch! Very good chance to wound!\n\ [span_notice("Crashing Wave Kick")]: Punch Shove. Launch your opponent away from you with incredible force!\n\ - [span_notice("Keelhaul")]: Punch Grab. Kick an opponent to the floor, knocking them down! If your opponent is already prone, this move will disarm them and deal additional stamina damage to them.\n\ - While in throw mode (and not stunned, not a hulk, and not in a mech), you can reflect all projectiles that come your way, sending them back at the people who fired them! \ - Also, you are more resilient against suffering wounds in combat, and your limbs cannot be dismembered. This grants you extra staying power during extended combat, especially against slashing and other bleeding weapons. \ - You are not invincible, however- while you may not suffer debilitating wounds often, you must still watch your health and should have appropriate medical supplies for use during downtime. \ + [span_notice("Keelhaul")]: Shove Shove. Nonlethally kick an opponent to the floor, knocking them down, discombobulating them and dealing substantial stamina damage. If they're already prone, disarm them as well.\n\ + [span_notice("Grabs and Shoves")]: While in combat mode, your typical grab and shove do decent stamina damage. If you grab someone who has substantial amounts of stamina damage, you knock them out!\n\ + While in combat mode (and not stunned, not a hulk, and not in a mech), you can reflect all projectiles that come your way, sending them back at the people who fired them! \n\ + Also, you are more resilient against suffering wounds in combat, and your limbs cannot be dismembered. This grants you extra staying power during extended combat, especially against slashing and other bleeding weapons. \n\ + You are not invincible, however- while you may not suffer debilitating wounds often, you must still watch your health and should have appropriate medical supplies for use during downtime. \n\ In addition, your training has imbued you with a loathing of guns, and you can no longer use them.") diff --git a/code/datums/mocking/client.dm b/code/datums/mocking/client.dm index 8e09883ae21770..418f5cfb8db2f1 100644 --- a/code/datums/mocking/client.dm +++ b/code/datums/mocking/client.dm @@ -27,14 +27,24 @@ var/tgui_say var/typing_indicators +/datum/client_interface/New() + ..() + var/static/mock_client_uid = 0 + mock_client_uid++ + + src.key = "[key]_[mock_client_uid]" + ckey = ckey(key) + +#ifdef UNIT_TESTS // otherwise this shit can leak into production servers which is drather bad + GLOB.directory[ckey] = src +#endif + +/datum/client_interface/Destroy(force, ...) + GLOB.directory -= ckey + return ..() + /datum/client_interface/proc/IsByondMember() return FALSE -/datum/client_interface/New(key) - ..() - if(key) - src.key = key - ckey = ckey(key) - /datum/client_interface/proc/set_macros() return diff --git a/code/datums/mutations/touch.dm b/code/datums/mutations/touch.dm index 3f798ba52b2161..743f2b3fbf83ba 100644 --- a/code/datums/mutations/touch.dm +++ b/code/datums/mutations/touch.dm @@ -38,7 +38,7 @@ ///This var decides if the spell should chain, dictated by presence of power chromosome var/chain = FALSE ///Affects damage, should do about 1 per limb - var/zap_power = 3e6 + var/zap_power = 7500 ///Range of tesla shock bounces var/zap_range = 7 ///flags that dictate what the tesla shock can interact with, Can only damage mobs, Cannot damage machines or generate energy @@ -60,7 +60,7 @@ span_userdanger("[caster] electrocutes you!"), ) if(chain) - tesla_zap(victim, zap_range, zap_power, zap_flags) + tesla_zap(source = victim, zap_range = zap_range, power = zap_power, cutoff = 1e3, zap_flags = zap_flags) carbon_victim.visible_message(span_danger("An arc of electricity explodes out of [victim]!")) return TRUE @@ -72,7 +72,7 @@ span_userdanger("[caster] electrocutes you!"), ) if(chain) - tesla_zap(victim, zap_range, zap_power, zap_flags) + tesla_zap(source = victim, zap_range = zap_range, power = zap_power, cutoff = 1e3, zap_flags = zap_flags) living_victim.visible_message(span_danger("An arc of electricity explodes out of [victim]!")) return TRUE diff --git a/code/datums/proximity_monitor/fields/timestop.dm b/code/datums/proximity_monitor/fields/timestop.dm index 7fad290fc74d27..86ea41aee0138c 100644 --- a/code/datums/proximity_monitor/fields/timestop.dm +++ b/code/datums/proximity_monitor/fields/timestop.dm @@ -36,7 +36,7 @@ for(var/mob/living/to_check in GLOB.player_list) if(HAS_TRAIT(to_check, TRAIT_TIME_STOP_IMMUNE)) immune[to_check] = TRUE - for(var/mob/living/simple_animal/hostile/guardian/stand in GLOB.parasites) + for(var/mob/living/basic/guardian/stand in GLOB.parasites) if(stand.summoner && HAS_TRAIT(stand.summoner, TRAIT_TIME_STOP_IMMUNE)) //It would only make sense that a person's stand would also be immune. immune[stand] = TRUE if(start) diff --git a/code/datums/ruins/icemoon.dm b/code/datums/ruins/icemoon.dm index cf5b84f8f81636..a903d9444f4bdb 100644 --- a/code/datums/ruins/icemoon.dm +++ b/code/datums/ruins/icemoon.dm @@ -12,6 +12,12 @@ // above ground only +/datum/map_template/ruin/icemoon/gas + name = "Lizard Gas Station" + id = "lizgasruin" + description = "A gas station. It appears to have been recently open and is in mint condition." + suffix = "icemoon_surface_gas.dmm" + /datum/map_template/ruin/icemoon/lust name = "Ruin of Lust" id = "lust" diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm index 4862aa5e2742d2..e95167cf83ed4c 100644 --- a/code/datums/ruins/space.dm +++ b/code/datums/ruins/space.dm @@ -389,6 +389,12 @@ suffix = "whiteshipruin_box.dmm"*/ name = "The Faceoff" description = "What do you get when a meeting of the enemy corporations get crashed?" +/datum/map_template/ruin/space/meatstation + id = "meatderelict" + suffix = "meatderelict.dmm" + name = "Bioresearch Outpost" + description = "A bioresearch experiment gone wrong." + /datum/map_template/ruin/space/ghost_restaurant id = "space_ghost_restaurant.dmm" suffix = "space_ghost_restaurant.dmm" @@ -484,3 +490,28 @@ suffix = "whiteshipruin_box.dmm"*/ suffix = "infested_frigate.dmm" name = "SYN-C Brutus" description = "This wasn't an outbreak, this was a repelled attack." + +/datum/map_template/ruin/space/garbagetruck1 + id = "garbagetruck1" + suffix = "garbagetruck1.dmm" + name = "Decommissioned Garbage Truck NX1" + description = "An NX-760 interstellar transport barge. At the end of their life cycle, they are often filled with trash and launched into unexplored space to become someone else's problem. This one is full of kitchen waste, and rodents." + +/datum/map_template/ruin/space/garbagetruck2 + id = "garbagetruck2" + suffix = "garbagetruck2.dmm" + name = "Decommissioned Garbage Truck NX2" + description = "An NX-760 interstellar transport barge. At the end of their life cycle, they are often filled with trash and launched into unexplored space to become someone else's problem. This one is full of medical waste, and a syndicate agent." + +/datum/map_template/ruin/space/garbagetruck3 + id = "garbagetruck3" + suffix = "garbagetruck3.dmm" + name = "Decommissioned Garbage Truck NX3" + description = "An NX-760 interstellar transport barge. At the end of their life cycle, they are often filled with trash and launched into unexplored space to become someone else's problem. This one is full of industrial garbage, and a russian drug den." + +/datum/map_template/ruin/space/garbagetruck4 + id = "garbagetruck4" + suffix = "garbagetruck4.dmm" + name = "Decommissioned Garbage Truck NX4" + description = "An NX-760 interstellar transport barge. At the end of their life cycle, they are often filled with trash and launched into unexplored space to become someone else's problem. This one is full of commercial trash, and spiders." + diff --git a/code/datums/station_traits/_station_trait.dm b/code/datums/station_traits/_station_trait.dm index 1205673c565f9b..8e8303c0366810 100644 --- a/code/datums/station_traits/_station_trait.dm +++ b/code/datums/station_traits/_station_trait.dm @@ -65,9 +65,9 @@ qdel(src) ///Called by decals if they can be colored, to see if we got some cool colors for them. Only takes the first station trait -/proc/request_station_colors(atom/thing_to_color, pattern = PATTERN_DEFAULT) +/proc/request_station_colors(atom/thing_to_color, pattern) for(var/datum/station_trait/trait in SSstation.station_traits) - var/decal_color = trait.get_decal_color(thing_to_color, pattern) + var/decal_color = trait.get_decal_color(thing_to_color, pattern || PATTERN_DEFAULT) if(decal_color) return decal_color return null diff --git a/code/datums/status_effects/debuffs/fire_stacks.dm b/code/datums/status_effects/debuffs/fire_stacks.dm index 8f52165cdbb125..925273eb1fa8a3 100644 --- a/code/datums/status_effects/debuffs/fire_stacks.dm +++ b/code/datums/status_effects/debuffs/fire_stacks.dm @@ -233,10 +233,10 @@ qdel(moblight) moblight = new moblight_type(owner) - SEND_SIGNAL(owner, COMSIG_LIVING_IGNITED, owner) cache_stacks() update_overlay() update_particles() + SEND_SIGNAL(owner, COMSIG_LIVING_IGNITED, owner) return TRUE /** diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index a2aa81ebb698a0..598b78ca9dfcbf 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -334,6 +334,22 @@ owner.emote("surrender") +///For when you need to make someone be prompted for surrender, but not forever +/datum/status_effect/surrender_timed + id = "surrender_timed" + duration = 30 SECONDS + status_type = STATUS_EFFECT_UNIQUE + alert_type = null + +/datum/status_effect/surrender_timed/on_apply() + owner.apply_status_effect(/datum/status_effect/grouped/surrender, REF(src)) + return ..() + +/datum/status_effect/surrender_timed/on_remove() + owner.remove_status_effect(/datum/status_effect/grouped/surrender, REF(src)) + return ..() + + /* * A status effect used for preventing caltrop message spam * diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index 8ad69bc7daf1f3..342aec50d01276 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -976,6 +976,10 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) /datum/storage/proc/open_storage_attackby_secondary(datum/source, atom/weapon, mob/user) SIGNAL_HANDLER + if(istype(weapon, /obj/item/chameleon)) + var/obj/item/chameleon/chameleon_weapon = weapon + chameleon_weapon.make_copy(source, user) + return open_storage_on_signal(source, user) /// Signal handler to open up the storage when we recieve a signal. diff --git a/code/game/alternate_appearance.dm b/code/game/alternate_appearance.dm index 28b7a4f52479d3..9f3da121b12170 100644 --- a/code/game/alternate_appearance.dm +++ b/code/game/alternate_appearance.dm @@ -149,7 +149,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) /datum/atom_hud/alternate_appearance/basic/blessed_aware/mobShouldSee(mob/M) if(M.mind?.holy_role) return TRUE - if (istype(M, /mob/living/simple_animal/hostile/construct/wraith)) + if (istype(M, /mob/living/basic/construct/wraith)) return TRUE if(isrevenant(M) || IS_WIZARD(M)) return TRUE diff --git a/code/game/area/areas/ruins/icemoon.dm b/code/game/area/areas/ruins/icemoon.dm index f8808903ef4561..8afa3fae2d08f4 100644 --- a/code/game/area/areas/ruins/icemoon.dm +++ b/code/game/area/areas/ruins/icemoon.dm @@ -1,5 +1,8 @@ // Icemoon Ruins +/area/ruin/powered/lizard_gas + name = "\improper Lizard Gas Station" + /area/ruin/unpowered/buried_library name = "\improper Buried Library" diff --git a/code/game/area/areas/ruins/space.dm b/code/game/area/areas/ruins/space.dm index 6050d565c19f0e..f91a7654b5422f 100644 --- a/code/game/area/areas/ruins/space.dm +++ b/code/game/area/areas/ruins/space.dm @@ -599,6 +599,13 @@ /area/ruin/space/has_grav/derelictsulaco name = "\improper Derelict Sulaco" +/area/ruin/space/has_grav/powered/biooutpost + name = "\improper Bioresearch Outpost" + area_flags = UNIQUE_AREA | NOTELEPORT + +/area/ruin/space/has_grav/powered/biooutpost/vault + name = "\improper Bioresearch Outpost Secure Testing" + // Space Ghost Kitchen /area/ruin/space/space_ghost_restaurant name = "\improper Space Ghost Restaurant" @@ -683,3 +690,13 @@ //SYN-C Brutus, derelict frigate /area/ruin/space/has_grav/infested_frigate name = "SYN-C Brutus" + +//garbage trucks +/area/ruin/space/has_grav/garbagetruck + name = "decommissioned garbage truck" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + ambience_index = AMBIENCE_MAINT +/area/ruin/space/has_grav/garbagetruck/foodwaste +/area/ruin/space/has_grav/garbagetruck/medicalwaste +/area/ruin/space/has_grav/garbagetruck/squat +/area/ruin/space/has_grav/garbagetruck/toystore diff --git a/code/game/area/areas/station/security.dm b/code/game/area/areas/station/security.dm index 918cf30ceb8ca1..93629f35628c22 100644 --- a/code/game/area/areas/station/security.dm +++ b/code/game/area/areas/station/security.dm @@ -106,6 +106,10 @@ /area/station/security/execution/education name = "\improper Prisoner Education Chamber" +/area/station/security/mechbay + name = "Security Mechbay" + icon_state = "sec_mechbay" + /* * Security Checkpoints */ @@ -173,9 +177,6 @@ name = "Security Post - Third Floor" icon_state = "checkpoint_3" -/* -* Prison Areas -*/ /area/station/security/prison name = "\improper Prison Wing" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 74bbb3f7cbaad2..b6e3dbb760c5fd 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -699,10 +699,10 @@ if(!(reagent_sigreturn & STOP_GENERIC_REAGENT_EXAMINE)) if(reagents.flags & TRANSPARENT) if(reagents.total_volume) - . += "It contains [round(reagents.total_volume, 0.01)] units of various reagents[user_sees_reagents ? ":" : "."]" + . += "It contains [reagents.total_volume] units of various reagents[user_sees_reagents ? ":" : "."]" if(user_sees_reagents) //Show each individual reagent for detailed examination for(var/datum/reagent/current_reagent as anything in reagents.reagent_list) - . += "• [round(current_reagent.volume, 0.01)] units of [current_reagent.name]" + . += "• [round(current_reagent.volume, CHEMICAL_VOLUME_ROUNDING)] units of [current_reagent.name]" if(reagents.is_reacting) . += span_warning("It is currently reacting!") . += span_notice("The solution's pH is [round(reagents.ph, 0.01)] and has a temperature of [reagents.chem_temp]K.") @@ -2304,12 +2304,12 @@ RecalculateInvisibility() /// Removes the specified invisibility source from the tracker -/atom/proc/RemoveInvisibility(source_id) +/atom/proc/RemoveInvisibility(id) if(!invisibility_sources) return - var/list/priority_data = invisibility_sources[source_id] - invisibility_sources -= source_id + var/list/priority_data = invisibility_sources[id] + invisibility_sources -= id if(length(invisibility_sources) == 0) invisibility_sources = null diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 8d171f29dd83d2..9df3602aabccf2 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -322,7 +322,7 @@ GLOBAL_LIST_EMPTY(dynamic_forced_rulesets) if(length(SScommunications.command_report_footnotes)) . += generate_report_footnote() - print_command_report(., "Central Command Status Summary", announce=FALSE) + print_command_report(., "[command_name()] Status Summary", announce=FALSE) if(greenshift) priority_announce("Thanks to the tireless efforts of our security and intelligence divisions, there are currently no credible threats to [station_name()]. All station construction projects have been authorized. Have a secure shift!", "Security Report", SSstation.announcer.get_rand_report_sound()) else diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 7ad11367fc423e..b551909df419a9 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -61,9 +61,6 @@ if (isnull(creature.client)) // Are they connected? trimmed_list.Remove(creature) continue - if (isnull(creature.mind)) - trimmed_list.Remove(creature) - continue //SKYRAT EDIT ADDITION if(is_banned_from(creature.client.ckey, BAN_ANTAGONIST)) trimmed_list.Remove(creature) @@ -81,6 +78,10 @@ if (is_banned_from(creature.ckey, list(antag_flag_override || antag_flag, ROLE_SYNDICATE))) trimmed_list.Remove(creature) continue + + if (isnull(creature.mind)) + continue + if (restrict_ghost_roles && (creature.mind.assigned_role.title in GLOB.exp_specialmap[EXP_TYPE_SPECIAL])) // Are they playing a ghost role? trimmed_list.Remove(creature) continue @@ -183,7 +184,12 @@ if(makeBody) new_character = generate_ruleset_body(applicant) finish_setup(new_character, i) - notify_ghosts("[applicant.name] has been picked for the ruleset [name]!", source = new_character, action = NOTIFY_ORBIT, header="Something Interesting!") + notify_ghosts( + "[applicant.name] has been picked for the ruleset [name]!", + source = new_character, + action = NOTIFY_ORBIT, + header = "Something Interesting!", + ) /datum/dynamic_ruleset/midround/from_ghosts/proc/generate_ruleset_body(mob/applicant) var/mob/living/carbon/human/new_character = make_body(applicant) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 8319e51b73d053..39dcb81920ae37 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -129,7 +129,7 @@ for(var/dead_dudes_job in reopened_jobs) reopened_job_report_positions = "[reopened_job_report_positions ? "[reopened_job_report_positions]\n":""][dead_dudes_job]" - var/suicide_command_report = "Central Command Human Resources Board
\ + var/suicide_command_report = "[command_name()] Human Resources Board
\ Notice of Personnel Change

\ To personnel management staff aboard [station_name()]:

\ Our medical staff have detected a series of anomalies in the vital sensors \ diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 710b5c7ec09b7d..849192afc5ca38 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -131,7 +131,7 @@ var/subsystem_type = /datum/controller/subsystem/machines var/obj/item/circuitboard/circuit // Circuit to be created and inserted when the machinery is created - var/interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON|INTERACT_MACHINE_SET_MACHINE + var/interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON var/fair_market_price = 69 var/market_verb = "Customer" var/payment_department = ACCOUNT_ENG @@ -1130,9 +1130,9 @@ /obj/machinery/zap_act(power, zap_flags) if(prob(85) && (zap_flags & ZAP_MACHINE_EXPLOSIVE) && !(resistance_flags & INDESTRUCTIBLE)) - explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 4, flame_range = 2, adminlog = FALSE, smoke = FALSE) + explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 4, flame_range = 2, adminlog = TRUE, smoke = FALSE) else if(zap_flags & ZAP_OBJ_DAMAGE) - take_damage(power * 6.25e-7, BURN, ENERGY) + take_damage(power * 2.5e-4, BURN, ENERGY) if(prob(40)) emp_act(EMP_LIGHT) power -= power * 5e-4 diff --git a/code/game/machinery/barsigns.dm b/code/game/machinery/barsigns.dm index ab1abc95e10318..e3b07237a40685 100644 --- a/code/game/machinery/barsigns.dm +++ b/code/game/machinery/barsigns.dm @@ -1,10 +1,7 @@ /obj/machinery/barsign // All Signs are 64 by 32 pixels, they take two tiles name = "bar sign" desc = "A bar sign which has not been initialized, somehow. Complain at a coder!" - //SKYRAT EDIT CHANGE BEGIN - BARSIGNS - //icon = 'icons/obj/machines/barsigns.dmi' - icon = 'modular_skyrat/modules/barsigns/icons/barsigns.dmi' - //SKYRAT EDIT CHANGE END + icon = 'icons/obj/machines/barsigns.dmi' icon_state = "empty" req_access = list(ACCESS_BAR) max_integrity = 500 @@ -40,8 +37,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) update_appearance() /obj/machinery/barsign/update_icon_state() - if(!(machine_stat & (NOPOWER|BROKEN)) && chosen_sign && chosen_sign.icon) - icon_state = chosen_sign.icon + if(!(machine_stat & (NOPOWER|BROKEN)) && chosen_sign && chosen_sign.icon_state) + icon_state = chosen_sign.icon_state else icon_state = "empty" @@ -67,7 +64,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) return if(chosen_sign && chosen_sign.light_mask) - . += emissive_appearance(icon, "[chosen_sign.icon]-light-mask", src) + . += emissive_appearance(icon, "[chosen_sign.icon_state]-light-mask", src) /obj/machinery/barsign/update_appearance(updates=ALL) . = ..() @@ -205,7 +202,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) /// User-visible name of the sign. var/name /// Icon state associated with this sign - var/icon + var/icon_state /// Description shown in the sign's examine text. var/desc /// Hidden from list of selectable options. @@ -225,172 +222,190 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) /datum/barsign/maltesefalcon name = "Maltese Falcon" - icon = "maltesefalcon" + icon_state = "maltesefalcon" desc = "The Maltese Falcon, Space Bar and Grill." neon_color = "#5E8EAC" /datum/barsign/thebark name = "The Bark" - icon = "thebark" + icon_state = "thebark" desc = "Ian's bar of choice." neon_color = "#f7a604" /datum/barsign/harmbaton name = "The Harmbaton" - icon = "theharmbaton" + icon_state = "theharmbaton" desc = "A great dining experience for both security members and assistants." neon_color = "#ff7a4d" /datum/barsign/thesingulo name = "The Singulo" - icon = "thesingulo" + icon_state = "thesingulo" desc = "Where people go that'd rather not be called by their name." neon_color = "#E600DB" /datum/barsign/thedrunkcarp name = "The Drunk Carp" - icon = "thedrunkcarp" + icon_state = "thedrunkcarp" desc = "Don't drink and swim." neon_color = "#a82196" /datum/barsign/scotchservinwill name = "Scotch Servin Willy's" - icon = "scotchservinwill" + icon_state = "scotchservinwill" desc = "Willy sure moved up in the world from clown to bartender." neon_color = "#fee4bf" /datum/barsign/officerbeersky name = "Officer Beersky's" - icon = "officerbeersky" + icon_state = "officerbeersky" desc = "Man eat a dong, these drinks are great." neon_color = "#16C76B" /datum/barsign/thecavern name = "The Cavern" - icon = "thecavern" + icon_state = "thecavern" desc = "Fine drinks while listening to some fine tunes." neon_color = "#0fe500" /datum/barsign/theouterspess name = "The Outer Spess" - icon = "theouterspess" + icon_state = "theouterspess" desc = "This bar isn't actually located in outer space." neon_color = "#30f3cc" /datum/barsign/slipperyshots name = "Slippery Shots" - icon = "slipperyshots" + icon_state = "slipperyshots" desc = "Slippery slope to drunkeness with our shots!" neon_color = "#70DF00" /datum/barsign/thegreytide name = "The Grey Tide" - icon = "thegreytide" + icon_state = "thegreytide" desc = "Abandon your toolboxing ways and enjoy a lazy beer!" neon_color = "#00F4D6" /datum/barsign/honkednloaded name = "Honked 'n' Loaded" - icon = "honkednloaded" + icon_state = "honkednloaded" desc = "Honk." neon_color = "#FF998A" /datum/barsign/thenest name = "The Nest" - icon = "thenest" + icon_state = "thenest" desc = "A good place to retire for a drink after a long night of crime fighting." neon_color = "#4d6796" /datum/barsign/thecoderbus name = "The Coderbus" - icon = "thecoderbus" + icon_state = "thecoderbus" desc = "A very controversial bar known for its wide variety of constantly-changing drinks." neon_color = "#ffffff" /datum/barsign/theadminbus name = "The Adminbus" - icon = "theadminbus" + icon_state = "theadminbus" desc = "An establishment visited mainly by space-judges. It isn't bombed nearly as much as court hearings." neon_color = "#ffffff" /datum/barsign/oldcockinn name = "The Old Cock Inn" - icon = "oldcockinn" + icon_state = "oldcockinn" desc = "Something about this sign fills you with despair." neon_color = "#a4352b" /datum/barsign/thewretchedhive name = "The Wretched Hive" - icon = "thewretchedhive" + icon_state = "thewretchedhive" desc = "Legally obligated to instruct you to check your drinks for acid before consumption." neon_color = "#26b000" /datum/barsign/robustacafe name = "The Robusta Cafe" - icon = "robustacafe" + icon_state = "robustacafe" desc = "Holder of the 'Most Lethal Barfights' record 5 years uncontested." neon_color = "#c45f7a" /datum/barsign/emergencyrumparty name = "The Emergency Rum Party" - icon = "emergencyrumparty" + icon_state = "emergencyrumparty" desc = "Recently relicensed after a long closure." neon_color = "#f90011" /datum/barsign/combocafe name = "The Combo Cafe" - icon = "combocafe" + icon_state = "combocafe" desc = "Renowned system-wide for their utterly uncreative drink combinations." neon_color = "#33ca40" /datum/barsign/vladssaladbar name = "Vlad's Salad Bar" - icon = "vladssaladbar" + icon_state = "vladssaladbar" desc = "Under new management. Vlad was always a bit too trigger happy with that shotgun." neon_color = "#306900" /datum/barsign/theshaken name = "The Shaken" - icon = "theshaken" + icon_state = "theshaken" desc = "This establishment does not serve stirred drinks." neon_color = "#dcd884" /datum/barsign/thealenath name = "The Ale' Nath" - icon = "thealenath" + icon_state = "thealenath" desc = "All right, buddy. I think you've had EI NATH. Time to get a cab." neon_color = "#ed0000" /datum/barsign/thealohasnackbar name = "The Aloha Snackbar" - icon = "alohasnackbar" + icon_state = "alohasnackbar" desc = "A tasteful, inoffensive tiki bar sign." neon_color = "" /datum/barsign/thenet name = "The Net" - icon = "thenet" + icon_state = "thenet" desc = "You just seem to get caught up in it for hours." neon_color = "#0e8a00" /datum/barsign/maidcafe name = "Maid Cafe" - icon = "maidcafe" + icon_state = "maidcafe" desc = "Welcome back, master!" neon_color = "#ff0051" /datum/barsign/the_lightbulb name = "The Lightbulb" - icon = "the_lightbulb" + icon_state = "the_lightbulb" desc = "A cafe popular among moths and moffs. Once shut down for a week after the bartender used mothballs to protect her spare uniforms." neon_color = "#faff82" /datum/barsign/goose name = "The Loose Goose" - icon = "goose" + icon_state = "goose" desc = "Drink till you puke and/or break the laws of reality!" neon_color = "#00cc33" +/datum/barsign/maltroach + name = "Maltroach" + icon_state = "maltroach" + desc = "Mothroaches politely greet you into the bar, or are they greeting eachother?" + neon_color = "#649e8a" + +/datum/barsign/rock_bottom + name = "Rock Bottom" + icon_state = "rock-bottom" + desc = "When it feels like you're stuck in a pit, might as well have a drink." + neon_color = "#aa2811" + +/datum/barsign/orangejuice + name = "Oranges' Juicery" + icon_state = "orangejuice" + desc = "For those who wish to be optimally tactful to the non-alcoholic population." + neon_color = COLOR_ORANGE + // Hidden signs list below this point /datum/barsign/hiddensigns @@ -398,19 +413,19 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) /datum/barsign/hiddensigns/empbarsign name = "EMP'd" - icon = "empbarsign" + icon_state = "empbarsign" desc = "Something has gone very wrong." rename_area = FALSE /datum/barsign/hiddensigns/syndibarsign name = "Syndi Cat" - icon = "syndibarsign" + icon_state = "syndibarsign" desc = "Syndicate or die." neon_color = "#ff0000" /datum/barsign/hiddensigns/signoff name = "Off" - icon = "empty" + icon_state = "empty" desc = "This sign doesn't seem to be on." rename_area = FALSE light_mask = FALSE @@ -420,48 +435,3 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) req_access = null MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign/all_access, 32) - - -// Tannhauser Gate Station Bar Signs - -/datum/barsign/orcacomand - name = "Orca Dive Bar" - icon = "orcacomand" - desc = "This sign is of a Killer Whale falling from a great hight with a potted plant. The whale seems to have the rank of Comander for some reason." - -/datum/barsign/zestbar - name = "Best Zest Bar" - icon = "zestbar" - desc = "Be sure to ask your bartender about the best panda zest, Yes the best is blue and we will not tell you." - -/datum/barsign/losttime - name = "Lost Time Bar" - icon = "losttime" - desc = "Your not sure how long you have realy spent in this place." - -/datum/barsign/collective - name = "Cherdenko Collective" - icon = "collective" - desc = "With all the ham you think this should be on the door to the meat locker" - -/datum/barsign/haurbus - name = "Man Pool" - icon = "haurbus" - desc = "Came as you were, Leave as something New!! Warning, Nanotrassen is not responsible for any TF on Premisses. TF is not guarenteeed with every libation. Certain terms and restrictions may apply" - -//CIT Ported bar Signs Go Below Here - -/datum/barsign/cybersylph - name = "Cyber Sylph's" - icon = "cybersylph" - desc = "A cafe renowed for its out-of-boundaries futuristic insignia." - -/datum/barsign/meow_mix - name = "Meow Mix" - icon = "Meow Mix" - desc = "No, we don't serve catnip, officer!" - -/datum/barsign/the_hive - name = "The Hive" - icon = "thehive" - desc = "Comb in for some sweet drinks! Not known for serving any sappy drink." diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index 042f442fa332e6..246c4b0e4a851c 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -6,7 +6,7 @@ max_integrity = 200 integrity_failure = 0.5 armor_type = /datum/armor/machinery_computer - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE|INTERACT_MACHINE_REQUIRES_LITERACY + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_REQUIRES_LITERACY /// How bright we are when turned on. var/brightness_on = 1 /// Icon_state of the keyboard overlay. diff --git a/code/game/machinery/computer/arcade/arcade.dm b/code/game/machinery/computer/arcade/arcade.dm index 58a7280e8643e9..9ff935a91653f4 100644 --- a/code/game/machinery/computer/arcade/arcade.dm +++ b/code/game/machinery/computer/arcade/arcade.dm @@ -77,7 +77,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( icon_keyboard = null icon_screen = "invaders" light_color = LIGHT_COLOR_GREEN - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE // we don't need to be literate to play video games fam + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON var/list/prize_override /obj/machinery/computer/arcade/proc/Reset() @@ -157,6 +157,8 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( icon_state = "arcade" circuit = /obj/item/circuitboard/computer/arcade/battle + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE // we don't need to be literate to play video games fam + var/enemy_name = "Space Villain" ///Enemy health/attack points var/enemy_hp = 100 diff --git a/code/game/machinery/computer/arena.dm b/code/game/machinery/computer/arena.dm index 39b39af197b61f..1ba000fa5da5a3 100644 --- a/code/game/machinery/computer/arena.dm +++ b/code/game/machinery/computer/arena.dm @@ -21,6 +21,9 @@ /// Controller for admin event arenas /obj/machinery/computer/arena name = "arena controller" + + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE|INTERACT_MACHINE_REQUIRES_LITERACY + /// Arena ID var/arena_id = ARENA_DEFAULT_ID /// Enables/disables spawning diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 6bc5c6f60d2fca..a1a1fe0ada2a96 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -19,7 +19,7 @@ /// All the plane masters that need to be applied. var/atom/movable/screen/background/cam_background - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE|INTERACT_MACHINE_REQUIRES_SIGHT + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_REQUIRES_SIGHT /obj/machinery/computer/security/Initialize(mapload) . = ..() diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index 870f64dd57584a..4750feb3b9b9df 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -24,7 +24,7 @@ ///Should we supress any view changes? var/should_supress_view_changes = TRUE - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_SET_MACHINE | INTERACT_MACHINE_REQUIRES_SIGHT + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_REQUIRES_SIGHT /obj/machinery/computer/camera_advanced/Initialize(mapload) . = ..() @@ -76,12 +76,10 @@ /obj/machinery/computer/camera_advanced/remove_eye_control(mob/living/user) if(!user) return - for(var/V in actions) - var/datum/action/A = V - A.Remove(user) - for(var/V in eyeobj.visibleCameraChunks) - var/datum/camerachunk/C = V - C.remove(eyeobj) + for(var/datum/action/actions_removed as anything in actions) + actions_removed.Remove(user) + for(var/datum/camerachunk/camerachunks_gone as anything in eyeobj.visibleCameraChunks) + camerachunks_gone.remove(eyeobj) if(user.client) user.reset_perspective(null) if(eyeobj.visible_icon && user.client) @@ -91,12 +89,12 @@ eyeobj.eye_user = null user.remote_control = null current_user = null - user.unset_machine() + unset_machine(user) playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE) /obj/machinery/computer/camera_advanced/check_eye(mob/user) if(!can_use(user) || (issilicon(user) && !user.has_unlimited_silicon_privilege)) - user.unset_machine() + unset_machine(user) /obj/machinery/computer/camera_advanced/Destroy() if(eyeobj) @@ -105,7 +103,7 @@ current_user = null return ..() -/obj/machinery/computer/camera_advanced/on_unset_machine(mob/M) +/obj/machinery/computer/camera_advanced/proc/unset_machine(mob/M) if(M == current_user) remove_eye_control(M) @@ -155,7 +153,7 @@ give_eye_control(L) eyeobj.setLoc(camera_location) else - user.unset_machine() + unset_machine(user) else give_eye_control(L) eyeobj.setLoc(eyeobj.loc) diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index 6502ecbf530d95..c3510afce731d8 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -400,7 +400,6 @@ . = TRUE add_fingerprint(usr) - usr.set_machine(src) switch(action) // Connect this DNA Console to a nearby DNA Scanner diff --git a/code/game/machinery/computer/launchpad_control.dm b/code/game/machinery/computer/launchpad_control.dm index 5590297c54a3cb..13f54f27980911 100644 --- a/code/game/machinery/computer/launchpad_control.dm +++ b/code/game/machinery/computer/launchpad_control.dm @@ -79,20 +79,6 @@ return FALSE return TRUE -/// Performs checks on whether or not the launch pad can be used. -/// Returns `null` if there are no errors, otherwise will return the error string. -/obj/machinery/computer/launchpad/proc/teleport_checks(obj/machinery/launchpad/pad) - if(QDELETED(pad)) - return "ERROR: Launchpad not responding. Check launchpad integrity." - if(!pad.isAvailable()) - return "ERROR: Launchpad not operative. Make sure the launchpad is ready and powered." - if(pad.teleporting) - return "ERROR: Launchpad busy." - var/turf/pad_turf = get_turf(pad) - if(pad_turf && is_centcom_level(pad_turf.z)) - return "ERROR: Launchpad not operative. Heavy area shielding makes teleporting impossible." - return null - /obj/machinery/computer/launchpad/proc/get_pad(number) var/obj/machinery/launchpad/pad = launchpads[number] return pad @@ -168,7 +154,7 @@ selected_id = null . = TRUE if("launch") - var/checks = teleport_checks(current_pad) + var/checks = current_pad.teleport_checks() if(isnull(checks)) current_pad.doteleport(usr, TRUE) else @@ -176,7 +162,7 @@ . = TRUE if("pull") - var/checks = teleport_checks(current_pad) + var/checks = current_pad.teleport_checks() if(isnull(checks)) current_pad.doteleport(usr, FALSE) else diff --git a/code/game/machinery/computer/orders/order_computer/mining_order.dm b/code/game/machinery/computer/orders/order_computer/mining_order.dm index c680974e4c1a4b..2ba9e00d9f5fa9 100644 --- a/code/game/machinery/computer/orders/order_computer/mining_order.dm +++ b/code/game/machinery/computer/orders/order_computer/mining_order.dm @@ -41,7 +41,7 @@ cost = get_total_cost(), \ contains = things_to_order, ) - var/datum/supply_order/new_order = new( + var/datum/supply_order/disposable/new_order = new( pack = mining_pack, orderer = purchaser, orderer_rank = "Mining Vendor", diff --git a/code/game/machinery/computer/prisoner/_prisoner.dm b/code/game/machinery/computer/prisoner/_prisoner.dm index 05bb4042c8be41..970b5f4f9be265 100644 --- a/code/game/machinery/computer/prisoner/_prisoner.dm +++ b/code/game/machinery/computer/prisoner/_prisoner.dm @@ -1,4 +1,5 @@ /obj/machinery/computer/prisoner + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE|INTERACT_MACHINE_REQUIRES_LITERACY var/obj/item/card/id/advanced/prisoner/contained_id /obj/machinery/computer/prisoner/Destroy() diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index b38ecb7c60fd7d..59ec1a35139c32 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -270,6 +270,7 @@ /obj/machinery/door/firedoor/proc/adjacent_change(turf/changed, path, list/new_baseturfs, flags, list/post_change_callbacks) SIGNAL_HANDLER post_change_callbacks += CALLBACK(src, PROC_REF(CalculateAffectingAreas)) + post_change_callbacks += CALLBACK(src, PROC_REF(process_results), changed) //check the atmosphere of the changed turf so we don't hold onto alarm if a wall is built /obj/machinery/door/firedoor/proc/check_atmos(turf/checked_turf) var/datum/gas_mixture/environment = checked_turf.return_air() diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm index 0b66fd391b1604..1e2287a04923a2 100644 --- a/code/game/machinery/embedded_controller/access_controller.dm +++ b/code/game/machinery/embedded_controller/access_controller.dm @@ -106,6 +106,7 @@ base_icon_state = "access_control" name = "access console" desc = "A small console that can cycle opening between two airlocks." + interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON|INTERACT_MACHINE_SET_MACHINE var/obj/machinery/door/airlock/interiorAirlock var/obj/machinery/door/airlock/exteriorAirlock var/idInterior diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index 7c73d2b6f65676..5b1c0e35a844a4 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -20,13 +20,10 @@ icon = 'icons/obj/medical/iv_drip.dmi' icon_state = "iv_drip" base_icon_state = "iv_drip" - ///icon_state for the reagent fill overlay - var/fill_icon_state = "reagent" - ///The thresholds used to determine the reagent fill icon - var/list/fill_icon_thresholds = list(0,10,25,50,75,80,90) anchored = FALSE mouse_drag_pointer = MOUSE_ACTIVE_POINTER use_power = NO_POWER_USE + ///What are we sticking our needle in? var/atom/attached ///Are we donating or injecting? @@ -41,16 +38,8 @@ var/internal_list_reagents ///How many reagents can we hold? var/internal_volume_maximum = 100 - ///Typecache of containers we accept - var/static/list/drip_containers = typecacheof(list( - /obj/item/reagent_containers/blood, - /obj/item/reagent_containers/cup, - /obj/item/reagent_containers/chem_pack, - )) // If the blood draining tab should be greyed out var/inject_only = FALSE - // Whether the injection maintained by the plumbing network - var/inject_from_plumbing = FALSE /obj/machinery/iv_drip/Initialize(mapload) . = ..() @@ -82,9 +71,6 @@ else if(!inject_only) context[SCREENTIP_CONTEXT_RMB] = "Change direction" - if(istype(src, /obj/machinery/iv_drip/plumbing)) - return CONTEXTUAL_SCREENTIP_SET - if(transfer_rate > MIN_IV_TRANSFER_RATE) context[SCREENTIP_CONTEXT_ALT_LMB] = "Set flow to min" else @@ -92,38 +78,38 @@ return CONTEXTUAL_SCREENTIP_SET -/obj/machinery/iv_drip/ui_data(mob/user) - var/list/data = list() +/obj/machinery/iv_drip/ui_static_data(mob/user) + . = list() + .["transferStep"] = IV_TRANSFER_RATE_STEP + .["maxTransferRate"] = MAX_IV_TRANSFER_RATE + .["minTransferRate"] = MIN_IV_TRANSFER_RATE - data["hasInternalStorage"] = use_internal_storage - data["hasContainer"] = reagent_container ? TRUE : FALSE - data["canRemoveContainer"] = !use_internal_storage +/obj/machinery/iv_drip/ui_data(mob/user) + . = list() - data["mode"] = mode == IV_INJECTING ? TRUE : FALSE - data["canDraw"] = inject_only || (attached && !isliving(attached)) ? FALSE : TRUE - data["injectFromPlumbing"] = inject_from_plumbing + .["hasInternalStorage"] = use_internal_storage + .["hasContainer"] = reagent_container ? TRUE : FALSE + .["canRemoveContainer"] = !use_internal_storage - data["canAdjustTransfer"] = inject_from_plumbing && mode == IV_INJECTING ? FALSE : TRUE - data["transferRate"] = transfer_rate - data["transferStep"] = IV_TRANSFER_RATE_STEP - data["maxTransferRate"] = MAX_IV_TRANSFER_RATE - data["minTransferRate"] = MIN_IV_TRANSFER_RATE + .["mode"] = mode == IV_INJECTING ? TRUE : FALSE + .["canDraw"] = inject_only || (attached && !isliving(attached)) ? FALSE : TRUE + .["transferRate"] = transfer_rate - data["hasObjectAttached"] = attached ? TRUE : FALSE + .["hasObjectAttached"] = attached ? TRUE : FALSE if(attached) - data["objectName"] = attached.name + .["objectName"] = attached.name var/datum/reagents/drip_reagents = get_reagents() if(drip_reagents) - data["containerCurrentVolume"] = round(drip_reagents.total_volume, IV_TRANSFER_RATE_STEP) - data["containerMaxVolume"] = drip_reagents.maximum_volume - data["containerReagentColor"] = mix_color_from_reagents(drip_reagents.reagent_list) - - return data + .["containerCurrentVolume"] = round(drip_reagents.total_volume, IV_TRANSFER_RATE_STEP) + .["containerMaxVolume"] = drip_reagents.maximum_volume + .["containerReagentColor"] = mix_color_from_reagents(drip_reagents.reagent_list) /obj/machinery/iv_drip/ui_act(action, params) - if(..()) - return TRUE + . = ..() + if(.) + return + switch(action) if("changeMode") toggle_mode() @@ -140,18 +126,9 @@ /// Sets the transfer rate to the provided value /obj/machinery/iv_drip/proc/set_transfer_rate(new_rate) - if(inject_from_plumbing && mode == IV_INJECTING) - return transfer_rate = round(clamp(new_rate, MIN_IV_TRANSFER_RATE, MAX_IV_TRANSFER_RATE), IV_TRANSFER_RATE_STEP) update_appearance(UPDATE_ICON) -/// Toggles transfer rate between min and max rate -/obj/machinery/iv_drip/proc/toggle_transfer_rate() - if(transfer_rate > MIN_IV_TRANSFER_RATE) - set_transfer_rate(MIN_IV_TRANSFER_RATE) - else - set_transfer_rate(MAX_IV_TRANSFER_RATE) - /obj/machinery/iv_drip/update_icon_state() if(transfer_rate > 0 && attached) icon_state = "[base_icon_state]_[mode ? "injecting" : "donating"]" @@ -170,12 +147,16 @@ if(!container_reagents) return + //The thresholds used to determine the reagent fill icon + var/static/list/fill_icon_thresholds = list(0, 10, 25, 50, 75, 80, 90) + var/threshold = null for(var/i in 1 to fill_icon_thresholds.len) if(ROUND_UP(100 * container_reagents.total_volume / container_reagents.maximum_volume) >= fill_icon_thresholds[i]) threshold = i + if(threshold) - var/fill_name = "[fill_icon_state][fill_icon_thresholds[threshold]]" + var/fill_name = "reagent[fill_icon_thresholds[threshold]]" var/mutable_appearance/filling = mutable_appearance(icon, fill_name) filling.color = mix_color_from_reagents(container_reagents.reagent_list) . += filling @@ -204,6 +185,13 @@ if(use_internal_storage) return ..() + //Typecache of containers we accept + var/static/list/drip_containers = typecacheof(list( + /obj/item/reagent_containers/blood, + /obj/item/reagent_containers/cup, + /obj/item/reagent_containers/chem_pack, + )) + if(is_type_in_typecache(W, drip_containers) || IS_EDIBLE(W)) if(reagent_container) to_chat(user, span_warning("[reagent_container] is already loaded on [src]!")) @@ -223,14 +211,11 @@ /obj/machinery/iv_drip/proc/can_use_alt_click(mob/user) if(!can_interact(user)) return FALSE - if(istype(src, /obj/machinery/iv_drip/plumbing)) // AltClick is used for rotation there - return FALSE - return TRUE /obj/machinery/iv_drip/AltClick(mob/user) if(!can_use_alt_click(user)) return ..() - toggle_transfer_rate() + set_transfer_rate(transfer_rate > MIN_IV_TRANSFER_RATE ? MIN_IV_TRANSFER_RATE : MAX_IV_TRANSFER_RATE) /obj/machinery/iv_drip/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) @@ -258,7 +243,7 @@ if(!drip_reagents) return PROCESS_KILL - if(transfer_rate == 0) + if(!transfer_rate) return // Give reagents @@ -364,9 +349,7 @@ if(!isliving(usr)) to_chat(usr, span_warning("You can't do that!")) return - if(!usr.can_perform_action(src)) - return - if(usr.incapacitated()) + if(!usr.can_perform_action(src) || usr.incapacitated()) return if(inject_only) mode = IV_INJECTING @@ -423,29 +406,6 @@ AddElement(/datum/element/update_icon_blocker) . = ..() -///modified IV that can be anchored and takes plumbing in- and output -/obj/machinery/iv_drip/plumbing - name = "automated IV drip" - desc = "A modified IV drip with plumbing connects. Reagents received from the connect are injected directly into their bloodstream, blood that is drawn goes to the internal storage and then into the ducting." - icon_state = "plumb" - base_icon_state = "plumb" - density = TRUE - use_internal_storage = TRUE - inject_from_plumbing = TRUE - -/obj/machinery/iv_drip/plumbing/Initialize(mapload) - . = ..() - AddComponent(/datum/component/plumbing/iv_drip, anchored) - AddComponent(/datum/component/simple_rotation) - -/obj/machinery/iv_drip/plumbing/wrench_act(mob/living/user, obj/item/tool) - . = ..() - default_unfasten_wrench(user, tool) - return TOOL_ACT_TOOLTYPE_SUCCESS - -/obj/machinery/iv_drip/plumbing/deconstruct(disassembled = TRUE) - qdel(src) - /atom/movable/screen/alert/iv_connected name = "IV Connected" desc = "You have an IV connected to your arm. Remember to remove it or drag the IV stand with you before moving, or else it will rip out!" diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm index 5400cccf2f2e9a..910f3802bfd6ba 100644 --- a/code/game/machinery/launch_pad.dm +++ b/code/game/machinery/launch_pad.dm @@ -8,29 +8,31 @@ active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2.5 hud_possible = list(DIAG_LAUNCHPAD_HUD) circuit = /obj/item/circuitboard/machine/launchpad + /// The beam icon var/icon_teleport = "lpad-beam" - var/stationary = TRUE //to prevent briefcase pad deconstruction and such + /// To prevent briefcase pad deconstruction and such + var/stationary = TRUE + /// What to name the launchpad in the console var/display_name = "Launchpad" + /// The speed of the teleportation var/teleport_speed = 35 + /// Max range of the launchpad var/range = 10 - var/teleporting = FALSE //if it's in the process of teleporting + /// If it's in the process of teleporting + var/teleporting = FALSE + /// The power efficiency of the launchpad var/power_efficiency = 1 + /// Current x target var/x_offset = 0 + /// Current y target var/y_offset = 0 + /// The icon to use for the indicator var/indicator_icon = "launchpad_target" /// Determines if the bluespace launchpad is blatantly obvious on teleportation. var/hidden = FALSE /// The beam on teleportation var/teleport_beam = "sm_arc_supercharged" -/obj/machinery/launchpad/RefreshParts() - . = ..() - var/max_range_multiplier = 0 - for(var/datum/stock_part/servo/servo in component_parts) - max_range_multiplier += servo.tier - range = initial(range) - range *= max_range_multiplier - /obj/machinery/launchpad/Initialize(mapload) . = ..() prepare_huds() @@ -39,23 +41,19 @@ update_hud() +/obj/machinery/launchpad/RefreshParts() + . = ..() + var/max_range_multiplier = 0 + for(var/datum/stock_part/servo/servo in component_parts) + max_range_multiplier += servo.tier + range = initial(range) + range *= max_range_multiplier + /obj/machinery/launchpad/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) if(same_z_layer && !QDELETED(src)) update_hud() return ..() -/obj/machinery/launchpad/proc/update_hud() - var/image/holder = hud_list[DIAG_LAUNCHPAD_HUD] - var/mutable_appearance/target = mutable_appearance('icons/effects/effects.dmi', "launchpad_target", ABOVE_OPEN_TURF_LAYER, src, GAME_PLANE) - holder.appearance = target - - update_indicator() - - if(stationary) - AddComponent(/datum/component/usb_port, list( - /obj/item/circuit_component/bluespace_launchpad, - )) - /obj/machinery/launchpad/Destroy() for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diag_hud.remove_atom_from_hud(src) @@ -66,25 +64,24 @@ if(in_range(user, src) || isobserver(user)) . += span_notice("The status display reads: Maximum range: [range] units.") -/obj/machinery/launchpad/attackby(obj/item/I, mob/user, params) - if(stationary) - if(default_deconstruction_screwdriver(user, "lpad-idle-open", "lpad-idle", I)) - update_indicator() - return +/obj/machinery/launchpad/attackby(obj/item/weapon, mob/user, params) + if(!stationary) + return ..() - if(panel_open) - if(I.tool_behaviour == TOOL_MULTITOOL) - if(!multitool_check_buffer(user, I)) - return - var/obj/item/multitool/M = I - M.set_buffer(src) - balloon_alert(user, "saved to multitool buffer") - return 1 + if(default_deconstruction_screwdriver(user, "lpad-idle-open", "lpad-idle", weapon)) + update_indicator() + return - if(default_deconstruction_crowbar(I)) + if(panel_open && weapon.tool_behaviour == TOOL_MULTITOOL) + if(!multitool_check_buffer(user, weapon)) return + var/obj/item/multitool/multi = weapon + multi.set_buffer(src) + balloon_alert(user, "saved to buffer") + return TRUE - return ..() + if(default_deconstruction_crowbar(weapon)) + return /obj/machinery/launchpad/attack_ghost(mob/dead/observer/ghost) . = ..() @@ -95,17 +92,30 @@ var/turf/target = locate(target_x, target_y, z) ghost.forceMove(target) -/obj/machinery/launchpad/proc/isAvailable() - if(machine_stat & NOPOWER) - return FALSE - if(panel_open) +/// Updates diagnostic huds +/obj/machinery/launchpad/proc/update_hud() + var/image/holder = hud_list[DIAG_LAUNCHPAD_HUD] + var/mutable_appearance/target = mutable_appearance('icons/effects/effects.dmi', "launchpad_target", ABOVE_OPEN_TURF_LAYER, src, GAME_PLANE) + holder.appearance = target + + update_indicator() + + if(stationary) + AddComponent(/datum/component/usb_port, list( + /obj/item/circuit_component/bluespace_launchpad, + )) + +/// Whether this launchpad can send or receive. +/obj/machinery/launchpad/proc/is_available() + if(QDELETED(src) || !is_operational || panel_open) return FALSE return TRUE +/// Updates the indicator icon. /obj/machinery/launchpad/proc/update_indicator() var/image/holder = hud_list[DIAG_LAUNCHPAD_HUD] var/turf/target_turf - if(isAvailable()) + if(is_available()) target_turf = locate(x + x_offset, y + y_offset, z) if(target_turf) holder.icon_state = indicator_icon @@ -113,6 +123,7 @@ else holder.icon_state = null +/// Sets the offset of the launchpad. /obj/machinery/launchpad/proc/set_offset(x, y) if(teleporting) return @@ -132,15 +143,18 @@ . = ..() animate(src, alpha = 0, flags = ANIMATION_PARALLEL, time = BEAM_FADE_TIME) - +/// Checks if the launchpad can teleport. /obj/machinery/launchpad/proc/teleport_checks() - if(!isAvailable()) + if(!is_available()) return "ERROR: Launchpad not operative. Make sure the launchpad is ready and powered." + if(teleporting) return "ERROR: Launchpad busy." - var/turf/pad_turf = get_turf(src) - if(pad_turf && is_centcom_level(pad_turf.z)) + + var/area/surrounding = get_area(src) + if(is_centcom_level(z) || istype(surrounding, /area/shuttle)) return "ERROR: Launchpad not operative. Heavy area shielding makes teleporting impossible." + return null /// Performs the teleport. @@ -179,7 +193,7 @@ indicator_icon = "launchpad_target" update_indicator() - if(QDELETED(src) || !isAvailable()) + if(!is_available()) return teleporting = FALSE @@ -277,7 +291,7 @@ briefcase = null return ..() -/obj/machinery/launchpad/briefcase/isAvailable() +/obj/machinery/launchpad/briefcase/is_available() if(closed) return FALSE if(panel_open) diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index c9b220bb0cdc2d..6e16beb494ef2d 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -12,6 +12,8 @@ var/area/area = null ///Range of the light emitted when powered, but off var/light_on_range = 1 + /// Should this lightswitch automatically rename itself to match the area it's in? + var/autoname = TRUE MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light_switch, 26) @@ -29,12 +31,22 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light_switch, 26) area = GLOB.areas_by_type[area] if(!area) area = get_area(src) - if(!name) + if(autoname) name = "light switch ([area.name])" find_and_hang_on_wall(custom_drop_callback = CALLBACK(src, PROC_REF(deconstruct), TRUE)) - + register_context() update_appearance() +/obj/machinery/light_switch/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(isnull(held_item)) + context[SCREENTIP_CONTEXT_LMB] = area.lightswitch ? "Flick off" : "Flick on" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour != TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_RMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET + return . + /obj/machinery/light_switch/update_appearance(updates=ALL) . = ..() luminosity = (machine_stat & NOPOWER) ? 0 : 1 @@ -62,6 +74,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light_switch, 26) . = ..() set_lights(!area.lightswitch) +/obj/machinery/light_switch/attackby_secondary(obj/item/weapon, mob/user, params) + if(weapon.tool_behaviour == TOOL_SCREWDRIVER) + to_chat(user, "You pop \the [src] off the wall.") + deconstruct() + return COMPONENT_CANCEL_ATTACK_CHAIN + return ..() + /obj/machinery/light_switch/proc/set_lights(status) if(area.lightswitch == status) return diff --git a/code/game/machinery/modular_shield.dm b/code/game/machinery/modular_shield.dm index 3f08760166aec2..f4e15cfa878135 100644 --- a/code/game/machinery/modular_shield.dm +++ b/code/game/machinery/modular_shield.dm @@ -1,6 +1,6 @@ /obj/machinery/modular_shield_generator name = "Modular Shield Generator" - desc = "A forcefield generator, it seems more stationary than its cousins." + desc = "A forcefield generator, it seems more stationary than its cousins. It cant handle G-force and will require frequent reboots when built on mobile craft." icon = 'icons/obj/machines/modular_shield_generator.dmi' icon_state = "gen_recovering_closed" density = TRUE @@ -162,6 +162,10 @@ return activate_shields() +/obj/machinery/modular_shield_generator/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock) + . = ..() + if(active) + deactivate_shields() ///generates the forcefield based on the given radius and calls calculate_regen to update the regen value accordingly /obj/machinery/modular_shield_generator/proc/activate_shields() @@ -438,17 +442,21 @@ /obj/machinery/modular_shield/module/wrench_act(mob/living/user, obj/item/tool) . = ..() - if(default_change_direction_wrench(user, tool)) - if(shield_generator) - LAZYREMOVE(shield_generator.connected_modules, (src)) - shield_generator.calculate_boost() - shield_generator = null - update_icon_state() - if(connected_node) - LAZYREMOVE(connected_node.connected_through_us, (src)) - connected_node = null - connected_turf = get_step(loc, dir) - return TRUE + if(!default_change_direction_wrench(user, tool)) + return FALSE + + if(shield_generator) + LAZYREMOVE(shield_generator.connected_modules, (src)) + shield_generator.calculate_boost() + shield_generator = null + update_icon_state() + + if(connected_node) + LAZYREMOVE(connected_node.connected_through_us, (src)) + connected_node = null + + connected_turf = get_step(loc, dir) + return TRUE /obj/machinery/modular_shield/module/crowbar_act(mob/living/user, obj/item/tool) . = ..() @@ -514,16 +522,26 @@ return icon_state = "node_on_[panel_open ? "open" : "closed"]" -/obj/machinery/modular_shield/module/node/setDir(new_dir) - . = ..() + +/obj/machinery/modular_shield/module/node/wrench_act(mob/living/user, obj/item/tool) + + if(!default_change_direction_wrench(user, tool)) + return FALSE disconnect_connected_through_us() - if(isnull(shield_generator)) - return - LAZYREMOVE(shield_generator.connected_modules, (src)) - shield_generator.calculate_boost() - shield_generator = null - update_icon_state() + + if(shield_generator) + LAZYREMOVE(shield_generator.connected_modules, (src)) + shield_generator.calculate_boost() + shield_generator = null + update_icon_state() + + if(connected_node) + LAZYREMOVE(connected_node.connected_through_us, (src)) + connected_node = null + + connected_turf = get_step(loc, dir) + return TRUE //after trying to connect to a machine infront of us, we will try to link anything connected to us to a generator /obj/machinery/modular_shield/module/node/try_connect(user) diff --git a/code/game/machinery/newscaster/newscaster_machine.dm b/code/game/machinery/newscaster/newscaster_machine.dm index 1ae08c066f043e..fc908a98840bc6 100644 --- a/code/game/machinery/newscaster/newscaster_machine.dm +++ b/code/game/machinery/newscaster/newscaster_machine.dm @@ -12,7 +12,7 @@ armor_type = /datum/armor/machinery_newscaster max_integrity = 200 integrity_failure = 0.25 - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE|INTERACT_MACHINE_REQUIRES_LITERACY + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_REQUIRES_LITERACY ///Reference to the currently logged in user. var/datum/bank_account/current_user ///Name of the logged in user. diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index cf4e4d1e7e709f..11f4bb1dd5567d 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -326,7 +326,7 @@ DEFINE_BITFIELD(turret_flags, list( //This code handles moving the turret around. After all, it's a portable turret! if(!anchored && !isinspace()) set_anchored(TRUE) - SetInvisibility(INVISIBILITY_MAXIMUM, id=type) + RemoveInvisibility(id=type) update_appearance() to_chat(user, span_notice("You secure the exterior bolts on the turret.")) if(has_cover) @@ -336,7 +336,7 @@ DEFINE_BITFIELD(turret_flags, list( set_anchored(FALSE) to_chat(user, span_notice("You unsecure the exterior bolts on the turret.")) power_change() - RemoveInvisibility(type) + SetInvisibility(INVISIBILITY_NONE, id=type) qdel(cover) //deletes the cover, and the turret instance itself becomes its own cover. else if(I.GetID()) @@ -407,7 +407,7 @@ DEFINE_BITFIELD(turret_flags, list( . = ..() if(.) power_change() - RemoveInvisibility(type) + SetInvisibility(INVISIBILITY_NONE, id=type) spark_system.start() //creates some sparks because they look cool qdel(cover) //deletes the cover - no need on keeping it there! @@ -514,7 +514,7 @@ DEFINE_BITFIELD(turret_flags, list( return if(machine_stat & BROKEN) return - RemoveInvisibility(type) + SetInvisibility(INVISIBILITY_NONE, id=type) raising = 1 if(cover) flick("popup", cover) diff --git a/code/game/machinery/porta_turret/portable_turret_cover.dm b/code/game/machinery/porta_turret/portable_turret_cover.dm index a45828755748ce..082881fc2fa910 100644 --- a/code/game/machinery/porta_turret/portable_turret_cover.dm +++ b/code/game/machinery/porta_turret/portable_turret_cover.dm @@ -43,12 +43,12 @@ if(!parent_turret.anchored) parent_turret.set_anchored(TRUE) to_chat(user, span_notice("You secure the exterior bolts on the turret.")) - parent_turret.RemoveInvisibility(type) + parent_turret.SetInvisibility(INVISIBILITY_NONE, id=type, priority=INVISIBILITY_PRIORITY_TURRET_COVER) parent_turret.update_appearance() else parent_turret.set_anchored(FALSE) to_chat(user, span_notice("You unsecure the exterior bolts on the turret.")) - parent_turret.SetInvisibility(INVISIBILITY_MAXIMUM, id=type) + parent_turret.SetInvisibility(INVISIBILITY_MAXIMUM, id=type, priority=INVISIBILITY_PRIORITY_TURRET_COVER) parent_turret.update_appearance() qdel(src) return diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index 516f5ec8453a00..9ff9ee7f76b315 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -251,7 +251,12 @@ if(isnull(payload) || istype(payload, /obj/machinery/syndicatebomb/training)) return - notify_ghosts("\A [src] has been activated at [get_area(src)]!", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Bomb Planted") + notify_ghosts( + "\A [src] has been activated at [get_area(src)]!", + source = src, + action = NOTIFY_ORBIT, + header = "Bomb Planted", + ) user.add_mob_memory(/datum/memory/bomb_planted/syndicate, antagonist = src) log_bomber(user, "has primed a", src, "for detonation (Payload: [payload.name])") payload.adminlog = "The [name] that [key_name(user)] had primed detonated!" diff --git a/code/game/objects/effects/anomalies/anomalies_bluespace.dm b/code/game/objects/effects/anomalies/anomalies_bluespace.dm index 998a5da9f5ccfa..49d59b9bcf701e 100644 --- a/code/game/objects/effects/anomalies/anomalies_bluespace.dm +++ b/code/game/objects/effects/anomalies/anomalies_bluespace.dm @@ -10,6 +10,10 @@ ///Distance we can teleport someone passively var/teleport_distance = 4 +/obj/effect/anomaly/bluespace/Initialize(mapload, new_lifespan, drops_core) + . = ..() + apply_wibbly_filters(src) + /obj/effect/anomaly/bluespace/anomalyEffect() ..() for(var/mob/living/M in range(teleport_range,src)) @@ -98,4 +102,3 @@ var/mob/living/living = bumpee living.apply_status_effect(/datum/status_effect/teleport_madness) - diff --git a/code/game/objects/effects/anomalies/anomalies_flux.dm b/code/game/objects/effects/anomalies/anomalies_flux.dm index 2bb3ab28a1ada7..91f09095d6f6f9 100644 --- a/code/game/objects/effects/anomalies/anomalies_flux.dm +++ b/code/game/objects/effects/anomalies/anomalies_flux.dm @@ -14,6 +14,7 @@ COMSIG_ATOM_ENTERED = PROC_REF(on_entered), ) AddElement(/datum/element/connect_loc, loc_connections) + apply_wibbly_filters(src) /obj/effect/anomaly/flux/anomalyEffect() ..() @@ -66,7 +67,7 @@ ///range in whuich we zap var/zap_range = 1 ///strength of the zappy - var/zap_power = 1e6 + var/zap_power = 2500 ///the zappy flags var/zap_flags = ZAP_GENERATES_POWER | ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE @@ -78,7 +79,7 @@ /obj/effect/anomaly/flux/big/anomalyEffect() . = ..() - tesla_zap(src, zap_range, zap_power, zap_flags) + tesla_zap(source = src, zap_range = zap_range, power = zap_power, cutoff = 1e3, zap_flags = zap_flags) /obj/effect/anomaly/flux/big/Bumped(atom/movable/bumpee) . = ..() diff --git a/code/game/objects/effects/anomalies/anomalies_gravity.dm b/code/game/objects/effects/anomalies/anomalies_gravity.dm index efd49ef502f637..fa7c4f48a36f33 100644 --- a/code/game/objects/effects/anomalies/anomalies_gravity.dm +++ b/code/game/objects/effects/anomalies/anomalies_gravity.dm @@ -23,6 +23,7 @@ COMSIG_ATOM_ENTERED = PROC_REF(on_entered), ) AddElement(/datum/element/connect_loc, loc_connections) + apply_wibbly_filters(src) warp = new(src) vis_contents += warp diff --git a/code/game/objects/effects/anomalies/anomalies_hallucination.dm b/code/game/objects/effects/anomalies/anomalies_hallucination.dm index 83648601017d41..a6696070df1c72 100644 --- a/code/game/objects/effects/anomalies/anomalies_hallucination.dm +++ b/code/game/objects/effects/anomalies/anomalies_hallucination.dm @@ -15,6 +15,10 @@ span_warning("You are going insane!"), ) +/obj/effect/anomaly/hallucination/Initialize(mapload, new_lifespan, drops_core) + . = ..() + apply_wibbly_filters(src) + /obj/effect/anomaly/hallucination/anomalyEffect(seconds_per_tick) . = ..() ticks += seconds_per_tick diff --git a/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm b/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm index f97f3482e83623..b290c23ac3f4dd 100644 --- a/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm +++ b/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm @@ -7,6 +7,10 @@ var/releasedelay = 10 aSignal = /obj/item/assembly/signaler/anomaly/pyro +/obj/effect/anomaly/pyro/Initialize(mapload, new_lifespan, drops_core) + . = ..() + apply_wibbly_filters(src) + /obj/effect/anomaly/pyro/anomalyEffect(seconds_per_tick) ..() ticks += seconds_per_tick diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm index 2c6d01b5bc400d..941034ec511be4 100644 --- a/code/game/objects/effects/decals/decal.dm +++ b/code/game/objects/effects/decals/decal.dm @@ -50,8 +50,8 @@ anchored = TRUE /// Does this decal change colors on holidays var/use_holiday_colors = FALSE - /// The pattern used when recoloring the decal - var/pattern = PATTERN_DEFAULT + /// The pattern used when recoloring the decal. If null, it'll use the def of the station or holiday. + var/pattern // This is with the intent of optimizing mapload // See spawners for more details since we use the same pattern diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm index 4254d99fdc391b..112f3b228dc47d 100644 --- a/code/game/objects/effects/decals/misc.dm +++ b/code/game/objects/effects/decals/misc.dm @@ -13,6 +13,8 @@ var/lifetime = INFINITY ///Are we a part of a stream? var/stream + /// String used in combat logs containing reagents present for when the puff hits something + var/logging_string /obj/effect/decal/chempuff/Destroy(force) user = null @@ -22,28 +24,39 @@ /obj/effect/decal/chempuff/blob_act(obj/structure/blob/B) return -/obj/effect/decal/chempuff/proc/end_life(datum/move_loop/engine) - QDEL_IN(src, engine.delay) //Gotta let it stop drifting - animate(src, alpha = 0, time = engine.delay) +/obj/effect/decal/chempuff/proc/end_life(delay = 0.5 SECONDS) + QDEL_IN(src, delay) //Gotta let it stop drifting + animate(src, alpha = 0, time = delay) /obj/effect/decal/chempuff/proc/loop_ended(datum/move_loop/source) SIGNAL_HANDLER + if(QDELETED(src)) return - end_life(source) + end_life(source.delay) /obj/effect/decal/chempuff/proc/check_move(datum/move_loop/source, result) + SIGNAL_HANDLER + if(QDELETED(src)) //Reasons PLEASE WORK I SWEAR TO GOD return if(result == MOVELOOP_FAILURE) //If we hit something - end_life(source) + end_life(source.delay) return - var/puff_reagents_string = reagents.get_reagent_log_string() - var/travelled_max_distance = (source.lifetime - source.delay <= 0) - var/turf/our_turf = get_turf(src) + spray_down_turf(get_turf(src), travelled_max_distance = (source.lifetime - source.delay <= 0)) - for(var/atom/movable/turf_atom in our_turf) + if(lifetime < 0) // Did we use up all the puff early? + end_life(source.delay) + +/** + * Handles going through every movable on the passed turf and calling [spray_down_atom] on them. + * + * [travelled_max_distance] is used to determine if we're at the end of the life, as in some + * contexts an atom may or may not end up being exposed depending on how far we've travelled. + */ +/obj/effect/decal/chempuff/proc/spray_down_turf(turf/spraying, travelled_max_distance = FALSE) + for(var/atom/movable/turf_atom in spraying) if(turf_atom == src || turf_atom.invisibility) //we ignore the puff itself and stuff below the floor continue @@ -51,8 +64,7 @@ break if(!stream) - reagents.expose(turf_atom, VAPOR) - log_combat(user, turf_atom, "sprayed", sprayer, addition="which had [puff_reagents_string]") + spray_down_atom(turf_atom) if(ismob(turf_atom)) lifetime -= 1 continue @@ -65,23 +77,24 @@ if(turf_mob.body_position != STANDING_UP && !travelled_max_distance) continue - reagents.expose(turf_mob, VAPOR) - log_combat(user, turf_mob, "sprayed", sprayer, addition="which had [puff_reagents_string]") + spray_down_atom(turf_atom) lifetime -= 1 else if(travelled_max_distance) - reagents.expose(turf_atom, VAPOR) - log_combat(user, turf_atom, "sprayed", sprayer, addition="which had [puff_reagents_string]") + spray_down_atom(turf_atom) lifetime -= 1 if(lifetime >= 0 && (!stream || travelled_max_distance)) - reagents.expose(our_turf, VAPOR) - log_combat(user, our_turf, "sprayed", sprayer, addition="which had [puff_reagents_string]") + spray_down_atom(spraying) lifetime -= 1 - // Did we use up all the puff early? - if(lifetime < 0) - end_life(source) +/// Actually handles exposing the passed atom to the reagents and logging +/obj/effect/decal/chempuff/proc/spray_down_atom(atom/spraying) + if(isnull(logging_string)) + logging_string = reagents.get_reagent_log_string() + + reagents.expose(spraying, VAPOR) + log_combat(user, spraying, "sprayed", sprayer, addition = "which had [logging_string]") /obj/effect/decal/fakelattice name = "lattice" diff --git a/code/game/objects/effects/particles/smoke.dm b/code/game/objects/effects/particles/smoke.dm index cd42f702ef9754..4f31ffc0869986 100644 --- a/code/game/objects/effects/particles/smoke.dm +++ b/code/game/objects/effects/particles/smoke.dm @@ -18,9 +18,6 @@ /particles/smoke/burning position = list(0, 0, 0) -/particles/smoke/burning/fireplace - position = list(0, 29, 0) - /particles/smoke/burning/small spawning = 1 scale = list(0.8, 0.8) diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index 591036b30d9d4e..091b4700673201 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -43,6 +43,8 @@ var/force_teleport = FALSE /// Does this portal create spark effect when teleporting? var/sparkless = FALSE + /// If FALSE, the wibble filter will not be applied to this portal (only a visual effect). + var/wibbles = TRUE /obj/effect/portal/anom name = "wormhole" @@ -53,6 +55,7 @@ mech_sized = TRUE teleport_channel = TELEPORT_CHANNEL_WORMHOLE light_on = FALSE + wibbles = FALSE /obj/effect/portal/Move(newloc) for(var/T in newloc) @@ -100,6 +103,8 @@ hardlinked = automatic_link if(isturf(hard_target_override)) hard_target = hard_target_override + if(wibbles) + apply_wibbly_filters(src) /obj/effect/portal/singularity_pull() return diff --git a/code/game/objects/effects/posters/contraband.dm b/code/game/objects/effects/posters/contraband.dm index 6881c52862c717..2bb2fcce50e469 100644 --- a/code/game/objects/effects/posters/contraband.dm +++ b/code/game/objects/effects/posters/contraband.dm @@ -509,7 +509,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/poster/contraband/triumphal_arch . = ..() . += span_notice("You browse some of the poster's information...") . += "\t[span_info("Va Lümla Commissary Menu (Spring 335)")]" - . += "\t[span_info("Windgrass Cigarettes, Half-Pack (6): 1 Ticket")]" + . += "\t[span_info("Sparkweed Cigarettes, Half-Pack (6): 1 Ticket")]" . += "\t[span_info("Töchtaüse Schnapps, Bottle (4 Measures): 2 Tickets")]" . += "\t[span_info("Activin Gum, Pack (4): 1 Ticket")]" . += "\t[span_info("A18 Sustenance Bar, Breakfast, Bar (4): 1 Ticket")]" diff --git a/code/game/objects/effects/spiderwebs.dm b/code/game/objects/effects/spiderwebs.dm index 9b44d3507db2e1..9a3d6c9c8e3732 100644 --- a/code/game/objects/effects/spiderwebs.dm +++ b/code/game/objects/effects/spiderwebs.dm @@ -194,6 +194,22 @@ . = ..() AddComponent(/datum/component/caltrop, min_damage = 20, max_damage = 30, flags = CALTROP_NOSTUN | CALTROP_BYPASS_SHOES) +/obj/structure/spider/reflector + name = "Reflective silk screen" + icon = 'icons/effects/effects.dmi' + desc = "Made up of an extremly reflective silk material looking at it hurts." + icon_state = "reflector" + max_integrity = 30 + density = TRUE + opacity = TRUE + anchored = TRUE + flags_ricochet = RICOCHET_SHINY | RICOCHET_HARD + receive_ricochet_chance_mod = INFINITY + +/obj/structure/spider/reflector/Initialize(mapload) + . = ..() + air_update_turf(TRUE, TRUE) + /obj/structure/spider/effigy name = "web effigy" icon = 'icons/effects/effects.dmi' diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 33d13c4ec0d4a4..5b9f5a5a06b81f 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -289,6 +289,10 @@ icon_state = "bluestream_fade" duration = 9 +/obj/effect/temp_visual/bluespace_fissure/Initialize(mapload) + . = ..() + apply_wibbly_filters(src) + /obj/effect/temp_visual/gib_animation icon = 'icons/mob/simple/mob.dmi' duration = 15 diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index a8aeab47614562..1e874fed1a6f74 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1221,7 +1221,7 @@ return src /** - * tryEmbed() is for when you want to try embedding something without dealing with the damage + hit messages of calling hitby() on the item while targetting the target. + * tryEmbed() is for when you want to try embedding something without dealing with the damage + hit messages of calling hitby() on the item while targeting the target. * * Really, this is used mostly with projectiles with shrapnel payloads, from [/datum/element/embed/proc/checkEmbedProjectile], and called on said shrapnel. Mostly acts as an intermediate between different embed elements. * @@ -1374,12 +1374,9 @@ // Update icons if this is being carried by a mob /obj/item/wash(clean_types) . = ..() - - SEND_SIGNAL(src, COMSIG_ATOM_WASHED) - if(ismob(loc)) var/mob/mob_loc = loc - mob_loc.regenerate_icons() + mob_loc.update_clothing(slot_flags) /// Called on [/datum/element/openspace_item_click_handler/proc/on_afterattack]. Check the relative file for information. /obj/item/proc/handle_openspace_click(turf/target, mob/user, proximity_flag, click_parameters) diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 9dd7e125055f18..195895c44c37e9 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -654,10 +654,8 @@ return FALSE var/list/user_memories = user.mind.memories var/datum/memory/key/account/user_key = user_memories[/datum/memory/key/account] - var/user_account = 11111 - if(!isnull(user_key)) - user_account = user_key.remembered_id - var/new_bank_id = tgui_input_number(user, "Enter the account ID to associate with this card.", "Link Bank Account", user_account, 999999, 111111) + var/default_account = (istype(user_key) && user_key.remembered_id) || 11111 + var/new_bank_id = tgui_input_number(user, "Enter the account ID to associate with this card.", "Link Bank Account", default_account, 999999, 111111) if(!new_bank_id || QDELETED(user) || QDELETED(src) || issilicon(user) || !alt_click_can_use_id(user) || loc != user) return FALSE if(registered_account?.account_id == new_bank_id) diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 94e9cb674b2691..6766e8376680e4 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -847,6 +847,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM span_notice("You hear a quiet click, as [user] shuts off [src] without even looking at what [user.p_theyre()] doing. Wow."), span_notice("You quietly shut off [src] without even looking at what you're doing. Wow.") ) + playsound(src, 'modular_skyrat/master_files/sound/items/zippo_close.ogg', 50, TRUE) // SKYRAT EDIT ADDITION else user.visible_message( span_notice("[user] quietly shuts off [src]."), @@ -860,6 +861,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM span_notice("Without even breaking stride, [user] flips open and lights [src] in one smooth movement."), span_notice("Without even breaking stride, you flip open and light [src] in one smooth movement.") ) + playsound(src, 'modular_skyrat/master_files/sound/items/zippo_open.ogg', 50, TRUE) // SKYRAT EDIT ADDITION return var/hand_protected = FALSE diff --git a/code/game/objects/items/circuitboards/circuitboard.dm b/code/game/objects/items/circuitboards/circuitboard.dm index 1e12576f686265..c32de5b336ddb1 100644 --- a/code/game/objects/items/circuitboards/circuitboard.dm +++ b/code/game/objects/items/circuitboards/circuitboard.dm @@ -108,7 +108,7 @@ micro-manipulator, console screen, beaker, Microlaser, matter bin, power cells. . = ..() if(!LAZYLEN(req_components)) . += span_info("It requires no components.") - return . + return var/list/nice_list = list() for(var/component_path in req_components) @@ -118,27 +118,33 @@ micro-manipulator, console screen, beaker, Microlaser, matter bin, power cells. var/component_name var/component_amount = req_components[component_path] + //e.g. "glass sheet" vs. "glass" if(ispath(component_path, /obj/item/stack)) var/obj/item/stack/stack_path = component_path - if(initial(stack_path.singular_name)) - component_name = initial(stack_path.singular_name) //e.g. "glass sheet" vs. "glass" - else if(ispath(component_path, /obj/item/stock_parts) && !specific_parts) - var/obj/item/stock_parts/stock_part = component_path - component_name = initial(stock_part.base_name) || initial(stock_part.name) - else if(ispath(component_path, /obj/item/stock_parts)) - var/obj/item/stock_parts/stock_part = component_path - component_name = initial(stock_part.name) - else if(ispath(component_path, /datum/stock_part)) - var/datum/stock_part/stock_part = component_path - var/obj/item/stock_parts/physical_object_type = initial(stock_part.physical_object_type) - component_name = initial(physical_object_type.base_name) || initial(physical_object_type.name) + component_name = initial(stack_path.singular_name) + + //stock parts in datum or obj form + else if(ispath(component_path, /obj/item/stock_parts) || ispath(component_path, /datum/stock_part)) + var/obj/item/stock_parts/stock_part + if(ispath(component_path, /obj/item/stock_parts)) + stock_part = component_path + else + var/datum/stock_part/datum_part = component_path + stock_part = initial(datum_part.physical_object_type) + + if(!specific_parts) + component_name = initial(stock_part.base_name) + if(!component_name) + component_name = initial(stock_part.name) + + //beakers, any non conventional part else if(ispath(component_path, /atom)) var/atom/stock_part = component_path component_name = initial(stock_part.name) + //append decoded name to final result if (isnull(component_name)) stack_trace("[component_path] was an invalid component") - nice_list += list("[component_amount] [component_name]\s") . += span_info("It requires [english_list(nice_list)].") diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm index ec8dfefc3322b6..cfa1d0e4fca033 100644 --- a/code/game/objects/items/devices/chameleonproj.dm +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -61,6 +61,9 @@ if(iseffect(target)) if(!(istype(target, /obj/effect/decal))) //be a footprint return + make_copy(target, user) + +/obj/item/chameleon/proc/make_copy(atom/target, mob/user) playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, TRUE, -6) to_chat(user, span_notice("Scanned [target].")) var/obj/temp = new /obj() diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 027595a38d8133..9ba63151c7c814 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -295,25 +295,33 @@ w_class = WEIGHT_CLASS_TINY flags_1 = CONDUCT_1 light_range = 2 - var/holo_cooldown = 0 + COOLDOWN_DECLARE(holosign_cooldown) /obj/item/flashlight/pen/afterattack(atom/target, mob/user, proximity_flag) . = ..() - if(!proximity_flag) - if(holo_cooldown > world.time) - to_chat(user, span_warning("[src] is not ready yet!")) - return - var/T = get_turf(target) - if(locate(/mob/living) in T) - new /obj/effect/temp_visual/medical_holosign(T,user) //produce a holographic glow - holo_cooldown = world.time + 10 SECONDS - return + if(proximity_flag) + return + + if(!COOLDOWN_FINISHED(src, holosign_cooldown)) + balloon_alert(user, "not ready!") + return + + var/target_turf = get_turf(target) + var/mob/living/living_target = locate(/mob/living) in target_turf + + if(!living_target || (living_target == user)) + return + + to_chat(living_target, span_boldnotice("[user] is offering medical assistance; please halt your actions.")) + new /obj/effect/temp_visual/medical_holosign(target_turf, user) //produce a holographic glow + COOLDOWN_START(src, holosign_cooldown, 10 SECONDS) // see: [/datum/wound/burn/flesh/proc/uv()] /obj/item/flashlight/pen/paramedic name = "paramedic penlight" desc = "A high-powered UV penlight intended to help stave off infection in the field on serious burned patients. Probably really bad to look into." icon_state = "penlight_surgical" + light_color = LIGHT_COLOR_PURPLE /// Our current UV cooldown COOLDOWN_DECLARE(uv_cooldown) /// How long between UV fryings diff --git a/code/game/objects/items/devices/portable_chem_mixer.dm b/code/game/objects/items/devices/portable_chem_mixer.dm index 18458f75697adb..c48e9fe8f1ecd2 100644 --- a/code/game/objects/items/devices/portable_chem_mixer.dm +++ b/code/game/objects/items/devices/portable_chem_mixer.dm @@ -4,19 +4,18 @@ icon = 'icons/obj/medical/chemical.dmi' icon_state = "portablechemicalmixer_open" worn_icon_state = "portable_chem_mixer" + equip_sound = 'sound/items/equip/toolbelt_equip.ogg' w_class = WEIGHT_CLASS_HUGE slot_flags = ITEM_SLOT_BELT - equip_sound = 'sound/items/equip/toolbelt_equip.ogg' custom_price = PAYCHECK_CREW * 10 custom_premium_price = PAYCHECK_CREW * 14 - var/obj/item/reagent_containers/beaker = null ///Creating an empty slot for a beaker that can be added to dispense into - var/amount = 30 ///The amount of reagent that is to be dispensed currently - - var/list/dispensable_reagents = list() ///List in which all currently dispensable reagents go - - ///If the UI has the pH meter shown - var/show_ph = TRUE + ///Creating an empty slot for a beaker that can be added to dispense into + var/obj/item/reagent_containers/beaker = null + ///The amount of reagent that is to be dispensed currently + var/amount = 30 + ///List in which all currently dispensable reagents go + var/list/dispensable_reagents = list() /obj/item/storage/portable_chem_mixer/Initialize(mapload) . = ..() @@ -29,45 +28,56 @@ /obj/item/reagent_containers/cup/glass/waterbottle, /obj/item/reagent_containers/condiment, )) + register_context() /obj/item/storage/portable_chem_mixer/Destroy() QDEL_NULL(beaker) return ..() -/obj/item/storage/portable_chem_mixer/ex_act(severity, target) - if(severity > EXPLODE_LIGHT) - return ..() +/obj/item/storage/portable_chem_mixer/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() - return FALSE + context[SCREENTIP_CONTEXT_CTRL_LMB] = "[atom_storage.locked ? "Un" : ""]Lock storage" + if(atom_storage.locked && !QDELETED(beaker)) + context[SCREENTIP_CONTEXT_ALT_LMB] = "Eject beaker" -/obj/item/storage/portable_chem_mixer/attackby(obj/item/I, mob/user, params) - if (is_reagent_container(I) && !(I.item_flags & ABSTRACT) && I.is_open_container() && atom_storage.locked) - var/obj/item/reagent_containers/B = I - . = TRUE //no afterattack - if(!user.transferItemToLoc(B, src)) - return - replace_beaker(user, B) - update_appearance() - ui_interact(user) - return - return ..() + if(!isnull(held_item)) + if (!atom_storage.locked || \ + (held_item.item_flags & ABSTRACT) || \ + !is_reagent_container(held_item) || \ + !held_item.is_open_container() \ + ) + return CONTEXTUAL_SCREENTIP_SET + context[SCREENTIP_CONTEXT_LMB] = "Insert beaker" -/** - * Updates the contents of the portable chemical mixer - * - * A list of dispensable reagents is created by iterating through each source beaker in the portable chemical beaker and reading its contents - */ -/obj/item/storage/portable_chem_mixer/proc/update_contents() - dispensable_reagents.Cut() + return CONTEXTUAL_SCREENTIP_SET - for (var/obj/item/reagent_containers/B in contents) - var/key = B.reagents.get_master_reagent_id() - if (!(key in dispensable_reagents)) - dispensable_reagents[key] = list() - dispensable_reagents[key]["reagents"] = list() - dispensable_reagents[key]["reagents"] += B.reagents +/obj/item/storage/portable_chem_mixer/examine(mob/user) + . = ..() + if(!atom_storage.locked) + . += span_notice("Use [EXAMINE_HINT("ctrl click")] to lock in order to use its interface.") + else + . += span_notice("Its storage is locked, use [EXAMINE_HINT("ctrl click")] to unlock it.") + if(QDELETED(beaker)) + . += span_notice("A beaker can be inserted to dispense reagents after it is locked.") + else + . += span_notice("A beaker of [beaker.reagents.maximum_volume] units capacity is inserted.") + . += span_notice("It can be ejected with [EXAMINE_HINT("alt click")].") + +/obj/item/storage/portable_chem_mixer/ex_act(severity, target) + return severity > EXPLODE_LIGHT ? ..() : FALSE + +/obj/item/storage/portable_chem_mixer/attackby(obj/item/weapon, mob/user, params) + if (!atom_storage.locked || \ + (weapon.item_flags & ABSTRACT) || \ + !is_reagent_container(weapon) || \ + !weapon.is_open_container() \ + ) + return ..() - return + replace_beaker(user, weapon) + update_appearance() + return TRUE /obj/item/storage/portable_chem_mixer/update_icon_state() if(!atom_storage.locked) @@ -79,28 +89,48 @@ icon_state = "portablechemicalmixer_empty" return ..() - /obj/item/storage/portable_chem_mixer/AltClick(mob/living/user) if(!atom_storage.locked) + balloon_alert(user, "lock first to use alt eject!") return ..() if(!can_interact(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return + replace_beaker(user) update_appearance() /obj/item/storage/portable_chem_mixer/CtrlClick(mob/living/user) - if(atom_storage.locked) + if(atom_storage.locked == STORAGE_FULLY_LOCKED) atom_storage.locked = STORAGE_NOT_LOCKED + replace_beaker(user) + SStgui.close_all_uis() else atom_storage.locked = STORAGE_FULLY_LOCKED - if (!atom_storage.locked) - update_contents() - if (atom_storage.locked) atom_storage.hide_contents(usr) - replace_beaker(user) + update_appearance() - playsound(src, 'sound/items/screwdriver2.ogg', 50) - return + +/obj/item/storage/portable_chem_mixer/Exited(atom/movable/gone, direction) + . = ..() + if(gone == beaker) + beaker = null + else + update_contents() + +/// Reload dispensable reagents from new contents +/obj/item/storage/portable_chem_mixer/proc/update_contents() + dispensable_reagents.Cut() + for (var/obj/item/reagent_containers/container in contents) + var/key = container.reagents.get_master_reagent_id() + if (!(key in dispensable_reagents)) + dispensable_reagents[key] = list() + dispensable_reagents[key]["reagents"] = list() + dispensable_reagents[key]["reagents"] += container.reagents + +/obj/item/storage/portable_chem_mixer/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + . = ..() + if(!atom_storage.locked) + update_contents() /** * Replaces the beaker of the portable chemical mixer with another beaker, or simply adds the new beaker if none is in currently @@ -111,34 +141,12 @@ * * obj/item/reagent_containers/new_beaker - The new beaker that the user wants to put into the device */ /obj/item/storage/portable_chem_mixer/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) - if(!user) - return FALSE if(beaker) user.put_in_hands(beaker) - beaker = null if(new_beaker) - beaker = new_beaker - return TRUE - -/obj/item/storage/portable_chem_mixer/attack_hand(mob/user, list/modifiers) - if (loc != user) - return ..() - else - if (!atom_storage.locked) - return ..() - if(atom_storage?.locked) - ui_interact(user) - return - -/obj/item/storage/portable_chem_mixer/attack_self(mob/user) - if(loc == user) - if (atom_storage.locked) - ui_interact(user) - return - else - to_chat(user, span_notice("It looks like this device can be worn as a belt for increased accessibility. A label indicates that the 'CTRL'-button on the device may be used to close it after it has been filled with bottles and beakers of chemicals.")) + if(!user.transferItemToLoc(new_beaker, src)) return - return + beaker = new_beaker /obj/item/storage/portable_chem_mixer/MouseDrop(obj/over_object) . = ..() @@ -149,30 +157,29 @@ M.putItemFromInventoryInHandIfPossible(src, H.held_index) /obj/item/storage/portable_chem_mixer/ui_interact(mob/user, datum/tgui/ui) + if(loc != user) + balloon_alert(user, "hold it in your hand!") + return + if(!atom_storage.locked) + balloon_alert(user, "lock it first!") + return + ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "PortableChemMixer", name) - - var/is_hallucinating = FALSE - if(isliving(user)) - var/mob/living/living_user = user - is_hallucinating = !!living_user.has_status_effect(/datum/status_effect/hallucination) - - if(is_hallucinating) - // to not ruin the immersion by constantly changing the fake chemicals - ui.set_autoupdate(FALSE) - ui.open() + var/is_hallucinating = FALSE + if(isliving(user)) + var/mob/living/living_user = user + is_hallucinating = !!living_user.has_status_effect(/datum/status_effect/hallucination) + ui.set_autoupdate(!is_hallucinating) // to not ruin the immersion by constantly changing the fake chemicals + /obj/item/storage/portable_chem_mixer/ui_data(mob/user) - var/list/data = list() - data["amount"] = amount - data["isBeakerLoaded"] = beaker ? 1 : 0 - data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null - data["beakerMaxVolume"] = beaker ? beaker.volume : null - data["beakerTransferAmounts"] = beaker ? list(1,5,10,30,50,100) : null - data["showpH"] = show_ph - var/chemicals[0] + . = list() + .["amount"] = amount + + var/list/chemicals = list() var/is_hallucinating = FALSE if(isliving(user)) var/mob/living/living_user = user @@ -190,46 +197,54 @@ total_ph = rs.ph if(is_hallucinating && prob(5)) chemname = "[pick_list_replacements("hallucination.json", "chemicals")]" - chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name), "volume" = total_volume, "pH" = total_ph))) - data["chemicals"] = chemicals - var/beakerContents[0] - if(beaker) - for(var/datum/reagent/R in beaker.reagents.reagent_list) - beakerContents.Add(list(list("name" = R.name, "id" = ckey(R.name), "volume" = R.volume, "pH" = R.ph))) // list in a list because Byond merges the first list... - data["beakerCurrentpH"] = round(beaker.reagents.ph, 0.01) - data["beakerContents"] = beakerContents - - return data - -/obj/item/storage/portable_chem_mixer/ui_act(action, params) + chemicals += list(list("title" = chemname, "id" = temp.name, "volume" = total_volume, "pH" = total_ph)) + .["chemicals"] = chemicals + + var/list/beaker_data = null + if(!QDELETED(beaker)) + beaker_data = list() + beaker_data["maxVolume"] = beaker.volume + beaker_data["transferAmounts"] = beaker.possible_transfer_amounts + beaker_data["pH"] = round(beaker.reagents.ph, 0.01) + beaker_data["currentVolume"] = round(beaker.reagents.total_volume, 0.01) + var/list/beakerContents = list() + if(length(beaker?.reagents.reagent_list)) + for(var/datum/reagent/reagent in beaker.reagents.reagent_list) + beakerContents += list(list("name" = reagent.name, "volume" = round(reagent.volume, 0.01))) // list in a list because Byond merges the first list... + beaker_data["contents"] = beakerContents + .["beaker"] = beaker_data + +/obj/item/storage/portable_chem_mixer/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return + switch(action) if("amount") - var/target = text2num(params["target"]) - amount = target - . = TRUE + amount = text2num(params["target"]) + return TRUE + if("dispense") - var/reagent_name = params["reagent"] - var/datum/reagent/reagent = GLOB.name2reagent[reagent_name] - var/entry = dispensable_reagents[reagent] - if(beaker && beaker.loc == src) - var/datum/reagents/R = beaker.reagents - var/actual = min(amount, 1000, R.maximum_volume - R.total_volume) - // todo: add check if we have enough reagent left - for (var/datum/reagents/source in entry["reagents"]) + var/datum/reagent/reagent = GLOB.name2reagent[params["reagent"]] + if(isnull(reagent)) + return + + if(!QDELETED(beaker)) + var/datum/reagents/container = beaker.reagents + var/actual = min(amount, 1000, container.maximum_volume - container.total_volume) + for (var/datum/reagents/source in dispensable_reagents[reagent]["reagents"]) var/to_transfer = min(source.total_volume, actual) - source.trans_to(beaker, to_transfer) + source.trans_to(beaker, to_transfer, transferred_by = ui.user) actual -= to_transfer if (actual <= 0) break - . = TRUE + return TRUE + if("remove") - var/amount = text2num(params["amount"]) - beaker.reagents.remove_all(amount) - . = TRUE + beaker.reagents.remove_all(text2num(params["amount"])) + return TRUE + if("eject") - replace_beaker(usr) + replace_beaker(ui.user) update_appearance() - . = TRUE + return TRUE diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 6c0cd4017e327d..0849c6c2b26385 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -124,7 +124,11 @@ span_hear("You hear a click.")) message_admins("Power sink activated by [ADMIN_LOOKUPFLW(user)] at [ADMIN_VERBOSEJMP(src)]") user.log_message("activated a powersink", LOG_GAME) - notify_ghosts("[user] has activated a power sink!", source = src, header = "Shocking News!") + notify_ghosts( + "[user] has activated a power sink!", + source = src, + header = "Shocking News!", + ) set_mode(OPERATING) if(OPERATING) @@ -188,7 +192,11 @@ if (!warning_given) warning_given = TRUE message_admins("Power sink at ([x],[y],[z] - JMP) has reached [ALERT]% of max heat. Explosion imminent.") - notify_ghosts("[src] is about to reach critical heat capacity!", source = src, header = "Power Sunk") + notify_ghosts( + "[src] is about to reach critical heat capacity!", + source = src, + header = "Power Sunk", + ) playsound(src, 'sound/effects/screech.ogg', 100, TRUE, TRUE) if(internal_heat >= max_heat) diff --git a/code/game/objects/items/devices/pressureplates.dm b/code/game/objects/items/devices/pressureplates.dm index e8c894d011225c..1b6a5ee6db7b8a 100644 --- a/code/game/objects/items/devices/pressureplates.dm +++ b/code/game/objects/items/devices/pressureplates.dm @@ -91,3 +91,21 @@ active = underfloor_accessibility < UNDERFLOOR_VISIBLE +/obj/item/pressure_plate/puzzle + protected = TRUE + anchored = TRUE //this prevents us from being picked up + active = TRUE + removable_signaller = FALSE + /// puzzle id we send if stepped on + var/puzzle_id + /// queue size must match + var/queue_size = 2 + +/obj/item/pressure_plate/puzzle/Initialize(mapload) + . = ..() + if(!isnull(puzzle_id)) + SSqueuelinks.add_to_queue(src, puzzle_id, queue_size) + +/obj/item/pressure_plate/puzzle/trigger() + can_trigger = FALSE + SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED) diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 13a054ec8e4984..d6dd9bcc3a7344 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -357,7 +357,6 @@ GLOBAL_LIST_INIT(channel_tokens, list( make_syndie() /obj/item/radio/headset/screwdriver_act(mob/living/user, obj/item/tool) - user.set_machine(src) if(keyslot || keyslot2) for(var/ch_name in channels) SSradio.remove_object(src, GLOB.radiochannels[ch_name]) @@ -379,8 +378,6 @@ GLOBAL_LIST_INIT(channel_tokens, list( return TRUE /obj/item/radio/headset/attackby(obj/item/W, mob/user, params) - user.set_machine(src) - if(istype(W, /obj/item/encryptionkey)) if(keyslot && keyslot2) to_chat(user, span_warning("The headset can't hold another key!")) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index c680056667b52d..1bc96c3512228a 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -531,7 +531,7 @@ subspace_transmission = TRUE subspace_switchable = TRUE dog_fashion = null - canhear_range = 0 // Skyrat Edit - Stops borgs being a loudspeaker and contains it to the tile they're on + canhear_range = 0 /obj/item/radio/borg/resetChannels() . = ..() diff --git a/code/game/objects/items/devices/reverse_bear_trap.dm b/code/game/objects/items/devices/reverse_bear_trap.dm index b5cbb985570707..8ac8d2a602675e 100644 --- a/code/game/objects/items/devices/reverse_bear_trap.dm +++ b/code/game/objects/items/devices/reverse_bear_trap.dm @@ -107,7 +107,15 @@ user.dropItemToGround(src) target.equip_to_slot_if_possible(src, ITEM_SLOT_HEAD) arm() - notify_ghosts("[user] put a reverse bear trap on [target]!", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, ghost_sound = 'sound/machines/beep.ogg', notify_volume = 75, header = "Reverse bear trap armed") + notify_ghosts( + "[user] put a reverse bear trap on [target]!", + source = src, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + ghost_sound = 'sound/machines/beep.ogg', + notify_volume = 75, + header = "Reverse bear trap armed", + ) /obj/item/reverse_bear_trap/proc/snap() reset() diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index 50c42c5f75318a..f7e28a2de3b74d 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -319,19 +319,9 @@ if(advanced && humantarget.has_dna()) render_list += "Genetic Stability: [humantarget.dna.stability]%.\n" - // Species and body temperature + // Hulk and body temperature var/datum/species/targetspecies = humantarget.dna.species - var/mutant = humantarget.dna.check_mutation(/datum/mutation/human/hulk) \ - || targetspecies.mutantlungs != initial(targetspecies.mutantlungs) \ - || targetspecies.mutantbrain != initial(targetspecies.mutantbrain) \ - || targetspecies.mutantheart != initial(targetspecies.mutantheart) \ - || targetspecies.mutanteyes != initial(targetspecies.mutanteyes) \ - || targetspecies.mutantears != initial(targetspecies.mutantears) \ - || targetspecies.mutanttongue != initial(targetspecies.mutanttongue) \ - || targetspecies.mutantliver != initial(targetspecies.mutantliver) \ - || targetspecies.mutantstomach != initial(targetspecies.mutantstomach) \ - || targetspecies.mutantappendix != initial(targetspecies.mutantappendix) \ - || istype(humantarget.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS), /obj/item/organ/external/wings/functional) + var/mutant = humantarget.dna.check_mutation(/datum/mutation/human/hulk) render_list += "Species: [targetspecies.name][mutant ? "-derived mutant" : ""]\n" var/core_temperature_message = "Core temperature: [round(humantarget.coretemperature-T0C, 0.1)] °C ([round(humantarget.coretemperature*1.8-459.67,0.1)] °F)" diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm index 4003f947b8ddcb..6bac2e7df37dd2 100644 --- a/code/game/objects/items/eightball.dm +++ b/code/game/objects/items/eightball.dm @@ -158,7 +158,12 @@ // notify ghosts that someone's shaking a haunted eightball // and inform them of the message, (hopefully a yes/no question) selected_message = last_message - notify_ghosts("[user] is shaking [src], hoping to get an answer to \"[selected_message]\"", source = src, action = NOTIFY_PLAY, header = "Magic eightball") + notify_ghosts( + "[user] is shaking [src], hoping to get an answer to \"[selected_message]\"", + source = src, + action = NOTIFY_PLAY, + header = "Magic eightball", + ) /obj/item/toy/eightball/haunted/get_answer() var/top_amount = 0 diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm index 2b157181023a04..da07843dec3581 100644 --- a/code/game/objects/items/food/misc.dm +++ b/code/game/objects/items/food/misc.dm @@ -432,6 +432,18 @@ . = ..() AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/sushi/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 6) +/obj/item/food/seaweedsheet/saltcane + name = "dried saltcane sheathe" + desc = "A dried sheet of saltcane sheathe can used for making sushi. Use an ingredient on it to start making custom sushi!" + icon_state = "seaweedsheet" + food_reagents = list( + /datum/reagent/consumable/nutriment = 1, + /datum/reagent/consumable/nutriment/vitamin = 1, + ) + tastes = list("seaweed" = 1) + foodtypes = VEGETABLES + w_class = WEIGHT_CLASS_SMALL + /obj/item/food/granola_bar name = "granola bar" desc = "A dried mixture of oats, nuts, fruits, and chocolate condensed into a chewy bar. Makes a great snack while space-hiking." diff --git a/code/game/objects/items/frog_statue.dm b/code/game/objects/items/frog_statue.dm new file mode 100644 index 00000000000000..4d1bf9b6aa595e --- /dev/null +++ b/code/game/objects/items/frog_statue.dm @@ -0,0 +1,165 @@ +#define STATUE_FILTER "statue_filter" +#define FILTER_COLOR "#34b347" +#define RECALL_DURATION 3 SECONDS +#define MINIMUM_COLOR_VALUE 60 + +/obj/item/frog_statue + name = "frog statue" + desc = "Are they really comfortable living in this thing?" + icon = 'icons/obj/weapons/guns/magic.dmi' + icon_state = "frog_statue" + item_flags = NOBLUDGEON + ///our pet frog + var/mob/living/contained_frog + ///the summon cooldown + COOLDOWN_DECLARE(summon_cooldown) + +/obj/item/frog_statue/attack_self(mob/user) + . = ..() + + if(.) + return TRUE + + if(!COOLDOWN_FINISHED(src, summon_cooldown)) + user.balloon_alert(user, "recharging!") + return TRUE + + COOLDOWN_START(src, summon_cooldown, 30 SECONDS) + if(isnull(contained_frog)) + user.balloon_alert(user, "no frog linked!") + return TRUE + if(contained_frog.loc == src) + release_frog(user) + return TRUE + recall_frog(user) + return TRUE + +/obj/item/frog_statue/examine(mob/user) + . = ..() + if(!IS_WIZARD(user)) + return + if(isnull(contained_frog)) + . += span_notice("There are currently no frogs linked to this statue!") + else + . += span_notice("Using it will [contained_frog in src ? "release" : "recall"] the beast!") + +///resummon the frog into its home +/obj/item/frog_statue/proc/recall_frog(mob/user) + playsound(src, 'sound/items/frog_statue_release.ogg', 20) + user.Beam(contained_frog, icon_state = "lichbeam", time = RECALL_DURATION) + animate(contained_frog, transform = matrix().Scale(0.3, 0.3), time = RECALL_DURATION) + addtimer(CALLBACK(contained_frog, TYPE_PROC_REF(/atom/movable, forceMove), src), RECALL_DURATION) + +///release the frog to wreak havoc +/obj/item/frog_statue/proc/release_frog(mob/user) + var/list/possible_turfs = list() + for(var/turf/possible_turf in oview(2, user)) + if(possible_turf.is_blocked_turf() || isopenspaceturf(possible_turf)) + continue + possible_turfs += possible_turf + playsound(src, 'sound/items/frog_statue_release.ogg', 50, TRUE) + var/turf/final_turf = length(possible_turfs) ? pick(possible_turfs) : get_turf(src) + user.Beam(final_turf, icon_state = "lichbeam", time = RECALL_DURATION) + contained_frog.forceMove(final_turf) + animate(contained_frog, transform = matrix(), time = RECALL_DURATION) + REMOVE_TRAIT(contained_frog, TRAIT_AI_PAUSED, MAGIC_TRAIT) + +///set this frog as our inhabitor +/obj/item/frog_statue/proc/set_new_frog(mob/living/frog) + frog.transform = frog.transform.Scale(0.3, 0.3) + contained_frog = frog + animate_filter() + RegisterSignal(frog, COMSIG_QDELETING, PROC_REF(render_obsolete)) + +/// we have lost our frog, let out a scream! +/obj/item/frog_statue/proc/render_obsolete(datum/source) + SIGNAL_HANDLER + + contained_frog = null + playsound(src, 'sound/magic/demon_dies.ogg', 50, TRUE) + UnregisterSignal(source, COMSIG_QDELETING) + +/obj/item/frog_statue/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + . = ..() + if(arrived != contained_frog) + return + animate_filter() + ADD_TRAIT(contained_frog, TRAIT_AI_PAUSED, MAGIC_TRAIT) + if(contained_frog.health < contained_frog.maxHealth) + START_PROCESSING(SSobj, src) + +/obj/item/frog_statue/process(seconds_per_tick) + if(isnull(contained_frog)) + return + if(contained_frog.health == contained_frog.maxHealth) + STOP_PROCESSING(SSobj, src) + return + if(contained_frog.stat == DEAD) + contained_frog.revive() + contained_frog.adjustBruteLoss(-5) + +/obj/item/frog_statue/proc/animate_filter(mob/living/frog) + add_filter(STATUE_FILTER, 2, list("type" = "outline", "color" = FILTER_COLOR, "size" = 1)) + var/filter = get_filter(STATUE_FILTER) + animate(filter, alpha = 230, time = 2 SECONDS, loop = -1) + animate(alpha = 30, time = 0.5 SECONDS) + +/obj/item/frog_statue/Exited(atom/movable/gone, direction) + . = ..() + if(gone != contained_frog) + return + clear_filters() + +/obj/item/frog_contract + name = "frog contract" + desc = "Create a pact with an elder frog! This great beast will be your mount, protector, but most importantly your friend." + icon = 'icons/obj/scrolls.dmi' + icon_state = "scroll" + +/obj/item/frog_contract/attack_self(mob/user) + . = ..() + if(.) + return TRUE + create_frog(user) + return TRUE + +///customize our own frog and trap it into the statue +/obj/item/frog_contract/proc/create_frog(mob/user) + var/obj/item/frog_statue/statue = new(null) + var/mob/living/basic/leaper/new_frog = new(statue) + statue.set_new_frog(new_frog) + new_frog.befriend(user) + ADD_TRAIT(new_frog, TRAIT_AI_PAUSED, MAGIC_TRAIT) + select_frog_name(user, new_frog) + select_frog_color(user, new_frog) + user.put_in_hands(statue) + qdel(src) + + + +/obj/item/frog_contract/proc/select_frog_name(mob/user, mob/new_frog) + var/frog_name = sanitize_name(tgui_input_text(user, "Choose your frog's name!", "Name pet toad", "leaper", MAX_NAME_LEN), allow_numbers = TRUE) + if(!frog_name) + to_chat(user, span_warning("Please enter a valid name.")) + select_frog_name(user, new_frog) + return + new_frog.name = frog_name + +/obj/item/frog_contract/proc/select_frog_color(mob/user, mob/living/basic/leaper/new_frog) + var/frog_color = input(user, "Select your frog's color!" , "Pet toad color", COLOR_GREEN) as color|null + if(isnull(frog_color)) + to_chat(user, span_warning("Please choose a valid color.")) + select_frog_color(user, new_frog) + return + var/temp_hsv = RGBtoHSV(frog_color) + if(ReadHSV(temp_hsv)[3] < MINIMUM_COLOR_VALUE) + to_chat(user, span_danger("This color is too dark!")) + select_frog_color(user, new_frog) + return + new_frog.set_color_overlay(frog_color) + + +#undef STATUE_FILTER +#undef FILTER_COLOR +#undef RECALL_DURATION +#undef MINIMUM_COLOR_VALUE diff --git a/code/game/objects/items/granters/crafting/rebarxbowsyndie.dm b/code/game/objects/items/granters/crafting/rebarxbowsyndie.dm new file mode 100644 index 00000000000000..fd38d4f4ccb203 --- /dev/null +++ b/code/game/objects/items/granters/crafting/rebarxbowsyndie.dm @@ -0,0 +1,13 @@ +/obj/item/book/granter/crafting_recipe/dusting/rebarxbowsyndie_ammo + name = "SYNDICATE REBAR CROSSBOW OWNERS MANUAL" + desc = "This book will self destruct upon being read a second time." + crafting_recipe_types = list( + /datum/crafting_recipe/rebarsyndie + ) + uses = 1 + remarks = list( + "AIM FOR THE LEGS TO CRIPPLE YOUR FOES", + "USE A ROD AND WIRECUTTERS TO MAKE BETTER AMMO", + "BE AWARE OF THE SCOPE'S BLIND SPOTS", + "READ THIS BOOK AGAIN TO DUST IT.", + ) diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm index d5f3b0dec9d431..998057bce2aded 100644 --- a/code/game/objects/items/grenades/plastic.dm +++ b/code/game/objects/items/grenades/plastic.dm @@ -119,7 +119,13 @@ message_admins("[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at [ADMIN_VERBOSEJMP(target)] with [det_time] second fuse") user.log_message("planted [name] on [target.name] with a [det_time] second fuse.", LOG_ATTACK) - notify_ghosts("[user] has planted \a [src] on [target] with a [det_time] second fuse!", source = bomb_target, action = (isturf(target) ? NOTIFY_JUMP : NOTIFY_ORBIT), flashwindow = FALSE, header = "Explosive Planted") + notify_ghosts( + "[user] has planted \a [src] on [target] with a [det_time] second fuse!", + source = bomb_target, + action = (isturf(target) ? NOTIFY_JUMP : NOTIFY_ORBIT), + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Explosive Planted", + ) moveToNullspace() //Yep diff --git a/code/game/objects/items/his_grace.dm b/code/game/objects/items/his_grace.dm index 12c06e6916ac01..fe0e12d4d50d52 100644 --- a/code/game/objects/items/his_grace.dm +++ b/code/game/objects/items/his_grace.dm @@ -149,7 +149,12 @@ gender = MALE adjust_bloodthirst(1) force_bonus = HIS_GRACE_FORCE_BONUS * LAZYLEN(contents) - notify_ghosts("[user] has awoken His Grace!", source = src, action = NOTIFY_ORBIT, header = "All Hail His Grace!") + notify_ghosts( + "[user] has awoken His Grace!", + source = src, + action = NOTIFY_ORBIT, + header = "All Hail His Grace!", + ) playsound(user, 'sound/effects/pope_entry.ogg', 100) update_appearance() move_gracefully() diff --git a/code/game/objects/items/holosign_creator.dm b/code/game/objects/items/holosign_creator.dm index 3f8bb3c41defff..f491321090a8cc 100644 --- a/code/game/objects/items/holosign_creator.dm +++ b/code/game/objects/items/holosign_creator.dm @@ -15,13 +15,16 @@ item_flags = NOBLUDGEON var/list/signs var/max_signs = 10 - var/creation_time = 0 //time to create a holosign in deciseconds. + //time to create a holosign in deciseconds. + var/creation_time = 0 + //holosign image that is projected var/holosign_type = /obj/structure/holosign/wetsign var/holocreator_busy = FALSE //to prevent placing multiple holo barriers at once /obj/item/holosign_creator/Initialize(mapload) . = ..() AddElement(/datum/element/openspace_item_click_handler) + RegisterSignal(src, COMSIG_OBJ_PAINTED, TYPE_PROC_REF(/obj/item/holosign_creator, on_color_change)) /obj/item/holosign_creator/handle_openspace_click(turf/target, mob/user, proximity_flag, click_parameters) afterattack(target, user, proximity_flag, click_parameters) @@ -64,6 +67,9 @@ if(target_turf.is_blocked_turf(TRUE)) //don't try to sneak dense stuff on our tile during the wait. return . target_holosign = new holosign_type(get_turf(target), src) + target_holosign.add_hiddenprint(user) + if(color) + target_holosign.color = color return . /obj/item/holosign_creator/attack(mob/living/carbon/human/M, mob/user) @@ -71,16 +77,24 @@ /obj/item/holosign_creator/attack_self(mob/user) if(LAZYLEN(signs)) - for(var/H in signs) - qdel(H) + for(var/obj/structure/holosign/hologram as anything in signs) + qdel(hologram) balloon_alert(user, "holograms cleared") /obj/item/holosign_creator/Destroy() . = ..() if(LAZYLEN(signs)) - for(var/H in signs) - qdel(H) + for(var/obj/structure/holosign/hologram as anything in signs) + qdel(hologram) +/obj/item/holosign_creator/proc/on_color_change(obj/item/holosign_creator, mob/user, obj/item/toy/crayon/spraycan/spraycan, is_dark_color) + SIGNAL_HANDLER + if(!spraycan.actually_paints) + return + + if(LAZYLEN(signs)) + for(var/obj/structure/holosign/hologram as anything in signs) + hologram.color = color /obj/item/holosign_creator/janibarrier name = "custodial holobarrier projector" @@ -127,28 +141,28 @@ creation_time = 1.5 SECONDS max_signs = 9 holosign_type = /obj/structure/holosign/barrier/cyborg - var/shock = 0 + var/shock = FALSE /obj/item/holosign_creator/cyborg/attack_self(mob/user) if(iscyborg(user)) - var/mob/living/silicon/robot/R = user + var/mob/living/silicon/robot/borg = user if(shock) to_chat(user, span_notice("You clear all active holograms, and reset your projector to normal.")) holosign_type = /obj/structure/holosign/barrier/cyborg - creation_time = 5 - for(var/sign in signs) - qdel(sign) - shock = 0 + creation_time = 0.5 SECONDS + for(var/obj/structure/holosign/hologram as anything in signs) + qdel(hologram) + shock = FALSE return - if(R.emagged && !shock) + if(borg.emagged && !shock) to_chat(user, span_warning("You clear all active holograms, and overload your energy projector!")) holosign_type = /obj/structure/holosign/barrier/cyborg/hacked - creation_time = 30 - for(var/sign in signs) - qdel(sign) - shock = 1 + creation_time = 3 SECONDS + for(var/obj/structure/holosign/hologram as anything in signs) + qdel(hologram) + shock = TRUE return - for(var/sign in signs) - qdel(sign) + for(var/obj/structure/holosign/hologram as anything in signs) + qdel(hologram) balloon_alert(user, "holograms cleared") diff --git a/code/game/objects/items/hot_potato.dm b/code/game/objects/items/hot_potato.dm index 1a801b0dcda5bd..797c24aaf4cc63 100644 --- a/code/game/objects/items/hot_potato.dm +++ b/code/game/objects/items/hot_potato.dm @@ -150,7 +150,12 @@ log_bomber(null, null, src, "was primed for detonation (Timer:[delay],Explosive:[detonate_explosion],Range:[detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_fire_range])") active = TRUE if(detonate_explosion) //doesn't send a notification unless it's a genuine, exploding hot potato. - notify_ghosts("[user] has primed a Hot Potato!", source = src, action = NOTIFY_ORBIT, header = "Hot Hot Hot!") + notify_ghosts( + "[user] has primed a Hot Potato!", + source = src, + action = NOTIFY_ORBIT, + header = "Hot Hot Hot!", + ) /obj/item/hot_potato/proc/deactivate() update_appearance() diff --git a/code/game/objects/items/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm index c9f961b594e26e..0661db5dbe0123 100644 --- a/code/game/objects/items/implants/implant_explosive.dm +++ b/code/game/objects/items/implants/implant_explosive.dm @@ -125,10 +125,10 @@ "[imp_in] is about to detonate their explosive implant!", source = src, action = NOTIFY_ORBIT, - flashwindow = FALSE, + notify_flags = NOTIFY_CATEGORY_NOFLASH, ghost_sound = 'sound/machines/warning-buzzer.ogg', header = "Tick Tick Tick...", - notify_volume = 75 + notify_volume = 75, ) playsound(loc, 'sound/items/timer.ogg', 30, FALSE) diff --git a/code/game/objects/items/maintenance_loot.dm b/code/game/objects/items/maintenance_loot.dm index bfdc53ea916ed9..538e4cac93d437 100644 --- a/code/game/objects/items/maintenance_loot.dm +++ b/code/game/objects/items/maintenance_loot.dm @@ -11,8 +11,8 @@ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' //wow, lore - desc = "A hefty lead pipe.\nLead in an uncommon sight in this sector after being phased out due to employee health concerns. \ - \nThose of a more cynical disposition assume that the NT lead ban is a scheme to prevent divertion to Syndicate ammunition factories." + desc = "A hefty lead pipe.\nLead is an uncommon sight in this sector after being phased out due to employee health concerns. \ + \nThose of a more cynical disposition have claimed that the NT lead ban is a scheme to prevent diversion to Syndicate ammunition factories." force = 15 throwforce = 12 throw_range = 4 @@ -25,12 +25,12 @@ //Add lead material to this once implemented. /obj/item/stock_parts/cell/lead name = "lead-acid battery" - desc = "A type of primitive battery. It is quite large feels unexpectedly heavy." + desc = "A primitive battery. It is quite large and feels unexpectedly heavy." icon = 'icons/obj/maintenance_loot.dmi' icon_state = "lead_battery" throwforce = 10 maxcharge = 20000 //decent max charge - chargerate = 1400 //charging is about 30% less efficient compared lithium batteries. + chargerate = 1400 //charging is about 30% less efficient than lithium batteries. charge_light_type = null connector_type = "leadacid" rating = 2 //Kind of a mid-tier battery diff --git a/code/game/objects/items/manuals.dm b/code/game/objects/items/manuals.dm index 9d8cd8e9426e9d..e89391f7887278 100644 --- a/code/game/objects/items/manuals.dm +++ b/code/game/objects/items/manuals.dm @@ -232,228 +232,3 @@ Good luck! "} - -// Wiki books that are linked to the configured wiki link. - -// A book that links to the wiki -/obj/item/book/manual/wiki - var/page_link = "" - window_size = "970x710" - -/obj/item/book/manual/wiki/attack_self() - if(!book_data.content) - initialize_wikibook() - return ..() - -/obj/item/book/manual/wiki/proc/initialize_wikibook() - var/wikiurl = CONFIG_GET(string/wikiurl) - if(wikiurl) - var/wikiinfo = {" - - - - - - - - -

You start skimming through the manual...

- - - - - - "} - book_data.set_content(wikiinfo, trusted = TRUE) - -/obj/item/book/manual/wiki/chemistry - name = "Chemistry Textbook" - icon_state ="chemistrybook" - starting_author = "Nanotrasen" - starting_title = "Chemistry Textbook" - page_link = "Guide_to_chemistry" - -/obj/item/book/manual/wiki/engineering_construction - name = "Station Repairs and Construction" - icon_state ="bookEngineering" - starting_author = "Engineering Encyclopedia" - starting_title = "Station Repairs and Construction" - page_link = "Guide_to_construction" - -/obj/item/book/manual/wiki/engineering_guide - name = "Engineering Textbook" - icon_state ="bookEngineering2" - starting_author = "Engineering Encyclopedia" - starting_title = "Engineering Textbook" - page_link = "Guide_to_engineering" - -/obj/item/book/manual/wiki/security_space_law - name = "Corporate Regulations" //SKYRAT EDIT CHANGE - Original: "Space Law" - desc = "A set of Nanotrasen regulations for keeping law, order, and procedure followed within their space stations." //SKYRAT EDIT CHANGE - Original: "A set of Nanotrasen guidelines for keeping law and order on their space stations." - icon_state = "bookSpaceLaw" - starting_author = "Nanotrasen" - starting_title = "Corporate Regulations" //SKYRAT EDIT CHANGE - Original: "Space Law" - page_link = "Corporate_Regulations" //SKYRAT EDIT CHANGE - Original: "Space_Law" - -/obj/item/book/manual/wiki/security_space_law/suicide_act(mob/living/user) - user.visible_message(span_suicide("[user] pretends to read \the [src] intently... then promptly dies of laughter!")) - return OXYLOSS - -/obj/item/book/manual/wiki/infections - name = "Infections - Making your own pandemic!" - icon_state = "bookInfections" - starting_author = "Infections Encyclopedia" - starting_title = "Infections - Making your own pandemic!" - page_link = "Infections" - -/obj/item/book/manual/wiki/telescience - name = "Teleportation Science - Bluespace for dummies!" - icon_state = "book7" - starting_author = "University of Bluespace" - starting_title = "Teleportation Science - Bluespace for dummies!" - page_link = "Guide_to_telescience" - -/obj/item/book/manual/wiki/engineering_hacking - name = "Hacking" - icon_state ="bookHacking" - starting_author = "Engineering Encyclopedia" - starting_title = "Hacking" - page_link = "Hacking" - -/obj/item/book/manual/wiki/detective - name = "The Film Noir: Proper Procedures for Investigations" - icon_state ="bookDetective" - starting_author = "Nanotrasen" - starting_title = "The Film Noir: Proper Procedures for Investigations" - page_link = "Detective" - -/obj/item/book/manual/wiki/barman_recipes - name = "Barman Recipes: Mixing Drinks and Changing Lives" - icon_state = "barbook" - starting_author = "Sir John Rose" - starting_title = "Barman Recipes: Mixing Drinks and Changing Lives" - page_link = "Guide_to_drinks" - -/obj/item/book/manual/wiki/robotics_cyborgs - name = "Robotics for Dummies" - icon_state = "borgbook" - starting_author = "XISC" - starting_title = "Robotics for Dummies" - page_link = "Guide_to_robotics" - -/obj/item/book/manual/wiki/research_and_development - name = "Research and Development 101" - icon_state = "rdbook" - starting_author = "Dr. L. Ight" - starting_title = "Research and Development 101" - page_link = "Guide_to_Research_and_Development" - -/obj/item/book/manual/wiki/experimentor - name = "Mentoring your Experiments" - icon_state = "rdbook" - starting_author = "Dr. H.P. Kritz" - starting_title = "Mentoring your Experiments" - page_link = "Experimentor" - -/obj/item/book/manual/wiki/cooking_to_serve_man - name = "To Serve Man" - desc = "It's a cookbook!" - icon_state ="cooked_book" - starting_author = "the Kanamitan Empire" - starting_title = "To Serve Man" - page_link = "Guide_to_food" - -/obj/item/book/manual/wiki/tcomms - name = "Subspace Telecommunications And You" - icon_state = "book3" - starting_author = "Engineering Encyclopedia" - starting_title = "Subspace Telecommunications And You" - page_link = "Guide_to_Telecommunications" - -/obj/item/book/manual/wiki/atmospherics - name = "Lexica Atmosia" - icon_state = "book5" - starting_author = "the City-state of Atmosia" - starting_title = "Lexica Atmosia" - page_link = "Guide_to_Atmospherics" - -/obj/item/book/manual/wiki/medicine - name = "Medical Space Compendium, Volume 638" - icon_state = "book8" - starting_author = "Medical Journal" - starting_title = "Medical Space Compendium, Volume 638" - page_link = "Guide_to_medicine" - -/obj/item/book/manual/wiki/surgery - name = "Brain Surgery for Dummies" - icon_state = "book4" - starting_author = "Dr. F. Fran" - starting_title = "Brain Surgery for Dummies" - page_link = "Surgery" - -/obj/item/book/manual/wiki/grenades - name = "DIY Chemical Grenades" - icon_state = "book2" - starting_author = "W. Powell" - starting_title = "DIY Chemical Grenades" - page_link = "Grenade" - -/obj/item/book/manual/wiki/ordnance - name = "Ordnance for Dummies or: How I Learned to Stop Worrying and Love the Maxcap" - icon_state = "book6" - starting_author = "Cuban Pete" - starting_title = "Ordnance for Dummies or: How I Learned to Stop Worrying and Love the Maxcap" - page_link = "Guide_to_toxins" - -/obj/item/book/manual/wiki/ordnance/suicide_act(mob/living/user) - var/mob/living/carbon/human/H = user - user.visible_message(span_suicide("[user] starts dancing to the Rhumba Beat! It looks like [user.p_theyre()] trying to commit suicide!")) - playsound(loc, 'sound/effects/spray.ogg', 10, TRUE, -3) - if (!QDELETED(H)) - H.emote("spin") - sleep(2 SECONDS) - for(var/obj/item/W in H) - H.dropItemToGround(W) - if(prob(50)) - step(W, pick(GLOB.alldirs)) - ADD_TRAIT(H, TRAIT_DISFIGURED, TRAIT_GENERIC) - for(var/obj/item/bodypart/part as anything in H.bodyparts) - part.adjustBleedStacks(5) - H.gib_animation() - sleep(0.3 SECONDS) - H.adjustBruteLoss(1000) //to make the body super-bloody - // if we use gib() then the body gets deleted - H.spawn_gibs() - H.spill_organs(DROP_ALL_REMAINS) - H.spread_bodyparts(DROP_BRAIN) - return BRUTELOSS - -/obj/item/book/manual/wiki/plumbing - name = "Chemical Factories Without Narcotics" - icon_state ="plumbingbook" - starting_author = "Nanotrasen" - starting_title = "Chemical Factories Without Narcotics" - page_link = "Guide_to_plumbing" - -/obj/item/book/manual/wiki/cytology - name = "Unethically Grown Organics" - icon_state ="cytologybook" - starting_author = "Kryson" - starting_title = "Unethically Grown Organics" - page_link = "Guide_to_cytology" - -/obj/item/book/manual/wiki/tgc - name = "Tactical Game Cards - Player's Handbook" - icon_state = "tgcbook" - starting_author = "Nanotrasen Edu-tainment Division" - starting_title = "Tactical Game Cards - Player's Handbook" - page_link = "Tactical_Game_Cards" diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm index 8a8635d879a2e6..9dd35dfb25f9e8 100644 --- a/code/game/objects/items/melee/baton.dm +++ b/code/game/objects/items/melee/baton.dm @@ -42,22 +42,22 @@ /// Boolean on whether people with chunky fingers can use this baton. var/chunky_finger_usable = FALSE - /// The context to show when the baton is active and targetting a living thing + /// The context to show when the baton is active and targeting a living thing var/context_living_target_active = "Stun" - /// The context to show when the baton is active and targetting a living thing in combat mode + /// The context to show when the baton is active and targeting a living thing in combat mode var/context_living_target_active_combat_mode = "Stun" - /// The context to show when the baton is inactive and targetting a living thing + /// The context to show when the baton is inactive and targeting a living thing var/context_living_target_inactive = "Prod" - /// The context to show when the baton is inactive and targetting a living thing in combat mode + /// The context to show when the baton is inactive and targeting a living thing in combat mode var/context_living_target_inactive_combat_mode = "Attack" - /// The RMB context to show when the baton is active and targetting a living thing + /// The RMB context to show when the baton is active and targeting a living thing var/context_living_rmb_active = "Attack" - /// The RMB context to show when the baton is inactive and targetting a living thing + /// The RMB context to show when the baton is inactive and targeting a living thing var/context_living_rmb_inactive = "Attack" /obj/item/melee/baton/Initialize(mapload) diff --git a/code/game/objects/items/puzzle_pieces.dm b/code/game/objects/items/puzzle_pieces.dm index 9bf33e36f2fe9e..8eba5081d22664 100644 --- a/code/game/objects/items/puzzle_pieces.dm +++ b/code/game/objects/items/puzzle_pieces.dm @@ -1,7 +1,8 @@ -//Every time you got lost looking for keycards, incriment: 1 +//Every time you got lost looking for keycards, increment: 2 + +//************** +//*****Keys***** //************** -//*****Keys******************* -//************** ** ** /obj/item/keycard name = "security keycard" desc = "This feels like it belongs to a door." @@ -45,8 +46,10 @@ move_resist = MOVE_FORCE_OVERPOWERING damage_deflection = 70 can_open_with_hands = FALSE - /// Make sure that the puzzle has the same puzzle_id as the keycard door! + /// Make sure that the puzzle has the same puzzle_id as the keycard door! (If this is null, queuelinks dont happen!) var/puzzle_id = null + /// do we use queue_links? + var/uses_queuelinks = TRUE /// Message that occurs when the door is opened var/open_message = "The door beeps, and slides opens." @@ -63,16 +66,18 @@ /obj/machinery/door/puzzle/Initialize(mapload) . = ..() - RegisterSignal(SSdcs, COMSIG_GLOB_PUZZLE_COMPLETED, PROC_REF(try_signal)) + if(!isnull(puzzle_id) && uses_queuelinks) + SSqueuelinks.add_to_queue(src, puzzle_id) -/obj/machinery/door/puzzle/Destroy(force) - . = ..() - UnregisterSignal(SSdcs, COMSIG_GLOB_PUZZLE_COMPLETED) +/obj/machinery/door/puzzle/MatchedLinks(id, list/partners) + for(var/partner in partners) + RegisterSignal(partner, COMSIG_PUZZLE_COMPLETED, PROC_REF(try_signal)) /obj/machinery/door/puzzle/proc/try_signal(datum/source, try_id) SIGNAL_HANDLER - INVOKE_ASYNC(src, PROC_REF(try_puzzle_open), try_id) + puzzle_id = null //honestly these cant be closed anyway and im not fucking around with door code anymore + INVOKE_ASYNC(src, PROC_REF(try_puzzle_open), null) /obj/machinery/door/puzzle/Bumped(atom/movable/AM) return !density && ..() @@ -101,6 +106,7 @@ /obj/machinery/door/puzzle/keycard desc = "This door only opens when a keycard is swiped. It looks virtually indestructible." + uses_queuelinks = FALSE /obj/machinery/door/puzzle/keycard/attackby(obj/item/attacking_item, mob/user, params) . = ..() @@ -203,6 +209,8 @@ ) /// Banned combinations of the list in decimal var/static/list/banned_combinations = list(-1, 47, 95, 203, 311, 325, 422, 473, 488, 500, 511) + /// queue size, must match count of objects this activates! + var/queue_size = 2 /datum/armor/structure_light_puzzle melee = 100 @@ -224,6 +232,8 @@ var/position = !!(generated_board & (1< + + + + + + +

You start skimming through the manual...

+ + + + "} + +// A book that links to the wiki +/obj/item/book/manual/wiki + starting_content = "Nanotrasen presently does not have any resources on this topic. If you would like to know more, contact your local Central Command representative." // safety + /// The ending URL of the page that we link to. + var/page_link = "" + +/obj/item/book/manual/wiki/display_content(mob/living/user) + var/wiki_url = CONFIG_GET(string/wikiurl) + if(!wiki_url) + user.balloon_alert(user, "this book is empty!") + return + + credit_book_to_reader(user) + DIRECT_OUTPUT(user, browse(WIKI_PAGE_IFRAME(wiki_url, page_link), "window=manual;size=[BOOK_WINDOW_BROWSE_SIZE]")) // if you change this GUARANTEE that it works. + +/obj/item/book/manual/wiki/chemistry + name = "Chemistry Textbook" + icon_state ="chemistrybook" + starting_author = "Nanotrasen" + starting_title = "Chemistry Textbook" + page_link = "Guide_to_chemistry" + +/obj/item/book/manual/wiki/engineering_construction + name = "Station Repairs and Construction" + icon_state ="bookEngineering" + starting_author = "Engineering Encyclopedia" + starting_title = "Station Repairs and Construction" + page_link = "Guide_to_construction" + +/obj/item/book/manual/wiki/engineering_guide + name = "Engineering Textbook" + icon_state ="bookEngineering2" + starting_author = "Engineering Encyclopedia" + starting_title = "Engineering Textbook" + page_link = "Guide_to_engineering" + +/obj/item/book/manual/wiki/security_space_law + name = "Space Law" + desc = "A set of Nanotrasen guidelines for keeping law and order on their space stations." + icon_state = "bookSpaceLaw" + starting_author = "Nanotrasen" + starting_title = "Space Law" + page_link = "Space_Law" + +/obj/item/book/manual/wiki/security_space_law/suicide_act(mob/living/user) + user.visible_message(span_suicide("[user] pretends to read \the [src] intently... then promptly dies of laughter!")) + return OXYLOSS + +/obj/item/book/manual/wiki/infections + name = "Infections - Making your own pandemic!" + icon_state = "bookInfections" + starting_author = "Infections Encyclopedia" + starting_title = "Infections - Making your own pandemic!" + page_link = "Infections" + +/obj/item/book/manual/wiki/telescience + name = "Teleportation Science - Bluespace for dummies!" + icon_state = "book7" + starting_author = "University of Bluespace" + starting_title = "Teleportation Science - Bluespace for dummies!" + page_link = "Guide_to_telescience" + +/obj/item/book/manual/wiki/engineering_hacking + name = "Hacking" + icon_state ="bookHacking" + starting_author = "Engineering Encyclopedia" + starting_title = "Hacking" + page_link = "Hacking" + +/obj/item/book/manual/wiki/detective + name = "The Film Noir: Proper Procedures for Investigations" + icon_state ="bookDetective" + starting_author = "Nanotrasen" + starting_title = "The Film Noir: Proper Procedures for Investigations" + page_link = "Detective" + +/obj/item/book/manual/wiki/barman_recipes + name = "Barman Recipes: Mixing Drinks and Changing Lives" + icon_state = "barbook" + starting_author = "Sir John Rose" + starting_title = "Barman Recipes: Mixing Drinks and Changing Lives" + page_link = "Guide_to_drinks" + +/obj/item/book/manual/wiki/robotics_cyborgs + name = "Robotics for Dummies" + icon_state = "borgbook" + starting_author = "XISC" + starting_title = "Robotics for Dummies" + page_link = "Guide_to_robotics" + +/obj/item/book/manual/wiki/research_and_development + name = "Research and Development 101" + icon_state = "rdbook" + starting_author = "Dr. L. Ight" + starting_title = "Research and Development 101" + page_link = "Guide_to_Research_and_Development" + +/obj/item/book/manual/wiki/experimentor + name = "Mentoring your Experiments" + icon_state = "rdbook" + starting_author = "Dr. H.P. Kritz" + starting_title = "Mentoring your Experiments" + page_link = "Experimentor" + +/obj/item/book/manual/wiki/cooking_to_serve_man + name = "To Serve Man" + desc = "It's a cookbook!" + icon_state ="cooked_book" + starting_author = "the Kanamitan Empire" + starting_title = "To Serve Man" + page_link = "Guide_to_food" + +/obj/item/book/manual/wiki/tcomms + name = "Subspace Telecommunications And You" + icon_state = "book3" + starting_author = "Engineering Encyclopedia" + starting_title = "Subspace Telecommunications And You" + page_link = "Guide_to_Telecommunications" + +/obj/item/book/manual/wiki/atmospherics + name = "Lexica Atmosia" + icon_state = "book5" + starting_author = "the City-state of Atmosia" + starting_title = "Lexica Atmosia" + page_link = "Guide_to_Atmospherics" + +/obj/item/book/manual/wiki/medicine + name = "Medical Space Compendium, Volume 638" + icon_state = "book8" + starting_author = "Medical Journal" + starting_title = "Medical Space Compendium, Volume 638" + page_link = "Guide_to_medicine" + +/obj/item/book/manual/wiki/surgery + name = "Brain Surgery for Dummies" + icon_state = "book4" + starting_author = "Dr. F. Fran" + starting_title = "Brain Surgery for Dummies" + page_link = "Surgery" + +/obj/item/book/manual/wiki/grenades + name = "DIY Chemical Grenades" + icon_state = "book2" + starting_author = "W. Powell" + starting_title = "DIY Chemical Grenades" + page_link = "Grenade" + +/obj/item/book/manual/wiki/ordnance + name = "Ordnance for Dummies or: How I Learned to Stop Worrying and Love the Maxcap" + icon_state = "book6" + starting_author = "Cuban Pete" + starting_title = "Ordnance for Dummies or: How I Learned to Stop Worrying and Love the Maxcap" + page_link = "Guide_to_toxins" + +/obj/item/book/manual/wiki/ordnance/suicide_act(mob/living/user) + var/mob/living/carbon/human/H = user + user.visible_message(span_suicide("[user] starts dancing to the Rhumba Beat! It looks like [user.p_theyre()] trying to commit suicide!")) + playsound(loc, 'sound/effects/spray.ogg', 10, TRUE, -3) + if (!QDELETED(H)) + H.emote("spin") + sleep(2 SECONDS) + for(var/obj/item/W in H) + H.dropItemToGround(W) + if(prob(50)) + step(W, pick(GLOB.alldirs)) + ADD_TRAIT(H, TRAIT_DISFIGURED, TRAIT_GENERIC) + for(var/obj/item/bodypart/part as anything in H.bodyparts) + part.adjustBleedStacks(5) + H.gib_animation() + sleep(0.3 SECONDS) + H.adjustBruteLoss(1000) //to make the body super-bloody + // if we use gib() then the body gets deleted + H.spawn_gibs() + H.spill_organs(DROP_ALL_REMAINS) + H.spread_bodyparts(DROP_BRAIN) + return BRUTELOSS + +/obj/item/book/manual/wiki/plumbing + name = "Chemical Factories Without Narcotics" + icon_state ="plumbingbook" + starting_author = "Nanotrasen" + starting_title = "Chemical Factories Without Narcotics" + page_link = "Guide_to_plumbing" + +/obj/item/book/manual/wiki/cytology + name = "Unethically Grown Organics" + icon_state ="cytologybook" + starting_author = "Kryson" + starting_title = "Unethically Grown Organics" + page_link = "Guide_to_cytology" + +/obj/item/book/manual/wiki/tgc + name = "Tactical Game Cards - Player's Handbook" + icon_state = "tgcbook" + starting_author = "Nanotrasen Edu-tainment Division" + starting_title = "Tactical Game Cards - Player's Handbook" + page_link = "Tactical_Game_Cards" + +#undef BOOK_WINDOW_BROWSE_SIZE +#undef WIKI_PAGE_IFRAME diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 7f135fe839cbea..2a6db83d9d4682 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -160,7 +160,7 @@ if(has_buckled_mobs()) for(var/m in buckled_mobs) var/mob/living/buckled_mob = m - buckled_mob.electrocute_act((clamp(round(strength * 3.125e-6), 10, 90) + rand(-5, 5)), src, flags = SHOCK_TESLA) + buckled_mob.electrocute_act((clamp(round(strength * 1.25e-3), 10, 90) + rand(-5, 5)), src, flags = SHOCK_TESLA) ///the obj is deconstructed into pieces, whether through careful disassembly or when destroyed. /obj/proc/deconstruct(disassembled = TRUE) diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index ba8623ec4aa3a8..cdc2b2bd5ec15a 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -63,6 +63,6 @@ /obj/structure/zap_act(power, zap_flags) if(zap_flags & ZAP_OBJ_DAMAGE) - take_damage(power * 1.5625e-7, BURN, "energy") + take_damage(power * 2.5e-4, BURN, "energy") power -= power * 5e-4 //walls take a lot out of ya . = ..() diff --git a/code/game/objects/structures/broken_flooring.dm b/code/game/objects/structures/broken_flooring.dm index c81ca778424fe9..b2be42ae40ddf7 100644 --- a/code/game/objects/structures/broken_flooring.dm +++ b/code/game/objects/structures/broken_flooring.dm @@ -8,6 +8,8 @@ opacity = FALSE plane = FLOOR_PLANE layer = CATWALK_LAYER + /// do we always have FLOOR_PLANE even if we arent on plating? + var/always_floorplane = FALSE /obj/structure/broken_flooring/Initialize(mapload) . = ..() @@ -16,7 +18,7 @@ /obj/structure/broken_flooring/LateInitialize() . = ..() var/turf/turf = get_turf(src) - if(!isplatingturf(turf)) // Render as trash if not on plating + if(!isplatingturf(turf) && !always_floorplane) // Render as trash if not on plating plane = GAME_PLANE layer = LOW_OBJ_LAYER return @@ -35,20 +37,40 @@ /obj/structure/broken_flooring/singular icon_state = "singular" +/obj/structure/broken_flooring/singular/always_floorplane + always_floorplane = TRUE + /obj/structure/broken_flooring/pile icon_state = "pile" +/obj/structure/broken_flooring/pile/always_floorplane + always_floorplane = TRUE + /obj/structure/broken_flooring/side icon_state = "side" +/obj/structure/broken_flooring/side/always_floorplane + always_floorplane = TRUE + /obj/structure/broken_flooring/corner icon_state = "corner" +/obj/structure/broken_flooring/corner/always_floorplane + always_floorplane = TRUE + /obj/structure/broken_flooring/plating icon_state = "plating" +/obj/structure/broken_flooring/plating/always_floorplane + always_floorplane = TRUE + MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/singular, 0) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/pile, 0) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/side, 0) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/corner, 0) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/plating, 0) +MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/singular/always_floorplane, 0) +MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/pile/always_floorplane, 0) +MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/side/always_floorplane, 0) +MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/corner/always_floorplane, 0) +MAPPING_DIRECTIONAL_HELPERS(/obj/structure/broken_flooring/plating/always_floorplane, 0) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index db1122465f3c7d..7585a3bd37484d 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -804,13 +804,13 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) if(!opened) return user.visible_message(span_notice("[user] slices apart \the [src]."), - span_notice("You cut \the [src] apart weaponith \the [weapon]."), - span_hear("You hear weaponelding.")) + span_notice("You cut \the [src] apart with \the [weapon]."), + span_hear("You hear welding.")) deconstruct(TRUE) return else // for example cardboard box is cut with wirecutters user.visible_message(span_notice("[user] cut apart \the [src]."), \ - span_notice("You cut \the [src] apart weaponith \the [weapon].")) + span_notice("You cut \the [src] apart with \the [weapon].")) deconstruct(TRUE) return if (user.combat_mode) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index 556230808bcaaa..af0718f3d64673 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -21,6 +21,7 @@ new /obj/item/storage/box/gas_miner_beacons(src) // SKYRAT EDIT ADDITION new /obj/item/construction/plumbing/engineering(src) //SKYRAT EDIT ADDITION new /obj/item/circuitboard/machine/rodstopper(src) //SKYRAT EDIT ADDITION + new /obj/item/card/id/departmental_budget/eng(src) //SKYRAT EDIT ADDITION /obj/structure/closet/secure_closet/engineering_chief/populate_contents_immediate() . = ..() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm index 80dfd65b71fc78..030d4640e85487 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm @@ -93,6 +93,7 @@ new /obj/item/circuitboard/machine/techfab/department/medical(src) new /obj/item/storage/photo_album/cmo(src) new /obj/item/storage/lockbox/medal/med(src) + new /obj/item/card/id/departmental_budget/med(src) //SKYRAT EDIT ADDITION /obj/structure/closet/secure_closet/chief_medical/populate_contents_immediate() . = ..() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm index 674529967fdd77..1329f213d65760 100755 --- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm @@ -18,6 +18,7 @@ new /obj/item/circuitboard/machine/techfab/department/science(src) new /obj/item/storage/photo_album/rd(src) new /obj/item/storage/box/skillchips/science(src) + new /obj/item/card/id/departmental_budget/sci(src) //SKYRAT EDIT ADDITION /obj/structure/closet/secure_closet/research_director/populate_contents_immediate() . = ..() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index ec46756140ca25..f25c9cfec5d27c 100755 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -20,6 +20,7 @@ new /obj/item/gun/energy/e_gun(src) new /obj/item/door_remote/captain(src) new /obj/item/storage/photo_album/captain(src) + new /obj/item/card/id/departmental_budget(src) //SKYRAT EDIT ADDITION /obj/structure/closet/secure_closet/hop name = "head of personnel's locker" @@ -44,6 +45,7 @@ new /obj/item/circuitboard/machine/techfab/department/service(src) new /obj/item/storage/photo_album/hop(src) new /obj/item/storage/lockbox/medal/hop(src) + new /obj/item/card/id/departmental_budget/srv(src) //SKYRAT EDIT ADDITION /obj/structure/closet/secure_closet/hos name = "head of security's locker" @@ -65,6 +67,7 @@ new /obj/item/storage/belt/security/full(src) new /obj/item/circuitboard/machine/techfab/department/security(src) new /obj/item/storage/photo_album/hos(src) + new /obj/item/card/id/departmental_budget/sec(src) //SKYRAT EDIT ADDITION /obj/structure/closet/secure_closet/hos/populate_contents_immediate() . = ..() diff --git a/code/game/objects/structures/crates_lockers/crates/large.dm b/code/game/objects/structures/crates_lockers/crates/large.dm index 6438fd358189e1..0f3b9c19773b94 100644 --- a/code/game/objects/structures/crates_lockers/crates/large.dm +++ b/code/game/objects/structures/crates_lockers/crates/large.dm @@ -60,8 +60,6 @@ ..() for (var/i in 1 to 5) new /obj/effect/spawner/random/clothing/funny_hats(src) - for (var/i in 1 to 5) - new /obj/item/mod/module/hat_stabilizer(src) if(prob(1)) var/our_contents = list() for(var/obj/item/clothing/head/any_hat in contents) diff --git a/code/game/objects/structures/fireplace.dm b/code/game/objects/structures/fireplace.dm index 379e58fb64ce4e..97a9ce8bd4d2b6 100644 --- a/code/game/objects/structures/fireplace.dm +++ b/code/game/objects/structures/fireplace.dm @@ -167,7 +167,17 @@ fuel_added = 0 update_appearance() adjust_light() - particles = new /particles/smoke/burning/fireplace() + particles = new /particles/smoke/burning() + + switch(dir) + if(SOUTH) + particles.position = list(0, 29, 0) + if(EAST) + particles.position = list(-20, 9, 0) + if(WEST) + particles.position = list(20, 9, 0) + if(NORTH) // there is no icon state for SOUTH + QDEL_NULL(particles) /obj/structure/fireplace/proc/put_out() STOP_PROCESSING(SSobj, src) diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 3d68af42dc7547..bb82c6fb2949f4 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -52,9 +52,12 @@ /obj/structure/grille/examine(mob/user) . = ..() + if(flags_1 & NODECONSTRUCT_1) + return + if(anchored) . += span_notice("It's secured in place with screws. The rods look like they could be cut through.") - if(!anchored) + else . += span_notice("The anchoring screws are unscrewed. The rods look like they could be cut through.") /obj/structure/grille/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) @@ -186,6 +189,8 @@ add_fingerprint(user) if(shock(user, 100)) return + if(flags_1 & NODECONSTRUCT_1) + return FALSE tool.play_tool_sound(src, 100) deconstruct() return TOOL_ACT_TOOLTYPE_SUCCESS @@ -196,6 +201,8 @@ add_fingerprint(user) if(shock(user, 90)) return FALSE + if(flags_1 & NODECONSTRUCT_1) + return FALSE if(!tool.use_tool(src, user, 0, volume=100)) return FALSE set_anchored(!anchored) @@ -352,8 +359,8 @@ var/obj/structure/cable/C = T.get_cable_node() if(C) playsound(src, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) - tesla_zap(src, 3, C.newavail() * 0.01, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot. - C.add_delayedload(C.newavail() * 0.0375) // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock. + tesla_zap(source = src, zap_range = 3, power = C.newavail() * 0.01, cutoff = 1e3, zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot. + C.add_delayedload(C.newavail() * 0.0375) // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock. // What do you mean by this? return ..() /obj/structure/grille/get_dumping_location() diff --git a/code/game/objects/structures/gym/weight_machine.dm b/code/game/objects/structures/gym/weight_machine.dm index 4fe8e5edfc0754..761db678b38334 100644 --- a/code/game/objects/structures/gym/weight_machine.dm +++ b/code/game/objects/structures/gym/weight_machine.dm @@ -1,5 +1,6 @@ #define WORKOUT_XP 5 #define EXERCISE_STATUS_DURATION 20 SECONDS +#define SAFE_DRUNK_LEVEL 39 /obj/structure/weightmachine name = "chest press machine" @@ -18,6 +19,9 @@ ///The weight action we give to people that buckle themselves to us. var/datum/action/push_weights/weight_action + ///message when drunk user fails to use the machine + var/drunk_message = "You try for a new record and pull through! Through a muscle that is." + ///List of messages picked when using the machine. var/static/list/more_weight = list( "pushing it to the limit!", @@ -110,6 +114,14 @@ end_workout() return + // awlways a chance for a person not to fail horribly when drunk + if(user.get_drunk_amount() > SAFE_DRUNK_LEVEL && prob(min(user.get_drunk_amount(), 99))) + playsound(src,'sound/effects/bang.ogg', 50, TRUE) + to_chat(user, span_warning(drunk_message)) + user.take_bodypart_damage(rand(5, 10), wound_bonus = 10) + end_workout() + return + if(issilicon(user)) user.balloon_alert(user, pick(finished_silicon_message)) else @@ -157,5 +169,8 @@ pixel_shift_y = 5 + drunk_message = "You raise the bar over you trying to balance it with one hand, keyword tried." + #undef WORKOUT_XP #undef EXERCISE_STATUS_DURATION +#undef SAFE_DRUNK_LEVEL diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm index fdef93e77d6d46..bd20ef405fc825 100644 --- a/code/game/objects/structures/holosign.dm +++ b/code/game/objects/structures/holosign.dm @@ -153,17 +153,10 @@ icon_state = "holo_medical" alpha = 125 //lazy :) max_integrity = 1 - var/force_allaccess = FALSE var/buzzcd = 0 -/obj/structure/holosign/barrier/medical/examine(mob/user) - . = ..() - . += span_notice("The biometric scanners are [force_allaccess ? "off" : "on"].") - /obj/structure/holosign/barrier/medical/CanAllowThrough(atom/movable/mover, border_dir) . = ..() - if(force_allaccess) - return TRUE if(istype(mover, /obj/vehicle/ridden)) for(var/M in mover.buckled_mobs) if(ishuman(M)) @@ -188,13 +181,6 @@ return FALSE return TRUE -/obj/structure/holosign/barrier/medical/attack_hand(mob/living/user, list/modifiers) - if(!user.combat_mode && CanPass(user, get_dir(src, user))) - force_allaccess = !force_allaccess - to_chat(user, span_warning("You [force_allaccess ? "deactivate" : "activate"] the biometric scanners.")) //warning spans because you can make the station sick! - else - return ..() - /obj/structure/holosign/barrier/cyborg/hacked name = "Charged Energy Field" desc = "A powerful energy field that blocks movement. Energy arcs off it." diff --git a/code/game/objects/structures/maintenance.dm b/code/game/objects/structures/maintenance.dm index 33f27f40c47398..acdf28353d68df 100644 --- a/code/game/objects/structures/maintenance.dm +++ b/code/game/objects/structures/maintenance.dm @@ -267,6 +267,7 @@ at the cost of risking a vicious bite.**/ COMSIG_ATOM_EXIT = PROC_REF(blow_steam), ) AddElement(/datum/element/connect_loc, loc_connections) + register_context() update_icon_state() /obj/structure/steam_vent/attack_hand(mob/living/user, list/modifiers) @@ -283,6 +284,16 @@ at the cost of risking a vicious bite.**/ return blow_steam() +/obj/structure/steam_vent/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(isnull(held_item)) + context[SCREENTIP_CONTEXT_LMB] = vent_active ? "Close valve" : "Open valve" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_RMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET + return . + /obj/structure/steam_vent/wrench_act_secondary(mob/living/user, obj/item/tool) . = ..() if(vent_active) diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 76363a1b07b534..59ecf9a5327503 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -26,7 +26,6 @@ integrity_failure = 0.5 max_integrity = 200 var/list/mirror_options = INERT_MIRROR_OPTIONS - var/magical_mirror = FALSE ///Flags this race must have to be selectable with this type of mirror. var/race_flags = MIRROR_MAGIC @@ -80,10 +79,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) /obj/structure/mirror/attack_hand(mob/living/carbon/human/user) . = ..() - if(. || !ishuman(user) || broken || !magical_mirror) // SKYRAT EDIT CHANGE - MUNDANE MIRRORS DON'T LET YOU CHANGE - ORIGINAL: if(. || !ishuman(user) || broken) + if(. || !ishuman(user) || broken || !istype(src, /obj/structure/mirror/magic)) // SKYRAT EDIT CHANGE - MUNDANE MIRRORS DON'T LET YOU CHANGE - ORIGINAL: if(. || !ishuman(user) || broken) return TRUE - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH) && !magical_mirror) + if(!istype(src, /obj/structure/mirror/magic) && !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return TRUE //no tele-grooming (if nonmagical) return display_radial_menu(user) @@ -110,20 +109,26 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) return display_radial_menu(user) /obj/structure/mirror/proc/change_beard(mob/living/carbon/human/beard_dresser) - if(beard_dresser.physique != FEMALE && !magical_mirror) - var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list) - if(isnull(new_style)) - return TRUE - if(HAS_TRAIT(beard_dresser, TRAIT_SHAVED)) - to_chat(beard_dresser, span_notice("If only growing back facial hair were that easy for you... The reminder makes you feel terrible.")) - beard_dresser.add_mood_event("bald_hair_day", /datum/mood_event/bald_reminder) - return TRUE - beard_dresser.set_facial_hairstyle(new_style, update = TRUE) - else + if(beard_dresser.physique == FEMALE) if(beard_dresser.facial_hairstyle == "Shaved") - to_chat(beard_dresser, span_notice("You realize you don't have any facial hair.")) - return - beard_dresser.set_facial_hairstyle("Shaved", update = TRUE) + balloon_alert(beard_dresser, "nothing to shave!") + return TRUE + var/shave_beard = tgui_alert(beard_dresser, "Shave your beard?", "Grooming", list("Yes", "No")) + if(shave_beard == "Yes") + beard_dresser.set_facial_hairstyle("Shaved", update = TRUE) + return TRUE + + var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list) + + if(isnull(new_style)) + return TRUE + + if(HAS_TRAIT(beard_dresser, TRAIT_SHAVED)) + to_chat(beard_dresser, span_notice("If only growing back facial hair were that easy for you... The reminder makes you feel terrible.")) + beard_dresser.add_mood_event("bald_hair_day", /datum/mood_event/bald_reminder) + return TRUE + + beard_dresser.set_facial_hairstyle(new_style, update = TRUE) /obj/structure/mirror/proc/change_hair(mob/living/carbon/human/hairdresser) var/new_style = tgui_input_list(hairdresser, "Select a hairstyle", "Grooming", GLOB.hairstyles_list) @@ -317,7 +322,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) desc = "Turn and face the strange... face." icon_state = "magic_mirror" mirror_options = MAGIC_MIRROR_OPTIONS - magical_mirror = TRUE /obj/structure/mirror/magic/Initialize(mapload) . = ..() @@ -329,6 +333,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) selectable_races[initial(species_type.name)] = species_type selectable_races = sort_list(selectable_races) +/obj/structure/mirror/magic/change_beard(mob/living/carbon/human/beard_dresser) // magical mirrors do nothing but give you the damn beard + var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list) + if(isnull(new_style)) + return TRUE + beard_dresser.set_facial_hairstyle(new_style, update = TRUE) + return TRUE + //Magic mirrors can change hair color as well /obj/structure/mirror/magic/change_hair(mob/living/carbon/human/user) var/hairchoice = tgui_alert(user, "Hairstyle or hair color?", "Change Hair", list("Style", "Color")) @@ -350,7 +361,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) /obj/structure/mirror/magic/attack_hand(mob/living/carbon/human/user) . = ..() - if(!.) + if(.) return TRUE if(HAS_TRAIT(user, TRAIT_ADVANCEDTOOLUSER) && HAS_TRAIT(user, TRAIT_LITERATE)) @@ -378,11 +389,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) /obj/structure/mirror/magic/pride/attack_hand(mob/living/carbon/human/user) . = ..() - if(!.) + if(.) return TRUE - user.visible_message(span_danger("The ground splits beneath [user] as [user.p_their()] hand leaves the mirror!"), \ - span_notice("Perfect. Much better! Now nobody will be able to resist yo-")) + user.visible_message( + span_bolddanger("The ground splits beneath [user] as [user.p_their()] hand leaves the mirror!"), + span_notice("Perfect. Much better! Now nobody will be able to resist yo-"), + ) var/turf/user_turf = get_turf(user) var/list/levels = SSmapping.levels_by_trait(ZTRAIT_SPACE_RUINS) diff --git a/code/game/objects/structures/spirit_board.dm b/code/game/objects/structures/spirit_board.dm index 2e6a2bd9a0776c..e8882251237fd7 100644 --- a/code/game/objects/structures/spirit_board.dm +++ b/code/game/objects/structures/spirit_board.dm @@ -56,7 +56,11 @@ if(virgin) virgin = FALSE - notify_ghosts("Someone has begun playing with \a [src] in [get_area(src)]!", source = src, header = "Spirit board") + notify_ghosts( + "Someone has begun playing with \a [src] in [get_area(src)]!", + source = src, + header = "Spirit board", + ) var/new_planchette = tgui_input_list(ghost, "Choose the letter.", "Seance!", ghosty_options) if(isnull(new_planchette)) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 7219bb69c2e601..c80e2da85d6706 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -292,7 +292,7 @@ ..() return SECONDARY_ATTACK_CONTINUE_CHAIN -/obj/structure/table/proc/AfterPutItemOnTable(obj/item/I, mob/living/user) +/obj/structure/table/proc/AfterPutItemOnTable(obj/item/thing, mob/living/user) return /obj/structure/table/deconstruct(disassembled = TRUE, wrench_disassembly = 0) @@ -358,34 +358,52 @@ canSmoothWith = null icon = 'icons/obj/smooth_structures/rollingtable.dmi' icon_state = "rollingtable" - var/list/attached_items = list() + /// Lazylist of the items that we have on our surface. + var/list/attached_items = null /obj/structure/table/rolling/Initialize(mapload) . = ..() AddElement(/datum/element/noisy_movement) + RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(on_our_moved)) -/obj/structure/table/rolling/AfterPutItemOnTable(obj/item/I, mob/living/user) +/obj/structure/table/rolling/Destroy() + for(var/item in attached_items) + clear_item_reference(item) + LAZYNULL(attached_items) // safety + return ..() + +/obj/structure/table/rolling/AfterPutItemOnTable(obj/item/thing, mob/living/user) . = ..() - attached_items += I - RegisterSignal(I, COMSIG_MOVABLE_MOVED, PROC_REF(RemoveItemFromTable)) //Listen for the pickup event, unregister on pick-up so we aren't moved + LAZYADD(attached_items, thing) + RegisterSignal(thing, COMSIG_MOVABLE_MOVED, PROC_REF(on_item_moved)) -/obj/structure/table/rolling/proc/RemoveItemFromTable(datum/source, newloc, dir) +/// Handles cases where any attached item moves, with or without the table. If we get picked up or anything, unregister the signal so we don't move with the table after removal from the surface. +/obj/structure/table/rolling/proc/on_item_moved(datum/source, atom/old_loc, dir, forced, list/old_locs, momentum_change) SIGNAL_HANDLER - if(newloc != loc) //Did we not move with the table? because that shit's ok - return FALSE - attached_items -= source - UnregisterSignal(source, COMSIG_MOVABLE_MOVED) + var/atom/thing = source // let it runtime if it doesn't work because that is mad wack + if(thing.loc == loc) // if we move with the table, move on + return -/obj/structure/table/rolling/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) - . = ..() - if(!loc) + clear_item_reference(thing) + +/// Handles movement of the table itself, as well as moving along any atoms we have on our surface. +/obj/structure/table/rolling/proc/on_our_moved(datum/source, atom/old_loc, dir, forced, list/old_locs, momentum_change) + SIGNAL_HANDLER + if(isnull(loc)) // aw hell naw return + for(var/mob/living/living_mob in old_loc.contents)//Kidnap everyone on top living_mob.forceMove(loc) + for(var/atom/movable/attached_movable as anything in attached_items) - if(!attached_movable.Move(loc)) - RemoveItemFromTable(attached_movable, attached_movable.loc) + if(!attached_movable.Move(loc)) // weird + clear_item_reference(attached_movable) // we check again in on_item_moved() just in case something's wacky tobaccy + +/// Removes the signal and the entrance from the list. +/obj/structure/table/rolling/proc/clear_item_reference(obj/item/thing) + UnregisterSignal(thing, COMSIG_MOVABLE_MOVED) + LAZYREMOVE(attached_items, thing) /* * Glass tables diff --git a/code/game/objects/structures/traps.dm b/code/game/objects/structures/traps.dm index 124237fa59719b..1b6f1da06b6ea2 100644 --- a/code/game/objects/structures/traps.dm +++ b/code/game/objects/structures/traps.dm @@ -8,7 +8,7 @@ alpha = 30 //initially quite hidden when not "recharging" var/flare_message = "the trap flares brightly!" var/last_trigger = 0 - var/time_between_triggers = 600 //takes a minute to recharge + var/time_between_triggers = 1 MINUTES var/charges = INFINITY var/antimagic_flags = MAGIC_RESISTANCE @@ -61,50 +61,50 @@ last_trigger = world.time charges-- if(charges <= 0) - animate(src, alpha = 0, time = 10) - QDEL_IN(src, 10) + animate(src, alpha = 0, time = 1 SECONDS) + QDEL_IN(src, 1 SECONDS) else animate(src, alpha = initial(alpha), time = time_between_triggers) -/obj/structure/trap/proc/on_entered(datum/source, atom/movable/AM) +/obj/structure/trap/proc/on_entered(datum/source, atom/movable/victim) SIGNAL_HANDLER if(last_trigger + time_between_triggers > world.time) return // Don't want the traps triggered by sparks, ghosts or projectiles. - if(is_type_in_typecache(AM, ignore_typecache)) + if(is_type_in_typecache(victim, ignore_typecache)) return - if(ismob(AM)) - var/mob/M = AM - if(M.mind in immune_minds) + if(ismob(victim)) + var/mob/mob_victim = victim + if(mob_victim.mind in immune_minds) return - if(M.can_block_magic(antimagic_flags)) + if(mob_victim.can_block_magic(antimagic_flags)) flare() return if(charges <= 0) return flare() - if(isliving(AM)) - trap_effect(AM) + if(isliving(victim)) + trap_effect(victim) -/obj/structure/trap/proc/trap_effect(mob/living/L) +/obj/structure/trap/proc/trap_effect(mob/living/victim) return /obj/structure/trap/stun name = "shock trap" desc = "A trap that will shock and render you immobile. You'd better avoid it." icon_state = "trap-shock" - var/stun_time = 100 + var/stun_time = 10 SECONDS -/obj/structure/trap/stun/trap_effect(mob/living/L) - L.electrocute_act(30, src, flags = SHOCK_NOGLOVES) // electrocute act does a message. - L.Paralyze(stun_time) +/obj/structure/trap/stun/trap_effect(mob/living/victim) + victim.electrocute_act(30, src, flags = SHOCK_NOGLOVES) // electrocute act does a message. + victim.Paralyze(stun_time) /obj/structure/trap/stun/hunter name = "bounty trap" desc = "A trap that only goes off when a fugitive steps on it, announcing the location and stunning the target. You'd better avoid it." icon = 'icons/obj/restraints.dmi' icon_state = "bounty_trap_on" - stun_time = 200 + stun_time = 20 SECONDS sparks = FALSE //the item version gives them off to prevent runtimes (see Destroy()) antimagic_flags = NONE var/obj/item/bountytrap/stored_item @@ -112,7 +112,7 @@ /obj/structure/trap/stun/hunter/Initialize(mapload) . = ..() - time_between_triggers = 10 + time_between_triggers = 1 SECONDS flare_message = "[src] snaps shut!" /obj/structure/trap/stun/hunter/Destroy() @@ -121,10 +121,10 @@ stored_item = null return ..() -/obj/structure/trap/stun/hunter/on_entered(datum/source, atom/movable/AM) - if(isliving(AM)) - var/mob/living/L = AM - if(!L.mind?.has_antag_datum(/datum/antagonist/fugitive)) +/obj/structure/trap/stun/hunter/on_entered(datum/source, atom/movable/victim) + if(isliving(victim)) + var/mob/living/living_victim = victim + if(!living_victim.mind?.has_antag_datum(/datum/antagonist/fugitive)) return caught = TRUE . = ..() @@ -169,11 +169,11 @@ radio.talk_into(src, "Fugitive has triggered this trap in the [get_area_name(src)]!", RADIO_CHANNEL_COMMON) /obj/item/bountytrap/attack_self(mob/living/user) - var/turf/T = get_turf(src) - if(!user || !user.transferItemToLoc(src, T))//visibly unequips + var/turf/target_turf = get_turf(src) + if(!user || !user.transferItemToLoc(src, target_turf))//visibly unequips return to_chat(user, span_notice("You set up [src]. Examine while close to disarm it.")) - stored_trap.forceMove(T)//moves trap to ground + stored_trap.forceMove(target_turf)//moves trap to ground forceMove(stored_trap)//moves item into trap /obj/item/bountytrap/Destroy() @@ -189,9 +189,9 @@ desc = "A trap that will set you ablaze. You'd better avoid it." icon_state = "trap-fire" -/obj/structure/trap/fire/trap_effect(mob/living/L) - to_chat(L, span_danger("Spontaneous combustion!")) - L.Paralyze(20) +/obj/structure/trap/fire/trap_effect(mob/living/victim) + to_chat(victim, span_danger("Spontaneous combustion!")) + victim.Paralyze(2 SECONDS) new /obj/effect/hotspot(get_turf(src)) /obj/structure/trap/chill @@ -199,11 +199,11 @@ desc = "A trap that will chill you to the bone. You'd better avoid it." icon_state = "trap-frost" -/obj/structure/trap/chill/trap_effect(mob/living/L) - to_chat(L, span_danger("You're frozen solid!")) - L.Paralyze(20) - L.adjust_bodytemperature(-300) - L.apply_status_effect(/datum/status_effect/freon) +/obj/structure/trap/chill/trap_effect(mob/living/victim) + to_chat(victim, span_bolddanger("You're frozen solid!")) + victim.Paralyze(2 SECONDS) + victim.adjust_bodytemperature(-300) + victim.apply_status_effect(/datum/status_effect/freon) /obj/structure/trap/damage @@ -212,12 +212,12 @@ icon_state = "trap-earth" -/obj/structure/trap/damage/trap_effect(mob/living/L) - to_chat(L, span_danger("The ground quakes beneath your feet!")) - L.Paralyze(100) - L.adjustBruteLoss(35) +/obj/structure/trap/damage/trap_effect(mob/living/victim) + to_chat(victim, span_bolddanger("The ground quakes beneath your feet!")) + victim.Paralyze(10 SECONDS) + victim.adjustBruteLoss(35) var/obj/structure/flora/rock/style_random/giant_rock = new(get_turf(src)) - QDEL_IN(giant_rock, 200) + QDEL_IN(giant_rock, 20 SECONDS) /obj/structure/trap/ward @@ -225,7 +225,7 @@ desc = "A divine barrier, It looks like you could destroy it with enough effort, or wait for it to dissipate..." icon_state = "ward" density = TRUE - time_between_triggers = 1200 //Exists for 2 minutes + time_between_triggers = 2 MINUTES /obj/structure/trap/ward/Initialize(mapload) . = ..() @@ -236,10 +236,10 @@ desc = "A trap that rings with unholy energy. You think you hear... chittering?" icon_state = "trap-cult" -/obj/structure/trap/cult/trap_effect(mob/living/L) - to_chat(L, span_danger("With a crack, the hostile constructs come out of hiding, stunning you!")) - L.electrocute_act(10, src, flags = SHOCK_NOGLOVES) // electrocute act does a message. - L.Paralyze(20) - new /mob/living/simple_animal/hostile/construct/proteon/hostile(loc) - new /mob/living/simple_animal/hostile/construct/proteon/hostile(loc) - QDEL_IN(src, 30) +/obj/structure/trap/cult/trap_effect(mob/living/victim) + to_chat(victim, span_bolddanger("With a crack, the hostile constructs come out of hiding, stunning you!")) + victim.electrocute_act(10, src, flags = SHOCK_NOGLOVES) // electrocute act does a message. + victim.Paralyze(2 SECONDS) + new /mob/living/basic/construct/proteon/hostile(loc) + new /mob/living/basic/construct/proteon/hostile(loc) + QDEL_IN(src, 3 SECONDS) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 6884888e4052b6..4260e7ba19f7e7 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -79,6 +79,9 @@ /obj/structure/window/examine(mob/user) . = ..() + if(flags_1 & NODECONSTRUCT_1) + return + switch(state) if(WINDOW_SCREWED_TO_FRAME) . += span_notice("The window is screwed to the frame.") @@ -480,6 +483,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) return FALSE /obj/structure/window/reinforced/attackby_secondary(obj/item/tool, mob/user, params) + if(flags_1 & NODECONSTRUCT_1) + return ..() + switch(state) if(RWINDOW_SECURE) if(tool.tool_behaviour == TOOL_WELDER) @@ -558,6 +564,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) /obj/structure/window/reinforced/examine(mob/user) . = ..() + if(flags_1 & NODECONSTRUCT_1) + return switch(state) if(RWINDOW_SECURE) . += span_notice("It's been screwed in with one way screws, you'd need to heat them to have any chance of backing them out.") diff --git a/code/game/turfs/closed/indestructible.dm b/code/game/turfs/closed/indestructible.dm index a569f7c58944ca..72dbf6dd6faec6 100644 --- a/code/game/turfs/closed/indestructible.dm +++ b/code/game/turfs/closed/indestructible.dm @@ -364,3 +364,13 @@ SKYRAT EDIT REMOVAL END */ /turf/closed/indestructible/grille/Initialize(mapload) . = ..() underlays += mutable_appearance('icons/turf/floors.dmi', "plating") + +/turf/closed/indestructible/meat + name = "dense meat wall" + desc = "A huge chunk of dense, packed meat. Effectively impervious to conventional methods of destruction." + icon = 'icons/turf/walls/meat.dmi' + icon_state = "meatwall-0" + base_icon_state = "meatwall" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_WALLS + canSmoothWith = SMOOTH_GROUP_WALLS diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm index 012d331f12a700..47b08da3662b2b 100644 --- a/code/game/turfs/closed/minerals.dm +++ b/code/game/turfs/closed/minerals.dm @@ -100,7 +100,7 @@ if (!isturf(T)) return - if(TIMER_COOLDOWN_CHECK(src, REF(user))) //prevents mining turfs in progress + if(TIMER_COOLDOWN_RUNNING(src, REF(user))) //prevents mining turfs in progress return TIMER_COOLDOWN_START(src, REF(user), tool_mine_speed) @@ -121,7 +121,7 @@ var/turf/user_turf = user.loc if (!isturf(user_turf)) return - if(TIMER_COOLDOWN_CHECK(src, REF(user))) //prevents mining turfs in progress + if(TIMER_COOLDOWN_RUNNING(src, REF(user))) //prevents mining turfs in progress return var/mining_speed = mining_arms ? tool_mine_speed : hand_mine_speed TIMER_COOLDOWN_START(src, REF(user), mining_speed) diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index 676e2e740fe82b..8480b19940c7ef 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -124,9 +124,6 @@ /turf/open/indestructible/light icon_state = "light_on-1" -/turf/open/indestructible/plating - icon_state = "plating" - /turf/open/indestructible/permalube icon_state = "darkfull" @@ -223,6 +220,29 @@ init_air = FALSE baseturfs = /turf/open/indestructible/airblock +/turf/open/indestructible/meat + icon_state = "meat" + footstep = FOOTSTEP_MEAT + barefootstep = FOOTSTEP_MEAT + clawfootstep = FOOTSTEP_MEAT + heavyfootstep = FOOTSTEP_MEAT + initial_gas_mix = OPENTURF_DEFAULT_ATMOS + baseturfs = /turf/open/indestructible/meat + +/turf/open/indestructible/meat/airless + initial_gas_mix = AIRLESS_ATMOS + +/turf/open/indestructible/plating + name = "plating" + icon_state = "plating" + desc = "The attachment points are all bent to uselessness, looks nigh-impervious to damage." + overfloor_placed = FALSE + underfloor_accessibility = UNDERFLOOR_INTERACTABLE + footstep = FOOTSTEP_PLATING + +/turf/open/indestructible/plating/airless + initial_gas_mix = AIRLESS_ATMOS + /turf/open/Initalize_Atmos(time) excited = FALSE update_visuals() diff --git a/code/game/turfs/open/chasm.dm b/code/game/turfs/open/chasm.dm index 3af4d12b176a33..f4094c35b367bc 100644 --- a/code/game/turfs/open/chasm.dm +++ b/code/game/turfs/open/chasm.dm @@ -76,6 +76,9 @@ /turf/open/chasm/proc/apply_components(mapload) AddComponent(/datum/component/chasm, GET_TURF_BELOW(src), mapload) +/turf/open/chasm/can_cross_safely(atom/movable/crossing) + return HAS_TRAIT(src, TRAIT_CHASM_STOPPED) || HAS_TRAIT(crossing, TRAIT_MOVE_FLYING) + // Chasms for Lavaland, with planetary atmos and lava glow /turf/open/chasm/lavaland initial_gas_mix = LAVALAND_DEFAULT_ATMOS diff --git a/code/game/turfs/open/floor/misc_floor.dm b/code/game/turfs/open/floor/misc_floor.dm index ce34f760a672d2..b4fb5c8f2b4fea 100644 --- a/code/game/turfs/open/floor/misc_floor.dm +++ b/code/game/turfs/open/floor/misc_floor.dm @@ -156,7 +156,7 @@ /turf/open/floor/noslip/tram/Initialize(mapload) . = ..() - var/current_holiday_color = request_holiday_colors(src, PATTERN_VERTICAL_STRIPE) + var/current_holiday_color = request_station_colors(src, PATTERN_VERTICAL_STRIPE) || request_holiday_colors(src, PATTERN_VERTICAL_STRIPE) if(current_holiday_color) color = current_holiday_color else diff --git a/code/game/turfs/open/floor/plating/misc_plating.dm b/code/game/turfs/open/floor/plating/misc_plating.dm index 1933b291aee932..9b79313111f132 100644 --- a/code/game/turfs/open/floor/plating/misc_plating.dm +++ b/code/game/turfs/open/floor/plating/misc_plating.dm @@ -6,6 +6,10 @@ initial_gas_mix = OPENTURF_LOW_PRESSURE baseturfs = /turf/open/floor/plating/lowpressure +/turf/open/floor/plating/dumpsterair + initial_gas_mix = OPENTURF_DIRTY_ATMOS + temperature = 309 + /turf/open/floor/plating/icemoon icon_state = "plating" initial_gas_mix = ICEMOON_DEFAULT_ATMOS diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index 623da55f10409b..ebcfd4d3843059 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -315,6 +315,9 @@ burn_living.adjust_fire_stacks(lava_firestacks * seconds_per_tick) burn_living.ignite_mob() +/turf/open/lava/can_cross_safely(atom/movable/crossing) + return HAS_TRAIT(src, TRAIT_LAVA_STOPPED) || HAS_TRAIT(crossing, immunity_trait ) || HAS_TRAIT(crossing, TRAIT_MOVE_FLYING) + /turf/open/lava/smooth name = "lava" baseturfs = /turf/open/lava/smooth diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm index 8b8b7ca00c67e9..bd74acab4408f2 100644 --- a/code/game/turfs/open/openspace.dm +++ b/code/game/turfs/open/openspace.dm @@ -166,6 +166,9 @@ PlaceOnTop(/turf/open/floor/plating, flags = flags) PlaceOnTop(new_floor_path, flags = flags) +/turf/open/openspace/can_cross_safely(atom/movable/crossing) + return HAS_TRAIT(crossing, TRAIT_MOVE_FLYING) + /turf/open/openspace/icemoon name = "ice chasm" baseturfs = /turf/open/openspace/icemoon diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm index 182e918dc33a28..049309c262bdbf 100644 --- a/code/game/turfs/open/space/space.dm +++ b/code/game/turfs/open/space/space.dm @@ -254,6 +254,9 @@ GLOBAL_LIST_EMPTY(starlight) destination_y = dest_y destination_z = dest_z +/turf/open/space/can_cross_safely(atom/movable/crossing) + return HAS_TRAIT(crossing, TRAIT_SPACEWALK) + /turf/open/space/openspace icon = 'icons/turf/floors.dmi' icon_state = MAP_SWITCH("pure_white", "invisible") diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index a16c57105211ba..2bee06e7c4940b 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -6,7 +6,7 @@ GLOBAL_LIST_EMPTY(station_turfs) vis_flags = VIS_INHERIT_ID // Important for interaction with and visualization of openspace. luminosity = 1 light_height = LIGHTING_HEIGHT_FLOOR - + ///what /mob/oranges_ear instance is already assigned to us as there should only ever be one. ///used for guaranteeing there is only one oranges_ear per turf when assigned, speeds up view() iteration var/mob/oranges_ear/assigned_oranges_ear @@ -756,3 +756,7 @@ GLOBAL_LIST_EMPTY(station_turfs) explosive_resistance -= get_explosive_block() inherent_explosive_resistance = explosion_block explosive_resistance += get_explosive_block() + +/// Returns whether it is safe for an atom to move across this turf +/turf/proc/can_cross_safely(atom/movable/crossing) + return TRUE diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 77830d0277c215..988eb1c82876e3 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -301,7 +301,7 @@ GLOBAL_PROTECT(admin_verbs_poll) add_verb(src, GLOB.admin_verbs_permissions) if(rights & R_STEALTH) add_verb(src, /client/proc/stealth) - if(rights & R_ADMIN) + if(rights & R_POLL) add_verb(src, GLOB.admin_verbs_poll) if(rights & R_SOUND) add_verb(src, GLOB.admin_verbs_sounds) diff --git a/code/modules/admin/verbs/adminevents.dm b/code/modules/admin/verbs/adminevents.dm index dd8f1d96f60e94..9ba0fa7608cc3b 100644 --- a/code/modules/admin/verbs/adminevents.dm +++ b/code/modules/admin/verbs/adminevents.dm @@ -224,7 +224,13 @@ SSshuttle.admin_emergency_no_recall = TRUE SSshuttle.emergency.setTimer(0) SSshuttle.emergency.mode = SHUTTLE_DISABLED - priority_announce("Warning: Emergency Shuttle uplink failure, shuttle disabled until further notice.", "Emergency Shuttle Uplink Alert", ANNOUNCER_SHUTTLE) // SKYRAT EDIT CHANGE - Announcer Sounds + priority_announce( + text = "Emergency Shuttle uplink failure, shuttle disabled until further notice.", + title = "Uplink Failure", + sound = ANNOUNCER_SHUTTLE, // SKYRAT EDIT CHANGE - Announcer Sounds - ORIGINAL: sound = 'sound/misc/announce_dig.ogg', + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "grey", + ) /client/proc/admin_enable_shuttle() set category = "Admin.Events" @@ -250,7 +256,13 @@ if(SSshuttle.last_call_time < 10 SECONDS && SSshuttle.last_mode != SHUTTLE_IDLE) SSshuttle.last_call_time = 10 SECONDS //Make sure no insta departures. SSshuttle.emergency.setTimer(SSshuttle.last_call_time) - priority_announce("Warning: Emergency Shuttle uplink reestablished, shuttle enabled.", "Emergency Shuttle Uplink Alert", ANNOUNCER_SHUTTLE) // SKYRAT EDIT CHANGE - Announcer Sounds + priority_announce( + text = "Emergency Shuttle uplink reestablished, shuttle enabled.", + title = "Uplink Restored", + sound = ANNOUNCER_SHUTTLE, // SKYRAT EDIT CHANGE - Announcer Sounds - ORIGINAL: sound = 'sound/misc/announce_dig.ogg', + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "green", + ) /client/proc/admin_hostile_environment() set category = "Admin.Events" diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index a435756b456ee6..e8d6a685ae4108 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -54,7 +54,7 @@ GLOBAL_LIST_EMPTY(antagonists) /// The typepath for the outfit to show in the preview for the preferences menu. var/preview_outfit /// Flags for antags to turn on or off and check! - var/antag_flags = FLAG_FAKE_ANTAG + var/antag_flags = NONE /// If true, this antagonist can assign themself a new objective var/can_assign_self_objectives = FALSE /// Default to fill in when entering a custom objective. diff --git a/code/modules/antagonists/abductor/equipment/glands/electric.dm b/code/modules/antagonists/abductor/equipment/glands/electric.dm index 9c4d47dc337ab3..a3107af021793c 100644 --- a/code/modules/antagonists/abductor/equipment/glands/electric.dm +++ b/code/modules/antagonists/abductor/equipment/glands/electric.dm @@ -22,5 +22,5 @@ addtimer(CALLBACK(src, PROC_REF(zap)), rand(30, 100)) /obj/item/organ/internal/heart/gland/electric/proc/zap() - tesla_zap(owner, 4, 3.2e6, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN) + tesla_zap(source = owner, zap_range = 4, power = 8e3, cutoff = 1e3, zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN) playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, TRUE) diff --git a/code/modules/antagonists/blob/blob_antag.dm b/code/modules/antagonists/blob/blob_antag.dm index 2d606d65b18d02..99bba74ae89d24 100644 --- a/code/modules/antagonists/blob/blob_antag.dm +++ b/code/modules/antagonists/blob/blob_antag.dm @@ -143,7 +143,8 @@ action = NOTIFY_ORBIT, ghost_sound = 'sound/ambience/antag/blobalert.ogg', header = "Blob Awakening!", - notify_volume = 75 + notify_volume = 75, + notify_flags = NOTIFY_CATEGORY_DEFAULT, ) /datum/antagonist/blob/antag_listing_status() diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm index e206d97c26b12d..324c91ea3a5292 100644 --- a/code/modules/antagonists/blob/structures/_blob.dm +++ b/code/modules/antagonists/blob/structures/_blob.dm @@ -227,9 +227,9 @@ /obj/structure/blob/zap_act(power, zap_flags) if(overmind) if(overmind.blobstrain.tesla_reaction(src, power)) - take_damage(power * 3.125e-6, BURN, ENERGY) + take_damage(power * 1.25e-3, BURN, ENERGY) else - take_damage(power * 3.125e-6, BURN, ENERGY) + take_damage(power * 1.25e-3, BURN, ENERGY) power -= power * 2.5e-3 //You don't get to do it for free return ..() //You don't get to do it for free diff --git a/code/modules/antagonists/changeling/powers/fakedeath.dm b/code/modules/antagonists/changeling/powers/fakedeath.dm index a4b6b54de3d208..cd748e83159538 100644 --- a/code/modules/antagonists/changeling/powers/fakedeath.dm +++ b/code/modules/antagonists/changeling/powers/fakedeath.dm @@ -20,22 +20,27 @@ if(revive_ready) INVOKE_ASYNC(src, PROC_REF(revive), user) disable_revive(user) // this should be already called via signal, but just incase something wacky happens + return TRUE - else if(enable_fakedeath(user)) - to_chat(user, span_changeling("We begin our stasis, preparing energy to arise once more.")) + var/death_duration_mod = 1 + if(user.has_status_effect(/datum/status_effect/gutted)) + death_duration_mod *= 8 // Anti-megafauna cheese - else - stack_trace("Changeling revive failed to enter fakedeath when it should have been in a valid state to.") + if(!enable_fakedeath(user, duration_modifier = death_duration_mod)) + CRASH("Changeling revive failed to enter fakedeath when it should have been in a valid state to.") + to_chat(user, span_changeling("We begin our stasis, preparing energy to arise once more.")) + if(death_duration_mod > 1) + to_chat(user, span_changeling(span_bold("Our body has sustained severe damage, and will take [death_duration_mod >= 5 ? "far ":""]longer to regenerate."))) return TRUE /// Used to enable fakedeath and register relevant signals / start timers -/datum/action/changeling/fakedeath/proc/enable_fakedeath(mob/living/changeling) +/datum/action/changeling/fakedeath/proc/enable_fakedeath(mob/living/changeling, duration_modifier = 1) if(revive_ready || HAS_TRAIT_FROM(changeling, TRAIT_DEATHCOMA, CHANGELING_TRAIT)) return changeling.fakedeath(CHANGELING_TRAIT) - addtimer(CALLBACK(src, PROC_REF(ready_to_regenerate), changeling), fakedeath_duration, TIMER_UNIQUE) + addtimer(CALLBACK(src, PROC_REF(ready_to_regenerate), changeling), fakedeath_duration * duration_modifier, TIMER_UNIQUE) // Basically, these let the ling exit stasis without giving away their ling-y-ness if revived through other means RegisterSignal(changeling, SIGNAL_REMOVETRAIT(TRAIT_DEATHCOMA), PROC_REF(fakedeath_reset)) RegisterSignal(changeling, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_change)) diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm index 8ba039564da83e..ebf66a7ee15230 100644 --- a/code/modules/antagonists/cult/cult_structures.dm +++ b/code/modules/antagonists/cult/cult_structures.dm @@ -37,26 +37,6 @@ icon_state = "[initial(icon_state)][anchored ? "" : "_off"]" return ..() -/obj/structure/destructible/cult/attack_animal(mob/living/simple_animal/user, list/modifiers) - if(!isconstruct(user)) - return ..() - - var/mob/living/simple_animal/hostile/construct/healer = user - if(!healer.can_repair) - return ..() - - if(atom_integrity >= max_integrity) - to_chat(user, span_cult("You cannot repair [src], as it's undamaged!")) - return - - user.changeNext_move(CLICK_CD_MELEE) - atom_integrity = min(max_integrity, atom_integrity + 5) - Beam(user, icon_state = "sendbeam", time = 0.4 SECONDS) - user.visible_message( - span_danger("[user] repairs [src]."), - span_cult("You repair [src], leaving it at [round(atom_integrity * 100 / max_integrity)]% stability.") - ) - /* * Proc for use with the concealing spell. Hides the building (makes it invisible). */ diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 63b2c6613c3104..240e3617029b4e 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -922,7 +922,12 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0) fail_invoke() log_game("Manifest rune failed - too many summoned ghosts") return list() - notify_ghosts("Manifest rune invoked in [get_area(src)].", 'sound/effects/ghost2.ogg', source = src, header = "Manifest rune") + notify_ghosts( + "Manifest rune invoked in [get_area(src)].", + 'sound/effects/ghost2.ogg', + source = src, + header = "Manifest rune", + ) var/list/ghosts_on_rune = list() for(var/mob/dead/observer/O in T) if(O.client && !is_banned_from(O.ckey, ROLE_CULTIST) && !QDELETED(src) && !(isAdminObserver(O) && (O.client.prefs.toggles & ADMIN_IGNORE_CULT_GHOST)) && !QDELETED(O)) diff --git a/code/modules/antagonists/fugitive/hunters/hunter_gear.dm b/code/modules/antagonists/fugitive/hunters/hunter_gear.dm index acb31c08ac01dd..364a5165f1bdc8 100644 --- a/code/modules/antagonists/fugitive/hunters/hunter_gear.dm +++ b/code/modules/antagonists/fugitive/hunters/hunter_gear.dm @@ -69,7 +69,7 @@ name = "psyker navigation warper" desc = "Uses amplified brainwaves to designate and map a precise transit location for the psyker shuttle." icon_screen = "recharge_comp_on" - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_SET_MACHINE //blind friendly + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON //blind friendly x_offset = 0 y_offset = 11 diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm index f0eff069e89ace..e1955bf32e8aa5 100644 --- a/code/modules/antagonists/heretic/heretic_antag.dm +++ b/code/modules/antagonists/heretic/heretic_antag.dm @@ -66,7 +66,7 @@ PATH_VOID = "blue", PATH_BLADE = "label", // my favorite color is label PATH_COSMIC = "purple", - PATH_KNOCK = "yellow", + PATH_LOCK = "yellow", ) var/static/list/path_to_rune_color = list( PATH_START = COLOR_LIME, @@ -76,7 +76,7 @@ PATH_VOID = COLOR_CYAN, PATH_BLADE = COLOR_SILVER, PATH_COSMIC = COLOR_PURPLE, - PATH_KNOCK = COLOR_YELLOW, + PATH_LOCK = COLOR_YELLOW, ) /datum/antagonist/heretic/Destroy() @@ -259,6 +259,9 @@ /datum/antagonist/heretic/on_body_transfer(mob/living/old_body, mob/living/new_body) . = ..() + if(old_body == new_body) // if they were using a temporary body + return + for(var/knowledge_index in researched_knowledge) var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_index] knowledge.on_lose(old_body, src) diff --git a/code/modules/antagonists/heretic/heretic_knowledge.dm b/code/modules/antagonists/heretic/heretic_knowledge.dm index 0c30a2361b0d22..81130d2f5a0edb 100644 --- a/code/modules/antagonists/heretic/heretic_knowledge.dm +++ b/code/modules/antagonists/heretic/heretic_knowledge.dm @@ -730,7 +730,13 @@ SSblackbox.record_feedback("tally", "heretic_ascended", 1, route) log_heretic_knowledge("[key_name(user)] completed their final ritual at [worldtime2text()].") - notify_ghosts("[user] has completed an ascension ritual!", source = user, action = NOTIFY_ORBIT, header = "A Heretic is Ascending!") + notify_ghosts( + "[user] has completed an ascension ritual!", + source = user, + action = NOTIFY_ORBIT, + header = "A Heretic is Ascending!", + notify_flags = NOTIFY_CATEGORY_DEFAULT, + ) return TRUE /datum/heretic_knowledge/ultimate/cleanup_atoms(list/selected_atoms) diff --git a/code/modules/antagonists/heretic/items/heretic_blades.dm b/code/modules/antagonists/heretic/items/heretic_blades.dm index 6bd8d22fb9e51b..7cce886a14598d 100644 --- a/code/modules/antagonists/heretic/items/heretic_blades.dm +++ b/code/modules/antagonists/heretic/items/heretic_blades.dm @@ -134,12 +134,12 @@ after_use_message = "The Stargazer hears your call..." // Path of Knock's blade -/obj/item/melee/sickly_blade/knock +/obj/item/melee/sickly_blade/lock name = "\improper key blade" desc = "A blade and a key, a key to what? \ What grand gates does it open?" icon_state = "key_blade" inhand_icon_state = "key_blade" - after_use_message = "The Mother of Ants hears your call..." + after_use_message = "The Stewards hear your call..." tool_behaviour = TOOL_CROWBAR toolspeed = 1.3 diff --git a/code/modules/antagonists/heretic/items/keyring.dm b/code/modules/antagonists/heretic/items/keyring.dm index 0498ba9e8a2aad..a6a53bc3cee1a9 100644 --- a/code/modules/antagonists/heretic/items/keyring.dm +++ b/code/modules/antagonists/heretic/items/keyring.dm @@ -1,4 +1,4 @@ -/obj/effect/knock_portal +/obj/effect/lock_portal name = "crack in reality" desc = "A crack in space, impossibly deep and painful to the eyes. Definitely not safe." icon = 'icons/effects/eldritch.dmi' @@ -12,45 +12,51 @@ density = FALSE //so we dont block doors closing layer = OBJ_LAYER //under doors ///The knock portal we teleport to - var/obj/effect/knock_portal/destination + var/obj/effect/lock_portal/destination ///The airlock we are linked to, we delete if it is destroyed var/obj/machinery/door/our_airlock + /// if true the heretic is teleported to a random airlock, nonheretics are sent to the target + var/inverted = FALSE -/obj/effect/knock_portal/Initialize(mapload, target) +/obj/effect/lock_portal/Initialize(mapload, target, invert = FALSE) . = ..() if(target) our_airlock = target RegisterSignal(target, COMSIG_QDELETING, PROC_REF(delete_on_door_delete)) - + var/static/list/loc_connections = list( COMSIG_ATOM_ENTERED = PROC_REF(on_entered), ) AddElement(/datum/element/connect_loc, loc_connections) + inverted = invert ///Deletes us and our destination portal if our_airlock is destroyed -/obj/effect/knock_portal/proc/delete_on_door_delete(datum/source) +/obj/effect/lock_portal/proc/delete_on_door_delete(datum/source) SIGNAL_HANDLER qdel(src) ///Signal handler for when our location is entered, calls teleport on the victim, if their old_loc didnt contain a portal already (to prevent loops) -/obj/effect/knock_portal/proc/on_entered(datum/source, mob/living/loser, atom/old_loc) +/obj/effect/lock_portal/proc/on_entered(datum/source, mob/living/loser, atom/old_loc) SIGNAL_HANDLER if(istype(loser) && !(locate(type) in old_loc)) teleport(loser) -/obj/effect/knock_portal/Destroy() - QDEL_NULL(destination) +/obj/effect/lock_portal/Destroy() + if(!isnull(destination) && !QDELING(destination)) + QDEL_NULL(destination) + + destination = null our_airlock = null return ..() ///Teleports the teleportee, to a random airlock if the teleportee isnt a heretic, or the other portal if they are one -/obj/effect/knock_portal/proc/teleport(mob/living/teleportee) +/obj/effect/lock_portal/proc/teleport(mob/living/teleportee) if(isnull(destination)) //dumbass qdel(src) return //get it? - var/obj/machinery/door/doorstination = IS_HERETIC_OR_MONSTER(teleportee) ? destination.our_airlock : find_random_airlock() + var/obj/machinery/door/doorstination = (inverted ? !IS_HERETIC_OR_MONSTER(teleportee) : IS_HERETIC_OR_MONSTER(teleportee)) ? destination.our_airlock : find_random_airlock() if(!do_teleport(teleportee, get_turf(doorstination), channel = TELEPORT_CHANNEL_MAGIC)) return @@ -61,7 +67,7 @@ INVOKE_ASYNC(src, PROC_REF(async_opendoor), doorstination) ///Returns a random airlock on the same Z level as our portal, that isnt our airlock -/obj/effect/knock_portal/proc/find_random_airlock() +/obj/effect/lock_portal/proc/find_random_airlock() var/list/turf/possible_destinations = list() for(var/obj/airlock as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door/airlock)) if(airlock.z != z) @@ -72,7 +78,7 @@ return pick(possible_destinations) ///Asynchronous proc to unbolt, then open the passed door -/obj/effect/knock_portal/proc/async_opendoor(obj/machinery/door/door) +/obj/effect/lock_portal/proc/async_opendoor(obj/machinery/door/door) if(istype(door, /obj/machinery/door/airlock)) //they can create portals on ANY door, but we should unlock airlocks so they can actually open var/obj/machinery/door/airlock/as_airlock = door as_airlock.unbolt() @@ -83,11 +89,13 @@ ///List of IDs this card consumed var/list/obj/item/card/id/fused_ids = list() ///The first portal in the portal pair, so we can clear it later - var/obj/effect/knock_portal/portal_one + var/obj/effect/lock_portal/portal_one ///The second portal in the portal pair, so we can clear it later - var/obj/effect/knock_portal/portal_two + var/obj/effect/lock_portal/portal_two ///The first door we are linking in the pair, so we can create a portal pair var/datum/weakref/link + /// are our created portals inverted? (heretics get sent to a random airlock, crew get sent to the target) + var/inverted = FALSE /obj/item/card/id/advanced/heretic/examine(mob/user) . = ..() @@ -97,6 +105,7 @@ . += span_hypnophrase("Using an ID on this will consume it and allow you to copy its accesses.") . += span_hypnophrase("Using this in-hand allows you to change its appearance.") . += span_hypnophrase("Using this on a pair of doors, allows you to link them together. Entering one door will transport you to the other, while heathens are instead teleported to a random airlock.") + . += span_hypnophrase("Ctrl-clicking the ID, makes the ID make inverted portals instead, which teleport you onto a random airlock onstation, while heathens are teleported to the destination.") /obj/item/card/id/advanced/heretic/attack_self(mob/user) . = ..() @@ -109,6 +118,13 @@ var/obj/item/card/id/card = fused_ids[cardname] shapeshift(card) +/obj/item/card/id/advanced/heretic/CtrlClick(mob/user) + . = ..() + if(!IS_HERETIC(user)) + return + inverted = !inverted + balloon_alert(user, "[inverted ? "now" : "no longer"] creating inverted rifts") + ///Changes our appearance to the passed ID card /obj/item/card/id/advanced/heretic/proc/shapeshift(obj/item/card/id/advanced/card) trim = card.trim @@ -124,7 +140,7 @@ ///Deletes and nulls our portal pair /obj/item/card/id/advanced/heretic/proc/clear_portals() QDEL_NULL(portal_one) - QDEL_NULL(portal_two) + QDEL_NULL(portal_two) ///Clears portal references /obj/item/card/id/advanced/heretic/proc/clear_portal_refs() @@ -138,9 +154,9 @@ if(portal_one || portal_two) clear_portals() message += ", previous cleared" - - portal_one = new(get_turf(door2), door2) - portal_two = new(get_turf(door1), door1) + + portal_one = new(get_turf(door2), door2, inverted) + portal_two = new(get_turf(door1), door1, inverted) portal_one.destination = portal_two RegisterSignal(portal_one, COMSIG_QDELETING, PROC_REF(clear_portal_refs)) //we only really need to register one because they already qdel both portals if one is destroyed portal_two.destination = portal_one @@ -159,7 +175,7 @@ . = ..() if(!proximity_flag || !IS_HERETIC(user)) return - if(istype(target, /obj/effect/knock_portal)) + if(istype(target, /obj/effect/lock_portal)) clear_portals() return diff --git a/code/modules/antagonists/heretic/items/lintel.dm b/code/modules/antagonists/heretic/items/labyrinth_handbook.dm similarity index 83% rename from code/modules/antagonists/heretic/items/lintel.dm rename to code/modules/antagonists/heretic/items/labyrinth_handbook.dm index 140453842c090c..b3e3649763fd58 100644 --- a/code/modules/antagonists/heretic/items/lintel.dm +++ b/code/modules/antagonists/heretic/items/labyrinth_handbook.dm @@ -1,5 +1,5 @@ /obj/effect/forcefield/wizard/heretic - name = "consecrated lintel" + name = "labyrinth pages" desc = "A field of papers flying in the air, repulsing heathens with impossible force." icon_state = "lintel" initial_duration = 8 SECONDS @@ -13,11 +13,11 @@ visible_message(span_danger("[src] repulses [bumpee] in a storm of paper!")) ///A heretic item that spawns a barrier at the clicked turf, 3 uses -/obj/item/heretic_lintel - name = "consecrated book" - desc = "Some kind of book, its contents make your head hurt. The material is not known to you and it seems to shift and twist unnaturally." +/obj/item/heretic_labyrinth_handbook + name = "labyrinth handbook" + desc = "A book containing the laws and regulations of the Locked Labyrinth, penned on an unknown substance. Its pages squirm and strain, looking to lash out and escape." icon = 'icons/obj/service/library.dmi' - icon_state = "hereticlintel" + icon_state = "heretichandbook" force = 10 damtype = BURN worn_icon_state = "book" @@ -34,14 +34,14 @@ ///how many uses do we have left var/uses = 3 -/obj/item/heretic_lintel/examine(mob/user) +/obj/item/heretic_labyrinth_handbook/examine(mob/user) . = ..() if(!IS_HERETIC_OR_MONSTER(user)) return . += span_hypnophrase("Materializes a barrier upon any tile in sight, which only you can pass through. Lasts 8 seconds.") . += span_hypnophrase("It has [uses] uses left.") -/obj/item/heretic_lintel/afterattack(atom/target, mob/user, proximity_flag) +/obj/item/heretic_labyrinth_handbook/afterattack(atom/target, mob/user, proximity_flag) . = ..() if(IS_HERETIC(user)) var/turf/turf_target = get_turf(target) diff --git a/code/modules/antagonists/heretic/knowledge/ash_lore.dm b/code/modules/antagonists/heretic/knowledge/ash_lore.dm index 52e25f6a8b17b2..63d317535ab9be 100644 --- a/code/modules/antagonists/heretic/knowledge/ash_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/ash_lore.dm @@ -212,7 +212,12 @@ /datum/heretic_knowledge/ultimate/ash_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) . = ..() - priority_announce("[generate_heretic_text()] Fear the blaze, for the Ashlord, [user.real_name] has ascended! The flames shall consume all! [generate_heretic_text()]","[generate_heretic_text()]", ANNOUNCER_SPANOMALIES) + priority_announce( + text = "[generate_heretic_text()] Fear the blaze, for the Ashlord, [user.real_name] has ascended! The flames shall consume all! [generate_heretic_text()]", + title = "[generate_heretic_text()]", + sound = ANNOUNCER_SPANOMALIES, + color_override = "pink", + ) var/datum/action/cooldown/spell/fire_sworn/circle_spell = new(user.mind) circle_spell.Grant(user) diff --git a/code/modules/antagonists/heretic/knowledge/blade_lore.dm b/code/modules/antagonists/heretic/knowledge/blade_lore.dm index 55102c12c79c85..e3117045f74a81 100644 --- a/code/modules/antagonists/heretic/knowledge/blade_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/blade_lore.dm @@ -408,7 +408,12 @@ /datum/heretic_knowledge/ultimate/blade_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) . = ..() - priority_announce("[generate_heretic_text()] Master of blades, the Torn Champion's disciple, [user.real_name] has ascended! Their steel is that which will cut reality in a maelstom of silver! [generate_heretic_text()]","[generate_heretic_text()]", ANNOUNCER_SPANOMALIES) + priority_announce( + text = "[generate_heretic_text()] Master of blades, the Torn Champion's disciple, [user.real_name] has ascended! Their steel is that which will cut reality in a maelstom of silver! [generate_heretic_text()]", + title = "[generate_heretic_text()]", + sound = ANNOUNCER_SPANOMALIES, + color_override = "pink", + ) user.client?.give_award(/datum/award/achievement/misc/blade_ascension, user) ADD_TRAIT(user, TRAIT_NEVER_WOUNDED, name) RegisterSignal(user, COMSIG_HERETIC_BLADE_ATTACK, PROC_REF(on_eldritch_blade)) diff --git a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm index 4607d78ff5c865..508d142fa27926 100644 --- a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm @@ -248,7 +248,7 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targetting/attack/star_gazer + /datum/pet_command/point_targeting/attack/star_gazer ) /datum/heretic_knowledge/ultimate/cosmic_final/is_valid_sacrifice(mob/living/carbon/human/sacrifice) @@ -260,7 +260,12 @@ /datum/heretic_knowledge/ultimate/cosmic_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) . = ..() - priority_announce("[generate_heretic_text()] A Star Gazer has arrived into the station, [user.real_name] has ascended! This station is the domain of the Cosmos! [generate_heretic_text()]","[generate_heretic_text()]", ANNOUNCER_SPANOMALIES) + priority_announce( + text = "[generate_heretic_text()] A Star Gazer has arrived into the station, [user.real_name] has ascended! This station is the domain of the Cosmos! [generate_heretic_text()]", + title = "[generate_heretic_text()]", + sound = ANNOUNCER_SPANOMALIES, + color_override = "pink", + ) var/mob/living/basic/heretic_summon/star_gazer/star_gazer_mob = new /mob/living/basic/heretic_summon/star_gazer(loc) star_gazer_mob.maxHealth = INFINITY star_gazer_mob.health = INFINITY diff --git a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm index f3f6d971353810..d9cc40712826d4 100644 --- a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm @@ -317,7 +317,12 @@ /datum/heretic_knowledge/ultimate/flesh_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) . = ..() - priority_announce("[generate_heretic_text()] Ever coiling vortex. Reality unfolded. ARMS OUTREACHED, THE LORD OF THE NIGHT, [user.real_name] has ascended! Fear the ever twisting hand! [generate_heretic_text()]", "[generate_heretic_text()]", ANNOUNCER_SPANOMALIES) + priority_announce( + text = "[generate_heretic_text()] Ever coiling vortex. Reality unfolded. ARMS OUTREACHED, THE LORD OF THE NIGHT, [user.real_name] has ascended! Fear the ever twisting hand! [generate_heretic_text()]", + title = "[generate_heretic_text()]", + sound = ANNOUNCER_SPANOMALIES, + color_override = "pink", + ) var/datum/action/cooldown/spell/shapeshift/shed_human_form/worm_spell = new(user.mind) worm_spell.Grant(user) diff --git a/code/modules/antagonists/heretic/knowledge/knock_lore.dm b/code/modules/antagonists/heretic/knowledge/lock_lore.dm similarity index 59% rename from code/modules/antagonists/heretic/knowledge/knock_lore.dm rename to code/modules/antagonists/heretic/knowledge/lock_lore.dm index 6879f527b6b8b4..25f58c879dd881 100644 --- a/code/modules/antagonists/heretic/knowledge/knock_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/lock_lore.dm @@ -1,17 +1,17 @@ /** - * # The path of Knock. + * # The path of Lock. * * Goes as follows: * - * A Locksmith’s Secret - * Grasp of Knock + * A Steward's Secret + * Grasp of Lock * > Sidepaths: * Ashen Eyes * Codex Cicatrix * Key Keeper’s Burden * - * Rite Of Passage - * Mark Of Knock + * Concierge's Rite + * Mark Of Lock * Ritual of Knowledge * Burglar's Finesse * > Sidepaths: @@ -21,26 +21,26 @@ * Opening Blade * Caretaker’s Last Refuge * - * Many secrets behind the Spider Door + * Unlock the Labyrinth */ /datum/heretic_knowledge/limited_amount/starting/base_knock - name = "A Locksmith’s Secret" - desc = "Opens up the Path of Knock to you. \ + name = "A Steward's Secret" + desc = "Opens up the Path of Lock to you. \ Allows you to transmute a knife and a crowbar into a Key Blade. \ You can only create two at a time and they function as fast crowbars. \ In addition, they can fit into utility belts." - gain_text = "The Knock permits no seal and no isolation. It thrusts us gleefully out of the safety of ignorance." - next_knowledge = list(/datum/heretic_knowledge/knock_grasp) + gain_text = "The Locked Labyrinth leads to freedom. But only the trapped Stewards know the correct path." + next_knowledge = list(/datum/heretic_knowledge/lock_grasp) required_atoms = list( /obj/item/knife = 1, /obj/item/crowbar = 1, ) - result_atoms = list(/obj/item/melee/sickly_blade/knock) + result_atoms = list(/obj/item/melee/sickly_blade/lock) limit = 2 - route = PATH_KNOCK + route = PATH_LOCK -/datum/heretic_knowledge/knock_grasp - name = "Grasp of Knock" +/datum/heretic_knowledge/lock_grasp + name = "Grasp of Lock" desc = "Your mansus grasp allows you to access anything! Right click on an airlock or a locker to force it open. \ DNA locks on mechs will be removed, and any pilot will be ejected. Works on consoles. \ Makes a distinctive knocking sound on use." @@ -51,24 +51,24 @@ /datum/heretic_knowledge/codex_cicatrix, ) cost = 1 - route = PATH_KNOCK + route = PATH_LOCK -/datum/heretic_knowledge/knock_grasp/on_gain(mob/user, datum/antagonist/heretic/our_heretic) +/datum/heretic_knowledge/lock_grasp/on_gain(mob/user, datum/antagonist/heretic/our_heretic) RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY, PROC_REF(on_secondary_mansus_grasp)) RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp)) -/datum/heretic_knowledge/knock_grasp/on_lose(mob/user, datum/antagonist/heretic/our_heretic) +/datum/heretic_knowledge/lock_grasp/on_lose(mob/user, datum/antagonist/heretic/our_heretic) UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY) UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK) -/datum/heretic_knowledge/knock_grasp/proc/on_mansus_grasp(mob/living/source, mob/living/target) +/datum/heretic_knowledge/lock_grasp/proc/on_mansus_grasp(mob/living/source, mob/living/target) SIGNAL_HANDLER var/obj/item/clothing/under/suit = target.get_item_by_slot(ITEM_SLOT_ICLOTHING) if(istype(suit) && suit.adjusted == NORMAL_STYLE) suit.toggle_jumpsuit_adjust() suit.update_appearance() -/datum/heretic_knowledge/knock_grasp/proc/on_secondary_mansus_grasp(mob/living/source, atom/target) +/datum/heretic_knowledge/lock_grasp/proc/on_secondary_mansus_grasp(mob/living/source, atom/target) SIGNAL_HANDLER if(ismecha(target)) @@ -98,7 +98,7 @@ It functions the same as an ID Card, but attacking it with an ID card fuses it and gains its access. \ You can use it in-hand to change its form to a card you fused. \ Does not preserve the card used in the ritual." - gain_text = "Gateways shall open before me, my very will ensnaring reality." + gain_text = "The Keeper sneered. \"These plastic rectangles are a mockery of keys, and I curse every door that desires them.\"" adds_sidepath_points = 1 required_atoms = list( /obj/item/storage/wallet = 1, @@ -106,64 +106,64 @@ /obj/item/card/id = 1, ) result_atoms = list(/obj/item/card/id/advanced/heretic) - next_knowledge = list(/datum/heretic_knowledge/limited_amount/rite_of_passage) + next_knowledge = list(/datum/heretic_knowledge/limited_amount/concierge_rite) cost = 1 - route = PATH_KNOCK + route = PATH_LOCK -/datum/heretic_knowledge/limited_amount/rite_of_passage // item that creates 3 max at a time heretic only barriers, probably should limit to 1 only, holy people can also pass - name = "Rite Of Passage" - desc = "Allows you to transmute a white crayon, a wooden plank, and a multitool to create a Consecrated Book. \ +/datum/heretic_knowledge/limited_amount/concierge_rite // item that creates 3 max at a time heretic only barriers, probably should limit to 1 only, holy people can also pass + name = "Concierge's Rite" + desc = "Allows you to transmute a white crayon, a wooden plank, and a multitool to create a Labyrinth Handbook. \ It can materialize a barricade at range that only you and people resistant to magic can pass. 3 uses." - gain_text = "With this I can repel those that intend me harm." + gain_text = "The Concierge scribbled my name into the Handbook. \"Welcome to your new home, fellow Steward.\"" required_atoms = list( /obj/item/toy/crayon/white = 1, /obj/item/stack/sheet/mineral/wood = 1, /obj/item/multitool = 1, ) - result_atoms = list(/obj/item/heretic_lintel) - next_knowledge = list(/datum/heretic_knowledge/mark/knock_mark) + result_atoms = list(/obj/item/heretic_labyrinth_handbook) + next_knowledge = list(/datum/heretic_knowledge/mark/lock_mark) cost = 1 - route = PATH_KNOCK + route = PATH_LOCK -/datum/heretic_knowledge/mark/knock_mark - name = "Mark of Knock" - desc = "Your Mansus Grasp now applies the Mark of Knock. \ +/datum/heretic_knowledge/mark/lock_mark + name = "Mark of Lock" + desc = "Your Mansus Grasp now applies the Mark of Lock. \ Attack a marked person to bar them from all passages for the duration of the mark. \ This will make it so that they have no access whatsoever, even public access doors will reject them." - gain_text = "Their requests for passage will remain unheeded." - next_knowledge = list(/datum/heretic_knowledge/knowledge_ritual/knock) - route = PATH_KNOCK - mark_type = /datum/status_effect/eldritch/knock + gain_text = "The Gatekeeper was a corrupt Steward. She hindered her fellows for her own twisted amusement." + next_knowledge = list(/datum/heretic_knowledge/knowledge_ritual/lock) + route = PATH_LOCK + mark_type = /datum/status_effect/eldritch/lock -/datum/heretic_knowledge/knowledge_ritual/knock +/datum/heretic_knowledge/knowledge_ritual/lock next_knowledge = list(/datum/heretic_knowledge/spell/burglar_finesse) - route = PATH_KNOCK + route = PATH_LOCK /datum/heretic_knowledge/spell/burglar_finesse name = "Burglar's Finesse" desc = "Grants you Burglar's Finesse, a single-target spell \ that puts a random item from the victims backpack into your hand." - gain_text = "Their trinkets will be mine, as will their lives in due time." + gain_text = "Consorting with Burglar spirits is frowned upon, but a Steward will always want to learn about new doors." adds_sidepath_points = 1 next_knowledge = list( /datum/heretic_knowledge/spell/apetra_vulnera, /datum/heretic_knowledge/spell/opening_blast, - /datum/heretic_knowledge/blade_upgrade/flesh/knock, + /datum/heretic_knowledge/blade_upgrade/flesh/lock, ) spell_to_add = /datum/action/cooldown/spell/pointed/burglar_finesse cost = 2 - route = PATH_KNOCK + route = PATH_LOCK -/datum/heretic_knowledge/blade_upgrade/flesh/knock //basically a chance-based weeping avulsion version of the former +/datum/heretic_knowledge/blade_upgrade/flesh/lock //basically a chance-based weeping avulsion version of the former name = "Opening Blade" desc = "Your blade has a chance to cause a weeping avulsion on attack." - gain_text = "The power of my patron courses through my blade, willing their very flesh to part." + gain_text = "The Pilgrim-Surgeon was not an Steward. Nonetheless, its blades and sutures proved a match for their keys." next_knowledge = list(/datum/heretic_knowledge/spell/caretaker_refuge) - route = PATH_KNOCK + route = PATH_LOCK wound_type = /datum/wound/slash/flesh/critical var/chance = 35 -/datum/heretic_knowledge/blade_upgrade/flesh/knock/do_melee_effects(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade) +/datum/heretic_knowledge/blade_upgrade/flesh/lock/do_melee_effects(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade) if(prob(chance)) return ..() @@ -172,29 +172,29 @@ desc = "Gives you a spell that makes you transparent and not dense. Cannot be used near living sentient beings. \ While in refuge, you cannot use your hands or spells, and you are immune to slowdown. \ You are invincible but unable to harm anything. Cancelled by being hit with an anti-magic item." - gain_text = "Then I saw my my own reflection cascaded mind-numbingly enough times that I was but a haze." + gain_text = "Jealously, the Guard and the Hound hunted me. But I unlocked my form, and was but a haze, untouchable." adds_sidepath_points = 1 - next_knowledge = list(/datum/heretic_knowledge/ultimate/knock_final) - route = PATH_KNOCK + next_knowledge = list(/datum/heretic_knowledge/ultimate/lock_final) + route = PATH_LOCK spell_to_add = /datum/action/cooldown/spell/caretaker cost = 1 -/datum/heretic_knowledge/ultimate/knock_final - name = "Many secrets behind the Spider Door" +/datum/heretic_knowledge/ultimate/lock_final + name = "Unlock the Labyrinth" desc = "The ascension ritual of the Path of Knock. \ Bring 3 corpses without organs in their torso to a transmutation rune to complete the ritual. \ When completed, you gain the ability to transform into empowered eldritch creatures \ - and in addition, create a tear to the Spider Door; \ + and in addition, create a tear to the Labyrinth's heart; \ a tear in reality located at the site of this ritual. \ Eldritch creatures will endlessly pour from this rift \ who are bound to obey your instructions." - gain_text = "With her knowledge, and what I had seen, I knew what to do. \ - I had to open the gates, with the holes in my foes as Ways! \ - Reality will soon be torn, the Spider Gate opened! WITNESS ME!" + gain_text = "The Stewards guided me, and I guided them. \ + My foes were the Locks and my blades were the Key! \ + The Labyrinth will be Locked no more, and freedom will be ours! WITNESS US!" required_atoms = list(/mob/living/carbon/human = 3) - route = PATH_KNOCK + route = PATH_LOCK -/datum/heretic_knowledge/ultimate/knock_final/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc) +/datum/heretic_knowledge/ultimate/lock_final/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc) . = ..() if(!.) return FALSE @@ -214,17 +214,22 @@ return FALSE return TRUE -/datum/heretic_knowledge/ultimate/knock_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) +/datum/heretic_knowledge/ultimate/lock_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) . = ..() - priority_announce("Delta-class dimensional anomaly detec[generate_heretic_text()] Reality rended, torn. Gates open, doors open, [user.real_name] has ascended! Fear the tide! [generate_heretic_text()]", "Centra[generate_heretic_text()]", ANNOUNCER_SPANOMALIES) - user.client?.give_award(/datum/award/achievement/misc/knock_ascension, user) + priority_announce( + text = "Delta-class dimensional anomaly detec[generate_heretic_text()] Reality rended, torn. Gates open, doors open, [user.real_name] has ascended! Fear the tide! [generate_heretic_text()]", + title = "[generate_heretic_text()]", + sound = ANNOUNCER_SPANOMALIES, + color_override = "pink", + ) + user.client?.give_award(/datum/award/achievement/misc/lock_ascension, user) // buffs var/datum/action/cooldown/spell/shapeshift/eldritch/ascension/transform_spell = new(user.mind) transform_spell.Grant(user) - user.client?.give_award(/datum/award/achievement/misc/knock_ascension, user) + user.client?.give_award(/datum/award/achievement/misc/lock_ascension, user) var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user) - var/datum/heretic_knowledge/blade_upgrade/flesh/knock/blade_upgrade = heretic_datum.get_knowledge(/datum/heretic_knowledge/blade_upgrade/flesh/knock) + var/datum/heretic_knowledge/blade_upgrade/flesh/lock/blade_upgrade = heretic_datum.get_knowledge(/datum/heretic_knowledge/blade_upgrade/flesh/lock) blade_upgrade.chance += 30 - new /obj/structure/knock_tear(loc, user.mind) + new /obj/structure/lock_tear(loc, user.mind) diff --git a/code/modules/antagonists/heretic/knowledge/rust_lore.dm b/code/modules/antagonists/heretic/knowledge/rust_lore.dm index 84f128b5cfcf9f..45966e21c5cb61 100644 --- a/code/modules/antagonists/heretic/knowledge/rust_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/rust_lore.dm @@ -264,7 +264,12 @@ /datum/heretic_knowledge/ultimate/rust_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) . = ..() - priority_announce("[generate_heretic_text()] Fear the decay, for the Rustbringer, [user.real_name] has ascended! None shall escape the corrosion! [generate_heretic_text()]","[generate_heretic_text()]", ANNOUNCER_SPANOMALIES) + priority_announce( + text = "[generate_heretic_text()] Fear the decay, for the Rustbringer, [user.real_name] has ascended! None shall escape the corrosion! [generate_heretic_text()]", + title = "[generate_heretic_text()]", + sound = ANNOUNCER_SPANOMALIES, + color_override = "pink", + ) new /datum/rust_spread(loc) RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) RegisterSignal(user, COMSIG_LIVING_LIFE, PROC_REF(on_life)) diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm index 983bbee32c600f..69b52953283f20 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm @@ -34,9 +34,9 @@ GLOBAL_LIST_EMPTY(heretic_sacrifice_landmarks) name = "rust heretic sacrifice landmark" for_heretic_path = PATH_RUST -/obj/effect/landmark/heretic/knock - name = "knock heretic sacrifice landmark" - for_heretic_path = PATH_KNOCK +/obj/effect/landmark/heretic/lock + name = "lock heretic sacrifice landmark" + for_heretic_path = PATH_LOCK // A fluff signpost object that doesn't teleport you somewhere when you touch it. /obj/structure/no_effect_signpost @@ -111,7 +111,7 @@ GLOBAL_LIST_EMPTY(heretic_sacrifice_landmarks) ambience_index = AMBIENCE_REEBE sound_environment = SOUND_ENVIRONMENT_SEWER_PIPE -/area/centcom/heretic_sacrifice/knock - name = "Mansus Knock Gate" +/area/centcom/heretic_sacrifice/lock + name = "Mansus Lock Gate" ambience_index = AMBIENCE_DANGER sound_environment = SOUND_ENVIRONMENT_PSYCHOTIC diff --git a/code/modules/antagonists/heretic/knowledge/side_knock_flesh.dm b/code/modules/antagonists/heretic/knowledge/side_lock_flesh.dm similarity index 100% rename from code/modules/antagonists/heretic/knowledge/side_knock_flesh.dm rename to code/modules/antagonists/heretic/knowledge/side_lock_flesh.dm diff --git a/code/modules/antagonists/heretic/knowledge/void_lore.dm b/code/modules/antagonists/heretic/knowledge/void_lore.dm index a5e21472517f37..95540636bce7c9 100644 --- a/code/modules/antagonists/heretic/knowledge/void_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/void_lore.dm @@ -202,7 +202,12 @@ /datum/heretic_knowledge/ultimate/void_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) . = ..() - priority_announce("[generate_heretic_text()] The nobleman of void [user.real_name] has arrived, stepping along the Waltz that ends worlds! [generate_heretic_text()]","[generate_heretic_text()]", ANNOUNCER_SPANOMALIES) + priority_announce( + text = "[generate_heretic_text()] The nobleman of void [user.real_name] has arrived, stepping along the Waltz that ends worlds! [generate_heretic_text()]", + title = "[generate_heretic_text()]", + sound = ANNOUNCER_SPANOMALIES, + color_override = "pink", + ) user.client?.give_award(/datum/award/achievement/misc/void_ascension, user) ADD_TRAIT(user, TRAIT_RESISTLOWPRESSURE, MAGIC_TRAIT) diff --git a/code/modules/antagonists/heretic/magic/ascended_shapeshift.dm b/code/modules/antagonists/heretic/magic/ascended_shapeshift.dm index e11053fd3e3ba7..18e8d26fecc60f 100644 --- a/code/modules/antagonists/heretic/magic/ascended_shapeshift.dm +++ b/code/modules/antagonists/heretic/magic/ascended_shapeshift.dm @@ -26,7 +26,7 @@ monster.melee_damage_lower = max((monster.melee_damage_lower * 2), 40) monster.melee_damage_upper = monster.melee_damage_upper / 2 monster.transform *= 1.5 - monster.AddElement(/datum/element/wall_smasher, strength_flag = ENVIRONMENT_SMASH_RWALLS) + monster.AddElement(/datum/element/wall_tearer) /datum/action/cooldown/spell/shapeshift/eldritch/ascension/do_unshapeshift(mob/living/caster) . = ..() diff --git a/code/modules/antagonists/heretic/status_effects/mark_effects.dm b/code/modules/antagonists/heretic/status_effects/mark_effects.dm index 068570f76c7b17..4cdc29288c481d 100644 --- a/code/modules/antagonists/heretic/status_effects/mark_effects.dm +++ b/code/modules/antagonists/heretic/status_effects/mark_effects.dm @@ -247,16 +247,16 @@ owner.Paralyze(2 SECONDS) return ..() -// MARK OF KNOCK +// MARK OF LOCK -/datum/status_effect/eldritch/knock +/datum/status_effect/eldritch/lock effect_icon_state = "emark7" duration = 10 SECONDS -/datum/status_effect/eldritch/knock/on_apply() +/datum/status_effect/eldritch/lock/on_apply() . = ..() ADD_TRAIT(owner, TRAIT_ALWAYS_NO_ACCESS, STATUS_EFFECT_TRAIT) -/datum/status_effect/eldritch/knock/on_remove() +/datum/status_effect/eldritch/lock/on_remove() REMOVE_TRAIT(owner, TRAIT_ALWAYS_NO_ACCESS, STATUS_EFFECT_TRAIT) return ..() diff --git a/code/modules/antagonists/heretic/structures/knock_final.dm b/code/modules/antagonists/heretic/structures/lock_final.dm similarity index 88% rename from code/modules/antagonists/heretic/structures/knock_final.dm rename to code/modules/antagonists/heretic/structures/lock_final.dm index f7d0d1a9ea7b00..c823206293121a 100644 --- a/code/modules/antagonists/heretic/structures/knock_final.dm +++ b/code/modules/antagonists/heretic/structures/lock_final.dm @@ -1,4 +1,4 @@ -/obj/structure/knock_tear +/obj/structure/lock_tear name = "???" desc = "It stares back. Theres no reason to remain. Run." max_integrity = INFINITE @@ -24,7 +24,7 @@ /mob/living/basic/heretic_summon/star_gazer, ) -/obj/structure/knock_tear/Initialize(mapload, datum/mind/ascendant_mind) +/obj/structure/lock_tear/Initialize(mapload, datum/mind/ascendant_mind) . = ..() transform *= 3 if(isnull(monster_types)) @@ -36,7 +36,7 @@ INVOKE_ASYNC(src, PROC_REF(poll_ghosts)) /// Ask ghosts if they want to make some noise -/obj/structure/knock_tear/proc/poll_ghosts() +/obj/structure/lock_tear/proc/poll_ghosts() var/list/candidates = poll_ghost_candidates("Would you like to be a random eldritch monster attacking the crew?", ROLE_SENTIENCE, ROLE_SENTIENCE, 10 SECONDS, POLL_IGNORE_HERETIC_MONSTER) while(LAZYLEN(candidates)) var/mob/dead/observer/candidate = pick_n_take(candidates) @@ -44,7 +44,7 @@ gathering_candidates = FALSE /// Destroy the rift if you kill the heretic -/obj/structure/knock_tear/proc/end_madness(datum/former_master) +/obj/structure/lock_tear/proc/end_madness(datum/former_master) SIGNAL_HANDLER var/turf/our_turf = get_turf(src) playsound(our_turf, 'sound/magic/castsummon.ogg', vol = 100, vary = TRUE) @@ -53,20 +53,20 @@ new /obj/effect/temp_visual/destabilising_tear(our_turf) qdel(src) -/obj/structure/knock_tear/attack_ghost(mob/user) +/obj/structure/lock_tear/attack_ghost(mob/user) . = ..() if(. || gathering_candidates) return ghost_to_monster(user) -/obj/structure/knock_tear/examine(mob/user) +/obj/structure/lock_tear/examine(mob/user) . = ..() if (!isobserver(user) || gathering_candidates) return . += span_notice("You can use this to enter the world as a foul monster.") /// Turn a ghost into an 'orrible beast -/obj/structure/knock_tear/proc/ghost_to_monster(mob/dead/observer/user, should_ask = TRUE) +/obj/structure/lock_tear/proc/ghost_to_monster(mob/dead/observer/user, should_ask = TRUE) if(should_ask) var/ask = tgui_alert(user, "Become a monster?", "Ascended Rift", list("Yes", "No")) if(ask != "Yes" || QDELETED(src) || QDELETED(user)) @@ -86,10 +86,10 @@ kill_all_your_friends.completed = TRUE woohoo_free_antag.objectives += kill_all_your_friends -/obj/structure/knock_tear/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) +/obj/structure/lock_tear/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) return FALSE -/obj/structure/knock_tear/Destroy(force) +/obj/structure/lock_tear/Destroy(force) if(ascendee) ascendee = null return ..() diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index 9f527e0184ad13..a249bae7acb6ae 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -622,7 +622,6 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) name = "Robotic Factory (Removes Shunting)" description = "Build a machine anywhere, using expensive nanomachines, that will slowly create loyal cyborgs for you." // Skyrat edit cost = 100 - one_purchase = TRUE power_type = /datum/action/innate/ai/place_transformer unlock_text = span_notice("You make contact with Space Amazon and request a robotics factory for delivery.") unlock_sound = 'sound/machines/ping.ogg' @@ -655,9 +654,11 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) var/obj/machinery/transformer_rp/conveyor = new(T) //SKYRAT EDIT CHANGE - SILLICONQOL - ORIGINAL: var/obj/machinery/transformer/conveyor = new(T) conveyor.master_ai = owner playsound(T, 'sound/effects/phasein.ogg', 100, TRUE) - owner_AI.can_shunt = FALSE - to_chat(owner, span_warning("You are no longer able to shunt your core to APCs.")) + if(owner_AI.can_shunt) //prevent repeated messages + owner_AI.can_shunt = FALSE + to_chat(owner, span_warning("You are no longer able to shunt your core to APCs.")) adjust_uses(-1) + active = FALSE /mob/living/silicon/ai/proc/remove_transformer_image(client/C, image/I, turf/T) if(C && I.loc == T) @@ -1024,7 +1025,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) say_name = params["name"] /datum/ai_module/utility/emag - name = "Targetted Safeties Override" + name = "Targeted Safeties Override" description = "Allows you to disable the safeties of any machinery on the station, provided you can access it." cost = 20 power_type = /datum/action/innate/ai/ranged/emag @@ -1032,7 +1033,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) unlock_sound = SFX_SPARKS /datum/action/innate/ai/ranged/emag - name = "Targetted Safeties Override" + name = "Targeted Safeties Override" desc = "Allows you to effectively emag anything you click on." button_icon = 'icons/obj/card.dmi' button_icon_state = "emag" diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm b/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm index 0b6a28c3bcac79..1cd6327cbe3e09 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm @@ -464,6 +464,7 @@ GLOBAL_VAR(station_nuke_source) source = src, header = "Nuke Armed", action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_DEFAULT, ) update_appearance() diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm index 9bff5c06b24721..eeb4d255bf6dbd 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm @@ -73,7 +73,14 @@ GLOBAL_LIST_EMPTY(jam_on_wardec) war_was_declared(memo = war_declaration) /obj/item/nuclear_challenge/proc/war_was_declared(mob/living/user, memo) - priority_announce(memo, title = "Declaration of War", sound = 'sound/machines/alarm.ogg', has_important_message = TRUE, sender_override = "Nuclear Operative Outpost", color_override = "red") + priority_announce( + text = memo, + title = "Declaration of War", + sound = 'sound/machines/alarm.ogg', + has_important_message = TRUE, + sender_override = "Nuclear Operative Outpost", + color_override = "red", + ) if(user) to_chat(user, "You've attracted the attention of powerful forces within the syndicate. \ A bonus bundle of telecrystals has been granted to your team. Great things await you if you complete the mission.") @@ -168,7 +175,14 @@ GLOBAL_LIST_EMPTY(jam_on_wardec) return #endif - priority_announce(memo, title = "Declaration of War", sound = 'sound/machines/alarm.ogg', has_important_message = TRUE, sender_override = "Nuclear Operative Outpost", color_override = "red") + priority_announce( + text = memo, + title = "Declaration of War", + sound = 'sound/machines/alarm.ogg', + has_important_message = TRUE, + sender_override = "Nuclear Operative Outpost", + color_override = "red", + ) /obj/item/nuclear_challenge/literally_just_does_the_message/distribute_tc() return diff --git a/code/modules/antagonists/pirate/pirate_event.dm b/code/modules/antagonists/pirate/pirate_event.dm index 2a2162fda68bdc..c66130748fb8f5 100644 --- a/code/modules/antagonists/pirate/pirate_event.dm +++ b/code/modules/antagonists/pirate/pirate_event.dm @@ -80,9 +80,19 @@ var/mob/our_candidate = candidates[1] var/mob/spawned_mob = spawner.create_from_ghost(our_candidate) candidates -= our_candidate - notify_ghosts("The [chosen_gang.ship_name] has an object of interest: [spawned_mob]!", source = spawned_mob, action = NOTIFY_ORBIT, header="Pirates!") + notify_ghosts( + "The [chosen_gang.ship_name] has an object of interest: [spawned_mob]!", + source = spawned_mob, + action = NOTIFY_ORBIT, + header = "Pirates!", + ) else - notify_ghosts("The [chosen_gang.ship_name] has an object of interest: [spawner]!", source = spawner, action = NOTIFY_ORBIT, header="Pirate Spawn Here!") + notify_ghosts( + "The [chosen_gang.ship_name] has an object of interest: [spawner]!", + source = spawner, + action = NOTIFY_ORBIT, + header = "Pirate Spawn Here!", + ) priority_announce(chosen_gang.arrival_announcement, sender_override = chosen_gang.ship_name) diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index 3e759bdc36275a..68491617aaa0ec 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -554,7 +554,7 @@ add_memory_in_range(head_of_staff, 5, /datum/memory/revolution_heads_victory, protagonist = head_of_staff) priority_announce("It appears the mutiny has been quelled. Please return yourself and your incapacitated colleagues to work. \ - We have remotely blacklisted the head revolutionaries in your medical records to prevent accidental revival.", null, null, null, "Central Command Loyalty Monitoring Division") + We have remotely blacklisted the head revolutionaries in your medical records to prevent accidental revival.", null, null, null, "[command_name()] Loyalty Monitoring Division") /// Mutates the ticker to report that the revs have won /datum/team/revolution/proc/round_result(finished) diff --git a/code/modules/antagonists/space_dragon/carp_rift.dm b/code/modules/antagonists/space_dragon/carp_rift.dm index dc9be2dfb8ddc0..7e95fd1b93a618 100644 --- a/code/modules/antagonists/space_dragon/carp_rift.dm +++ b/code/modules/antagonists/space_dragon/carp_rift.dm @@ -41,7 +41,13 @@ new_rift.dragon = dragon dragon.rift_list += new_rift to_chat(owner, span_boldwarning("The rift has been summoned. Prevent the crew from destroying it at all costs!")) - notify_ghosts("The Space Dragon has opened a rift!", source = new_rift, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Carp Rift Opened") + notify_ghosts( + "The Space Dragon has opened a rift!", + source = new_rift, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Carp Rift Opened", + ) ASSERT(dragon.rift_ability == src) // Badmin protection. QDEL_NULL(dragon.rift_ability) // Deletes this action when used successfully, we re-gain a new one on success later. @@ -189,14 +195,20 @@ if(light_color != LIGHT_COLOR_PURPLE) set_light_color(LIGHT_COLOR_PURPLE) update_light() - notify_ghosts("The carp rift can summon an additional carp!", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Carp Spawn Available") + notify_ghosts( + "The carp rift can summon an additional carp!", + source = src, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Carp Spawn Available", + ) last_carp_inc -= carp_interval // Is the rift now fully charged? if(time_charged >= max_charge) charge_state = CHARGE_COMPLETED var/area/A = get_area(src) - priority_announce("Spatial object has reached peak energy charge in [initial(A.name)], please stand-by.", "Central Command Wildlife Observations", has_important_message = TRUE) + priority_announce("Spatial object has reached peak energy charge in [initial(A.name)], please stand-by.", "[command_name()] Wildlife Observations", has_important_message = TRUE) atom_integrity = INFINITY icon_state = "carp_rift_charged" set_light_color(LIGHT_COLOR_DIM_YELLOW) @@ -216,7 +228,7 @@ if(charge_state < CHARGE_FINALWARNING && time_charged >= (max_charge * 0.5)) charge_state = CHARGE_FINALWARNING var/area/A = get_area(src) - priority_announce("A rift is causing an unnaturally large energy flux in [initial(A.name)]. Stop it at all costs!", "Central Command Wildlife Observations", ANNOUNCER_SPANOMALIES) + priority_announce("A rift is causing an unnaturally large energy flux in [initial(A.name)]. Stop it at all costs!", "[command_name()] Wildlife Observations", ANNOUNCER_SPANOMALIES) /** * Used to create carp controlled by ghosts when the option is available. diff --git a/code/modules/antagonists/space_dragon/space_dragon.dm b/code/modules/antagonists/space_dragon/space_dragon.dm index 574e458facae47..4b385b70e596c6 100644 --- a/code/modules/antagonists/space_dragon/space_dragon.dm +++ b/code/modules/antagonists/space_dragon/space_dragon.dm @@ -181,7 +181,7 @@ var/datum/objective/summon_carp/main_objective = locate() in objectives main_objective?.completed = TRUE priority_announce("A large amount of lifeforms have been detected approaching [station_name()] at extreme speeds. \ - Remaining crew are advised to evacuate as soon as possible.", "Central Command Wildlife Observations", has_important_message = TRUE) + Remaining crew are advised to evacuate as soon as possible.", "[command_name()] Wildlife Observations", has_important_message = TRUE) sound_to_playing_players('sound/creatures/space_dragon_roar.ogg', volume = 75) for(var/obj/structure/carp_rift/rift as anything in rift_list) rift.carp_stored = 999999 diff --git a/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm b/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm index c3dd93f01e2103..0d62ecece5f2a4 100644 --- a/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm +++ b/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm @@ -17,7 +17,7 @@ abstract_type = /datum/traitor_objective/destroy_heirloom - /// The jobs that this objective is targetting. + /// The jobs that this objective is targeting. var/list/target_jobs /// the item we need to destroy var/obj/item/target_item diff --git a/code/modules/antagonists/traitor/objectives/eyesnatching.dm b/code/modules/antagonists/traitor/objectives/eyesnatching.dm index 4a307f8d8e0bdd..c350eff981f8b8 100644 --- a/code/modules/antagonists/traitor/objectives/eyesnatching.dm +++ b/code/modules/antagonists/traitor/objectives/eyesnatching.dm @@ -208,7 +208,12 @@ playsound(target, 'sound/effects/pop.ogg', 100, TRAIT_MUTE) eyeballies.Remove(target) eyeballies.forceMove(get_turf(target)) - notify_ghosts("[target] has just had their eyes snatched!", source = target, action = NOTIFY_ORBIT, header = "Ouch!") + notify_ghosts( + "[target] has just had their eyes snatched!", + source = target, + action = NOTIFY_ORBIT, + header = "Ouch!", + ) target.emote("scream") if(prob(20)) target.emote("cry") diff --git a/code/modules/antagonists/traitor/objectives/kidnapping.dm b/code/modules/antagonists/traitor/objectives/kidnapping.dm index 4a463b2b61607a..d74b586efae25d 100644 --- a/code/modules/antagonists/traitor/objectives/kidnapping.dm +++ b/code/modules/antagonists/traitor/objectives/kidnapping.dm @@ -5,7 +5,7 @@ abstract_type = /datum/traitor_objective/target_player/kidnapping - /// The jobs that this objective is targetting. + /// The jobs that this objective is targeting. var/list/target_jobs /// Area that the target needs to be delivered to var/area/dropoff_area diff --git a/code/modules/antagonists/traitor/objectives/kill_pet.dm b/code/modules/antagonists/traitor/objectives/kill_pet.dm index ae28f5dbf4c08c..8ea89cb44d0338 100644 --- a/code/modules/antagonists/traitor/objectives/kill_pet.dm +++ b/code/modules/antagonists/traitor/objectives/kill_pet.dm @@ -31,7 +31,7 @@ /mob/living/basic/sloth/paperwork, ) ) - /// The head that we are targetting + /// The head that we are targeting var/datum/job/target /// Whether or not we only take from the traitor's own department head or not. var/limited_to_department_head = TRUE diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index a0498c38c45f5a..9b01b42410a7dd 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -35,20 +35,14 @@ /obj/item/soulstone/update_appearance(updates) . = ..() - for(var/mob/living/simple_animal/shade/sharded_shade in src) + for(var/mob/living/basic/shade/sharded_shade in src) switch(theme) if(THEME_HOLY) sharded_shade.name = "Purified [sharded_shade.real_name]" - sharded_shade.icon_state = "shade_holy" - sharded_shade.loot = list(/obj/item/ectoplasm/angelic) - if(THEME_CULT) + else sharded_shade.name = sharded_shade.real_name - sharded_shade.icon_state = "shade_cult" - sharded_shade.loot = list(/obj/item/ectoplasm) - if(THEME_WIZARD) - sharded_shade.name = sharded_shade.real_name - sharded_shade.icon_state = "shade_wizard" - sharded_shade.loot = list(/obj/item/ectoplasm/mystic) + sharded_shade.theme = theme + sharded_shade.update_appearance(UPDATE_ICON_STATE) /obj/item/soulstone/update_icon_state() . = ..() @@ -70,7 +64,7 @@ // "dull soulstone" name = "dull [name]" - var/mob/living/simple_animal/shade/shade = locate() in src + var/mob/living/basic/shade/shade = locate() in src if(shade) // "(dull) soulstone: Urist McCaptain" name = "[name]: [shade.real_name]" @@ -159,7 +153,7 @@ . += span_cult("This shard is spent; it is now just a creepy rock.") /obj/item/soulstone/Destroy() //Stops the shade from being qdel'd immediately and their ghost being sent back to the arrival shuttle. - for(var/mob/living/simple_animal/shade/shade in src) + for(var/mob/living/basic/shade/shade in src) INVOKE_ASYNC(shade, TYPE_PROC_REF(/mob/living, death)) return ..() @@ -217,7 +211,7 @@ release_shades(user) /obj/item/soulstone/proc/release_shades(mob/user, silent = FALSE) - for(var/mob/living/simple_animal/shade/captured_shade in src) + for(var/mob/living/basic/shade/captured_shade in src) captured_shade.forceMove(get_turf(user)) captured_shade.cancel_camera() update_appearance() @@ -234,7 +228,7 @@ on_release_spirits() /obj/item/soulstone/pre_attack(atom/A, mob/living/user, params) - var/mob/living/simple_animal/shade/occupant = (locate() in src) + var/mob/living/basic/shade/occupant = (locate() in src) var/obj/item/storage/toolbox/mechanical/target_toolbox = A if(!occupant || !istype(target_toolbox) || target_toolbox.has_soul) return ..() @@ -335,7 +329,7 @@ return TRUE //it'll probably get someone ;) ///captures a shade that was previously released from a soulstone. -/obj/item/soulstone/proc/capture_shade(mob/living/simple_animal/shade/shade, mob/living/user) +/obj/item/soulstone/proc/capture_shade(mob/living/basic/shade/shade, mob/living/user) if(isliving(user) && !role_check(user)) user.Unconscious(10 SECONDS) to_chat(user, span_userdanger("Your body is wracked with debilitating pain!")) @@ -358,7 +352,7 @@ ///transfer the mind of the shade to a construct mob selected by the user, then deletes both the shade and src. /obj/item/soulstone/proc/transfer_to_construct(obj/structure/constructshell/shell, mob/user) - var/mob/living/simple_animal/shade/shade = locate() in src + var/mob/living/basic/shade/shade = locate() in src if(!shade) to_chat(user, "[span_userdanger("Creation failed!")]: [src] is empty! Go kill someone!") return FALSE @@ -390,7 +384,7 @@ if(!shade_controller) shade_controller = victim victim.stop_sound_channel(CHANNEL_HEARTBEAT) - var/mob/living/simple_animal/shade/soulstone_spirit = new /mob/living/simple_animal/shade(src) + var/mob/living/basic/shade/soulstone_spirit = new /mob/living/basic/shade(src) soulstone_spirit.AddComponent(/datum/component/soulstoned, src) soulstone_spirit.name = "Shade of [victim.real_name]" soulstone_spirit.real_name = "Shade of [victim.real_name]" @@ -470,18 +464,18 @@ if(THEME_HOLY) makeNewConstruct(/mob/living/basic/construct/juggernaut/angelic, target, creator, cultoverride, loc_override) if(THEME_CULT) - makeNewConstruct(/mob/living/basic/construct/juggernaut/noncult, target, creator, cultoverride, loc_override) + makeNewConstruct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override) if(CONSTRUCT_WRAITH) if(IS_CULTIST(creator)) - makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc + makeNewConstruct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc return switch(theme) if(THEME_WIZARD) - makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith/mystic, target, creator, cultoverride, loc_override) + makeNewConstruct(/mob/living/basic/construct/wraith/mystic, target, creator, cultoverride, loc_override) if(THEME_HOLY) - makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith/angelic, target, creator, cultoverride, loc_override) + makeNewConstruct(/mob/living/basic/construct/wraith/angelic, target, creator, cultoverride, loc_override) if(THEME_CULT) - makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith/noncult, target, creator, cultoverride, loc_override) + makeNewConstruct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) if(CONSTRUCT_ARTIFICER) if(IS_CULTIST(creator)) makeNewConstruct(/mob/living/basic/construct/artificer, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc @@ -494,10 +488,10 @@ if(THEME_CULT) makeNewConstruct(/mob/living/basic/construct/artificer/noncult, target, creator, cultoverride, loc_override) -/proc/makeNewConstruct(mob/living/simple_animal/hostile/construct/ctype, mob/target, mob/stoner = null, cultoverride = FALSE, loc_override = null) +/proc/makeNewConstruct(mob/living/basic/construct/ctype, mob/target, mob/stoner = null, cultoverride = FALSE, loc_override = null) if(QDELETED(target)) return - var/mob/living/simple_animal/hostile/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target))) + var/mob/living/basic/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target))) var/makeicon = newstruct.icon_state var/theme = newstruct.theme flick("make_[makeicon][theme]", newstruct) diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm index 7704e11a1cb6fd..aece8d6741ba3f 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm @@ -69,7 +69,7 @@ name = "Guardian Deck" desc = "A deck of guardian tarot cards, capable of binding a personal guardian to your body. There are multiple types of guardian available, but all of them will transfer some amount of damage to you. \ It would be wise to avoid buying these with anything capable of causing you to swap bodies with others." - item_path = /obj/item/guardiancreator/choose/wizard + item_path = /obj/item/guardian_creator/wizard category = "Assistance" /datum/spellbook_entry/item/bloodbottle diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/offensive.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/offensive.dm index 546ae4da36a5b1..b23de0aa6b0693 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/offensive.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/offensive.dm @@ -142,3 +142,9 @@ item_path = /obj/item/highfrequencyblade/wizard category = "Offensive" cost = 3 + +/datum/spellbook_entry/item/frog_contract + name = "Frog Contract" + desc = "Sign a pact with the frogs to have your own destructive pet guardian!" + item_path = /obj/item/frog_contract + category = "Offensive" diff --git a/code/modules/antagonists/wizard/grand_ritual/finales/cheese.dm b/code/modules/antagonists/wizard/grand_ritual/finales/cheese.dm index 714cd62659bbb8..5cdd770486cd5a 100644 --- a/code/modules/antagonists/wizard/grand_ritual/finales/cheese.dm +++ b/code/modules/antagonists/wizard/grand_ritual/finales/cheese.dm @@ -10,7 +10,7 @@ /datum/grand_finale/cheese/trigger(mob/living/invoker) message_admins("[key_name(invoker)] has summoned forth The Wabbajack and cursed the crew with madness!") - priority_announce("Danger: Extremely potent reality altering object has been summoned on station. Immediate evacuation advised. Brace for impact.", "Central Command Higher Dimensional Affairs", 'sound/effects/glassbr1.ogg') + priority_announce("Danger: Extremely potent reality altering object has been summoned on station. Immediate evacuation advised. Brace for impact.", "[command_name()] Higher Dimensional Affairs", 'sound/effects/glassbr1.ogg') for (var/mob/living/carbon/human/crewmate as anything in GLOB.human_list) if (isnull(crewmate.mind)) diff --git a/code/modules/antagonists/wizard/grand_ritual/finales/immortality.dm b/code/modules/antagonists/wizard/grand_ritual/finales/immortality.dm index d20ca06752b6cf..92489145fda974 100644 --- a/code/modules/antagonists/wizard/grand_ritual/finales/immortality.dm +++ b/code/modules/antagonists/wizard/grand_ritual/finales/immortality.dm @@ -115,7 +115,7 @@ voice = target.voice voice_filter = target.voice_filter -/// Make the targetted human look like this +/// Make the targeted human look like this /datum/human_appearance_profile/proc/apply_to(mob/living/carbon/human/target) target.real_name = name target.age = age diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm index f981ab60af7f29..266b61e2d50b18 100644 --- a/code/modules/assembly/assembly.dm +++ b/code/modules/assembly/assembly.dm @@ -151,16 +151,6 @@ . = ..() . += span_notice("\The [src] [secured? "is secured and ready to be used!" : "can be attached to other things."]") -/obj/item/assembly/attack_self(mob/user) - if(!user) - return FALSE - user.set_machine(src) - interact(user) - return TRUE - -/obj/item/assembly/interact(mob/user) - return ui_interact(user) - /obj/item/assembly/ui_host(mob/user) // In order, return: // - The conencted wiring datum's owner, or diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index d38d20790e1412..3823706358fafa 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -96,7 +96,7 @@ switch(action) if("signal") if(cooldown_length > 0) - if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_SIGNALLER_SEND)) + if(TIMER_COOLDOWN_RUNNING(src, COOLDOWN_SIGNALLER_SEND)) balloon_alert(ui.user, "recharging!") return TIMER_COOLDOWN_START(src, COOLDOWN_SIGNALLER_SEND, cooldown_length) @@ -135,7 +135,7 @@ return if(!ishuman(user)) return - if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_SIGNALLER_SEND)) + if(TIMER_COOLDOWN_RUNNING(src, COOLDOWN_SIGNALLER_SEND)) balloon_alert(user, "still recharging...") return TIMER_COOLDOWN_START(src, COOLDOWN_SIGNALLER_SEND, 1 SECONDS) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm index 2550c37a8cd154..c06863ba09266c 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm @@ -13,7 +13,7 @@ Passive gate is similar to the regular pump except: desc = "A one-way air valve that does not require power. Passes gas when the output pressure is lower than the target pressure." can_unwrench = TRUE shift_underlay_only = FALSE - interaction_flags_machine = INTERACT_MACHINE_OFFLINE | INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_SET_MACHINE + interaction_flags_machine = INTERACT_MACHINE_OFFLINE | INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON construction_type = /obj/item/pipe/directional pipe_state = "passivegate" use_power = NO_POWER_USE diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_parts.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_parts.dm index ec6bc0caaa6ec7..96423f9f7704e0 100644 --- a/code/modules/atmospherics/machinery/components/fusion/hfr_parts.dm +++ b/code/modules/atmospherics/machinery/components/fusion/hfr_parts.dm @@ -169,10 +169,13 @@ desc = "Interface for the HFR to control the flow of the reaction." icon_state = "interface_off" circuit = /obj/item/circuitboard/machine/HFR_interface - var/obj/machinery/atmospherics/components/unary/hypertorus/core/connected_core icon_state_off = "interface_off" icon_state_open = "interface_open" icon_state_active = "interface_active" + /// Have we been activated at least once? + var/activated = FALSE + /// Reference to the core of our machine + var/obj/machinery/atmospherics/components/unary/hypertorus/core/connected_core /obj/machinery/hypertorus/interface/Destroy() if(connected_core) @@ -187,10 +190,13 @@ if(!centre || !centre.check_part_connectivity()) to_chat(user, span_notice("Check all parts and then try again.")) return TRUE - new/obj/item/paper/guides/jobs/atmos/hypertorus(loc) - connected_core = centre + connected_core = centre connected_core.activate(user) + if(!activated) + new /obj/item/paper/guides/jobs/atmos/hypertorus(loc) + activated = TRUE + return TRUE /obj/machinery/hypertorus/interface/ui_interact(mob/user, datum/tgui/ui) diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm index 9b080b59260fb0..1ea5fe9c6decf3 100644 --- a/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm +++ b/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm @@ -423,7 +423,8 @@ header = "Meltdown Incoming", action = NOTIFY_ORBIT, ghost_sound = 'sound/machines/warning-buzzer.ogg', - notify_volume = 75 + notify_volume = 75, + notify_flags = NOTIFY_CATEGORY_DEFAULT, ) for(var/i in HYPERTORUS_COUNTDOWN_TIME to 0 step -10) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm b/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm index b78de93868e7ae..49103c7729e6ca 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm @@ -13,11 +13,14 @@ qdel(src) return - gas_connector.dir = direction + gas_connector.dir = connected_machine.dir gas_connector.airs[1].volume = gas_volume SSair.start_processing_machine(connected_machine) register_with_machine() + gas_connector.set_init_directions() + gas_connector.atmos_init() + SSair.add_to_rebuild_queue(gas_connector) /datum/gas_machine_connector/Destroy() connected_machine = null diff --git a/code/modules/basketball/controller.dm b/code/modules/basketball/controller.dm index f5cc286ba2a187..d045d965341c90 100644 --- a/code/modules/basketball/controller.dm +++ b/code/modules/basketball/controller.dm @@ -120,6 +120,7 @@ GLOBAL_VAR(basketball_game) ghost_sound = 'sound/effects/ghost2.ogg', notify_volume = 75, action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_DEFAULT, ) create_bodies(ready_players) diff --git a/code/modules/bitrunning/alerts.dm b/code/modules/bitrunning/alerts.dm index f8c8aa30b94314..27412fb359a178 100644 --- a/code/modules/bitrunning/alerts.dm +++ b/code/modules/bitrunning/alerts.dm @@ -3,26 +3,6 @@ icon_state = "template" timeout = 10 SECONDS -/atom/movable/screen/alert/bitrunning/netpod_crowbar - name = "Forced Entry" - desc = "Someone is prying open the netpod door. Find an exit." - -/atom/movable/screen/alert/bitrunning/netpod_damaged - name = "Integrity Compromised" - desc = "The netpod is damaged. Find an exit." - -/atom/movable/screen/alert/bitrunning/qserver_shutting_down - name = "Domain Rebooting" - desc = "The domain is rebooting. Find an exit." - -/atom/movable/screen/alert/bitrunning/qserver_threat_deletion - name = "Queue Deletion" - desc = "The server is resetting. Oblivion awaits." - -/atom/movable/screen/alert/bitrunning/qserver_threat_spawned - name = "Threat Detected" - desc = "Data stream abnormalities present." - /atom/movable/screen/alert/bitrunning/qserver_domain_complete name = "Domain Completed" desc = "The domain is completed. Activate to exit." @@ -37,4 +17,5 @@ return if(tgui_alert(living_owner, "Disconnect safely?", "Server Message", list("Exit", "Remain"), 10 SECONDS) == "Exit") - SEND_SIGNAL(living_owner, COMSIG_BITRUNNER_SAFE_DISCONNECT) + SEND_SIGNAL(living_owner, COMSIG_BITRUNNER_ALERT_SEVER) + diff --git a/code/modules/bitrunning/components/avatar_connection.dm b/code/modules/bitrunning/components/avatar_connection.dm index b50d374867ad1c..cb1ed6737cb154 100644 --- a/code/modules/bitrunning/components/avatar_connection.dm +++ b/code/modules/bitrunning/components/avatar_connection.dm @@ -33,14 +33,21 @@ server.avatar_connection_refs.Add(WEAKREF(src)) avatar.key = old_body.key + ADD_TRAIT(avatar, TRAIT_NO_MINDSWAP, REF(src)) // do not remove this one ADD_TRAIT(old_body, TRAIT_MIND_TEMPORARILY_GONE, REF(src)) + /** + * Things that will disconnect forcefully: + * - Server shutdown / broken + * - Netpod power loss / broken + * - Pilot dies/ is moved / falls unconscious + */ RegisterSignals(old_body, list(COMSIG_LIVING_DEATH, COMSIG_MOVABLE_MOVED, COMSIG_LIVING_STATUS_UNCONSCIOUS), PROC_REF(on_sever_connection)) RegisterSignal(pod, COMSIG_BITRUNNER_CROWBAR_ALERT, PROC_REF(on_netpod_crowbar)) RegisterSignal(pod, COMSIG_BITRUNNER_NETPOD_INTEGRITY, PROC_REF(on_netpod_damaged)) - RegisterSignal(pod, COMSIG_BITRUNNER_SEVER_AVATAR, PROC_REF(on_sever_connection)) + RegisterSignal(pod, COMSIG_BITRUNNER_NETPOD_SEVER, PROC_REF(on_sever_connection)) RegisterSignal(server, COMSIG_BITRUNNER_DOMAIN_COMPLETE, PROC_REF(on_domain_completed)) - RegisterSignal(server, COMSIG_BITRUNNER_SEVER_AVATAR, PROC_REF(on_sever_connection)) + RegisterSignal(server, COMSIG_BITRUNNER_QSRV_SEVER, PROC_REF(on_sever_connection)) RegisterSignal(server, COMSIG_BITRUNNER_SHUTDOWN_ALERT, PROC_REF(on_shutting_down)) RegisterSignal(server, COMSIG_BITRUNNER_THREAT_CREATED, PROC_REF(on_threat_created)) #ifndef UNIT_TESTS @@ -68,18 +75,26 @@ /datum/component/avatar_connection/RegisterWithParent() ADD_TRAIT(parent, TRAIT_TEMPORARY_BODY, REF(src)) - RegisterSignal(parent, COMSIG_BITRUNNER_SAFE_DISCONNECT, PROC_REF(on_safe_disconnect)) + /** + * Things that cause safe disconnection: + * - Click the alert + * - Mailed in a cache + * - Click / Stand on the ladder + */ + RegisterSignals(parent, list(COMSIG_BITRUNNER_ALERT_SEVER, COMSIG_BITRUNNER_CACHE_SEVER, COMSIG_BITRUNNER_LADDER_SEVER), PROC_REF(on_safe_disconnect)) RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(on_sever_connection)) RegisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_linked_damage)) /datum/component/avatar_connection/UnregisterFromParent() REMOVE_TRAIT(parent, TRAIT_TEMPORARY_BODY, REF(src)) - UnregisterSignal(parent, COMSIG_BITRUNNER_SAFE_DISCONNECT) + UnregisterSignal(parent, COMSIG_BITRUNNER_ALERT_SEVER) + UnregisterSignal(parent, COMSIG_BITRUNNER_CACHE_SEVER) + UnregisterSignal(parent, COMSIG_BITRUNNER_LADDER_SEVER) UnregisterSignal(parent, COMSIG_LIVING_DEATH) UnregisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE) /// Disconnects the avatar and returns the mind to the old_body. -/datum/component/avatar_connection/proc/full_avatar_disconnect(forced = FALSE, datum/source) +/datum/component/avatar_connection/proc/full_avatar_disconnect(cause_damage = FALSE, datum/source) #ifndef UNIT_TESTS return_to_old_body() #endif @@ -88,7 +103,7 @@ if(isnull(hosting_netpod) && istype(source, /obj/machinery/netpod)) hosting_netpod = source - hosting_netpod?.disconnect_occupant(forced) + hosting_netpod?.disconnect_occupant(cause_damage) var/obj/machinery/quantum_server/server = server_ref?.resolve() server?.avatar_connection_refs.Remove(WEAKREF(src)) @@ -100,7 +115,7 @@ SIGNAL_HANDLER var/mob/living/avatar = parent - avatar.playsound_local(avatar, 'sound/machines/terminal_success.ogg', 50, TRUE) + avatar.playsound_local(avatar, 'sound/machines/terminal_success.ogg', 50, vary = TRUE) avatar.throw_alert( ALERT_BITRUNNER_COMPLETED, /atom/movable/screen/alert/bitrunning/qserver_domain_complete, @@ -112,12 +127,11 @@ SIGNAL_HANDLER var/mob/living/carbon/old_body = old_body_ref?.resolve() - if(isnull(old_body) || damage_type == STAMINA || damage_type == OXYLOSS) return if(damage >= (old_body.health + (ishuman(old_body) ? HUMAN_MAXHEALTH : MAX_LIVING_HEALTH))) // SKYRAT EDIT CHANGE - ORIGINAL: if(damage >= (old_body.health + MAX_LIVING_HEALTH)) - full_avatar_disconnect(forced = TRUE) + full_avatar_disconnect(cause_damage = TRUE) return if(damage > 30 && prob(30)) @@ -126,7 +140,7 @@ old_body.apply_damage(damage, damage_type, def_zone, blocked, wound_bonus = CANT_WOUND) if(old_body.stat > SOFT_CRIT) // KO! - full_avatar_disconnect(forced = TRUE) + full_avatar_disconnect(cause_damage = TRUE) /// Handles minds being swapped around in subsequent avatars /datum/component/avatar_connection/proc/on_mind_transfer(datum/mind/source, mob/living/previous_body) @@ -143,58 +157,66 @@ SIGNAL_HANDLER var/mob/living/avatar = parent - avatar.playsound_local(avatar, 'sound/machines/terminal_alert.ogg', 50, TRUE) - avatar.throw_alert( + avatar.playsound_local(avatar, 'sound/machines/terminal_alert.ogg', 50, vary = TRUE) + var/atom/movable/screen/alert/bitrunning/alert = avatar.throw_alert( ALERT_BITRUNNER_CROWBAR, - /atom/movable/screen/alert/bitrunning/netpod_crowbar, + /atom/movable/screen/alert/bitrunning, new_master = intruder ) + alert.name = "Netpod Breached" + alert.desc = "Someone is prying open the netpod. Find an exit." /// Triggers when the netpod is taking damage and is under 50% /datum/component/avatar_connection/proc/on_netpod_damaged(datum/source) SIGNAL_HANDLER var/mob/living/avatar = parent - avatar.throw_alert( + var/atom/movable/screen/alert/bitrunning/alert = avatar.throw_alert( ALERT_BITRUNNER_INTEGRITY, - /atom/movable/screen/alert/bitrunning/netpod_damaged, + /atom/movable/screen/alert/bitrunning, new_master = source ) + alert.name = "Integrity Compromised" + alert.desc = "The netpod is damaged. Find an exit." -/// Safely exits without forced variables, etc +/// Triggers when a safe disconnect is called /datum/component/avatar_connection/proc/on_safe_disconnect(datum/source) SIGNAL_HANDLER full_avatar_disconnect() -/// Helper for calling sever with forced variables +/// Received message to sever connection /datum/component/avatar_connection/proc/on_sever_connection(datum/source) SIGNAL_HANDLER - full_avatar_disconnect(forced = TRUE, source = source) + full_avatar_disconnect(cause_damage = TRUE, source = source) /// Triggers when the server is shutting down /datum/component/avatar_connection/proc/on_shutting_down(datum/source, mob/living/hackerman) SIGNAL_HANDLER var/mob/living/avatar = parent - avatar.playsound_local(avatar, 'sound/machines/terminal_alert.ogg', 50, TRUE) - avatar.throw_alert( + avatar.playsound_local(avatar, 'sound/machines/terminal_alert.ogg', 50, vary = TRUE) + var/atom/movable/screen/alert/bitrunning/alert = avatar.throw_alert( ALERT_BITRUNNER_SHUTDOWN, - /atom/movable/screen/alert/bitrunning/qserver_shutting_down, + /atom/movable/screen/alert/bitrunning, new_master = hackerman, ) + alert.name = "Domain Rebooting" + alert.desc = "The domain is rebooting. Find an exit." /// Server has spawned a ghost role threat /datum/component/avatar_connection/proc/on_threat_created(datum/source) SIGNAL_HANDLER var/mob/living/avatar = parent - avatar.throw_alert( + var/atom/movable/screen/alert/bitrunning/alert = avatar.throw_alert( ALERT_BITRUNNER_THREAT, - /atom/movable/screen/alert/bitrunning/qserver_threat_spawned, + /atom/movable/screen/alert/bitrunning, new_master = source, ) + alert.name = "Threat Detected" + alert.desc = "Data stream abnormalities present." /// Returns the mind to the old body /datum/component/avatar_connection/proc/return_to_old_body() diff --git a/code/modules/bitrunning/components/bitrunning_points.dm b/code/modules/bitrunning/components/bitrunning_points.dm index 58dda4a68ff6e5..328a70679e6530 100644 --- a/code/modules/bitrunning/components/bitrunning_points.dm +++ b/code/modules/bitrunning/components/bitrunning_points.dm @@ -1,46 +1,37 @@ -/// Attaches a component which listens for a given signal from the item. -/// -/// When the signal is received, it will add points to the signaler. +/// Attaches to a turf so it spawns a crate when a certain amount of points are added to it. /datum/component/bitrunning_points - /// The range at which we can find the signaler - var/max_point_range - /// Weakref to the loot crate landmark - where we send points - var/datum/weakref/our_spawner - /// The amount of points per each signal - var/points_per_signal - /// The signal we listen for - var/signal_type - -/datum/component/bitrunning_points/Initialize(signal_type, points_per_signal = 1, max_point_range = 4) - src.max_point_range = max_point_range - src.points_per_signal = points_per_signal - src.signal_type = signal_type - - locate_spawner() - -/datum/component/bitrunning_points/RegisterWithParent() - RegisterSignal(parent, signal_type, PROC_REF(on_event)) - -/datum/component/bitrunning_points/UnregisterFromParent() - UnregisterSignal(parent, signal_type) - -/// Finds the signaler if it hasn't been found yet. -/datum/component/bitrunning_points/proc/locate_spawner() - var/obj/effect/landmark/bitrunning/loot_signal/spawner = our_spawner?.resolve() - if(spawner) - return spawner - - for(var/obj/effect/landmark/bitrunning/loot_signal/found in GLOB.landmarks_list) - if(IN_GIVEN_RANGE(get_turf(parent), found, max_point_range)) - our_spawner = WEAKREF(found) - return found - -/// Once the specified signal is received, whisper to the spawner to add points. -/datum/component/bitrunning_points/proc/on_event(datum/source) + /// The amount required to spawn a crate + var/points_goal = 10 + /// A special condition limits this from spawning a crate + var/points_received = 0 + +/datum/component/bitrunning_points/Initialize(datum/lazy_template/virtual_domain/domain) + . = ..() + if(!isturf(parent)) + return COMPONENT_INCOMPATIBLE + + RegisterSignal(domain, COMSIG_BITRUNNER_GOAL_POINT, PROC_REF(on_add_points)) + +/// Listens for points to be added which will eventually spawn a crate. +/datum/component/bitrunning_points/proc/on_add_points(datum/source, points_to_add) SIGNAL_HANDLER - var/obj/effect/landmark/bitrunning/loot_signal/spawner = locate_spawner() - if(isnull(spawner)) + points_received += points_to_add + + if(points_received < points_goal) return - SEND_SIGNAL(spawner, COMSIG_BITRUNNER_GOAL_POINT, points_per_signal) + reveal() + +/// Spawns the crate with some effects +/datum/component/bitrunning_points/proc/reveal() + playsound(src, 'sound/magic/blink.ogg', 50, TRUE) + + var/turf/tile = parent + new /obj/structure/closet/crate/secure/bitrunning/encrypted(tile) + + var/datum/effect_system/spark_spread/quantum/sparks = new(tile) + sparks.set_up(number = 5, location = tile) + sparks.start() + + qdel(src) diff --git a/code/modules/bitrunning/components/virtual_elite_mob.dm b/code/modules/bitrunning/components/virtual_elite_mob.dm new file mode 100644 index 00000000000000..5a5766ecdf547a --- /dev/null +++ b/code/modules/bitrunning/components/virtual_elite_mob.dm @@ -0,0 +1,18 @@ +/// Removes loot tables from megafauna and lowers their health. +/datum/element/virtual_elite_mob + +/datum/element/virtual_elite_mob/Attach(datum/target) + . = ..() + if(!ismegafauna(target)) + return ELEMENT_INCOMPATIBLE + + var/mob/living/simple_animal/hostile/megafauna/boss = target + + var/new_max = clamp(boss.maxHealth * 0.5, 600, 1200) + boss.maxHealth = new_max + boss.health = new_max + boss.true_spawn = FALSE + boss.loot.Cut() + boss.loot += /obj/structure/closet/crate/secure/bitrunning/encrypted + boss.crusher_loot.Cut() + boss.crusher_loot += /obj/structure/closet/crate/secure/bitrunning/encrypted diff --git a/code/modules/bitrunning/objects/hololadder.dm b/code/modules/bitrunning/objects/hololadder.dm index 906801f1fc021e..e592f31382de98 100644 --- a/code/modules/bitrunning/objects/hololadder.dm +++ b/code/modules/bitrunning/objects/hololadder.dm @@ -35,7 +35,7 @@ balloon_alert(user, "disconnecting...") if(do_after(user, travel_time, src)) - SEND_SIGNAL(user, COMSIG_BITRUNNER_SAFE_DISCONNECT) + SEND_SIGNAL(user, COMSIG_BITRUNNER_LADDER_SEVER) /// Helper for times when you dont have hands (gondola??) /obj/structure/hololadder/proc/on_enter(datum/source, atom/movable/arrived, turf/old_loc) diff --git a/code/modules/bitrunning/objects/netpod.dm b/code/modules/bitrunning/objects/netpod.dm index cda63af2d9193a..754410174b3345 100644 --- a/code/modules/bitrunning/objects/netpod.dm +++ b/code/modules/bitrunning/objects/netpod.dm @@ -81,10 +81,10 @@ /obj/machinery/netpod/MouseDrop_T(mob/target, mob/user) var/mob/living/carbon/player = user - if(!iscarbon(player)) + if(!iscarbon(player) || !Adjacent(player) || !ISADVANCEDTOOLUSER(player) || !is_operational || !state_open) return - if((HAS_TRAIT(player, TRAIT_UI_BLOCKED) && !player.resting) || !Adjacent(player) || !ISADVANCEDTOOLUSER(player) || !is_operational) + if(player.buckled || HAS_TRAIT(player, TRAIT_HANDS_BLOCKED)) return close_machine(target) @@ -121,11 +121,6 @@ if(!state_open && gone == occupant) container_resist_act(gone) -/obj/machinery/netpod/Exited(atom/movable/gone, direction) - . = ..() - if(!state_open && gone == occupant) - container_resist_act(gone) - /obj/machinery/netpod/relaymove(mob/living/user, direction) if(!state_open) container_resist_act(user) @@ -176,7 +171,7 @@ if(do_after(pryer, 15 SECONDS, src)) if(!state_open) - SEND_SIGNAL(src, COMSIG_BITRUNNER_SEVER_AVATAR) + sever_connection() open_machine() return TRUE @@ -246,7 +241,7 @@ open_machine() /// Handles occupant post-disconnection effects like damage, sounds, etc -/obj/machinery/netpod/proc/disconnect_occupant(forced = FALSE) +/obj/machinery/netpod/proc/disconnect_occupant(cause_damage = FALSE) connected = FALSE var/mob/living/mob_occupant = occupant @@ -268,7 +263,7 @@ heal_time = (mob_occupant.stat + 2) * 5 addtimer(CALLBACK(src, PROC_REF(auto_disconnect)), heal_time SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME) - if(!forced) + if(!cause_damage) return mob_occupant.flash_act(override_blindness_check = TRUE, visual = TRUE) @@ -312,15 +307,9 @@ neo.set_static_vision(3 SECONDS) add_healing(occupant) - if(!do_after(neo, 2 SECONDS, src)) - return - // Very invalid - if(QDELETED(neo) || QDELETED(current_avatar) || QDELETED(src)) - return - - // Invalid - if(occupant != neo || isnull(neo.mind) || neo.stat == DEAD || current_avatar.stat == DEAD) + if(!validate_entry(neo, current_avatar)) + open_machine() return current_avatar.AddComponent( \ @@ -345,7 +334,7 @@ return server_ref = WEAKREF(server) - RegisterSignal(server, COMSIG_BITRUNNER_SERVER_UPGRADED, PROC_REF(on_server_upgraded)) + RegisterSignal(server, COMSIG_MACHINERY_REFRESH_PARTS, PROC_REF(on_server_upgraded)) RegisterSignal(server, COMSIG_BITRUNNER_DOMAIN_COMPLETE, PROC_REF(on_domain_complete)) RegisterSignal(server, COMSIG_BITRUNNER_DOMAIN_SCRUBBED, PROC_REF(on_domain_scrubbed)) @@ -358,14 +347,12 @@ "outfits" = list() ) - for(var/path as anything in outfit_list) - var/datum/outfit/outfit = path - + for(var/datum/outfit/outfit as anything in outfit_list) var/outfit_name = initial(outfit.name) if(findtext(outfit_name, "(") != 0 || findtext(outfit_name, "-") != 0) // No special variants please continue - collection["outfits"] += list(list("path" = path, "name" = outfit_name)) + collection["outfits"] += list(list("path" = outfit, "name" = outfit_name)) return list(collection) @@ -373,10 +360,7 @@ /obj/machinery/netpod/proc/on_broken(datum/source) SIGNAL_HANDLER - if(isnull(occupant) || !connected) - return - - SEND_SIGNAL(src, COMSIG_BITRUNNER_SEVER_AVATAR) + sever_connection() /// Checks the integrity, alerts occupants /obj/machinery/netpod/proc/on_damage_taken(datum/source, damage_amount) @@ -421,6 +405,11 @@ /obj/machinery/netpod/proc/on_examine(datum/source, mob/examiner, list/examine_text) SIGNAL_HANDLER + if(isnull(server_ref?.resolve())) + examine_text += span_infoplain("It's not connected to anything.") + examine_text += span_infoplain("Netpods must be built within 4 tiles of a server.") + return + examine_text += span_infoplain("Drag yourself into the pod to engage the link.") examine_text += span_infoplain("It has limited resuscitation capabilities. Remaining in the pod can heal some injuries.") examine_text += span_infoplain("It has a security system that will alert the occupant if it is tampered with.") @@ -444,13 +433,13 @@ open_machine() return - SEND_SIGNAL(src, COMSIG_BITRUNNER_SEVER_AVATAR) + sever_connection() /// When the server is upgraded, drops brain damage a little -/obj/machinery/netpod/proc/on_server_upgraded(datum/source, servo_rating) +/obj/machinery/netpod/proc/on_server_upgraded(obj/machinery/quantum_server/source) SIGNAL_HANDLER - disconnect_damage = BASE_DISCONNECT_DAMAGE * (1 - servo_rating) + disconnect_damage = BASE_DISCONNECT_DAMAGE * (1 - source.servo_bonus) /// Resolves a path to an outfit. /obj/machinery/netpod/proc/resolve_outfit(text) @@ -458,6 +447,13 @@ if(ispath(path, /datum/outfit)) return path +/// Severs the connection with the current avatar +/obj/machinery/netpod/proc/sever_connection() + if(isnull(occupant) || !connected) + return + + SEND_SIGNAL(src, COMSIG_BITRUNNER_NETPOD_SEVER) + /// Closes the machine without shoving in an occupant /obj/machinery/netpod/proc/shut_pod() state_open = FALSE @@ -467,4 +463,19 @@ update_appearance() +/// Checks for cases to eject/fail connecting an avatar +/obj/machinery/netpod/proc/validate_entry(mob/living/neo, mob/living/avatar) + if(!do_after(neo, 2 SECONDS, src)) + return FALSE + + // Very invalid + if(QDELETED(neo) || QDELETED(avatar) || QDELETED(src) || !is_operational) + return FALSE + + // Invalid + if(occupant != neo || isnull(neo.mind) || neo.stat > SOFT_CRIT || avatar.stat == DEAD) + return FALSE + + return TRUE + #undef BASE_DISCONNECT_DAMAGE diff --git a/code/modules/bitrunning/objects/quantum_console.dm b/code/modules/bitrunning/objects/quantum_console.dm index c918648d010b1b..cfa051b12a24e1 100644 --- a/code/modules/bitrunning/objects/quantum_console.dm +++ b/code/modules/bitrunning/objects/quantum_console.dm @@ -104,5 +104,4 @@ var/obj/machinery/quantum_server/nearby_server = locate(/obj/machinery/quantum_server, get_step(src, direction)) if(nearby_server) server_ref = WEAKREF(nearby_server) - nearby_server.console_ref = WEAKREF(src) return nearby_server diff --git a/code/modules/bitrunning/server/loot.dm b/code/modules/bitrunning/server/loot.dm index 8b3af95607c641..91889bce0a5ff1 100644 --- a/code/modules/bitrunning/server/loot.dm +++ b/code/modules/bitrunning/server/loot.dm @@ -7,27 +7,24 @@ rewards_base += servo_bonus - rewards_base += (domain_threats * 2) + rewards_base += (length(spawned_threat_refs) * 2) for(var/index in 2 to length(avatar_connection_refs)) rewards_base += multiplayer_bonus return rewards_base -/// Generates a reward based on the given domain -/obj/machinery/quantum_server/proc/generate_loot() - var/list/obj/machinery/byteforge/nearby_forges = get_nearby_forges() - if(isnull(nearby_forges)) - say(src, "No nearby byteforges detected.") - return FALSE +/// Handles spawning the (new) crate and deleting the former +/obj/machinery/quantum_server/proc/generate_loot(obj/cache, obj/machinery/byteforge/chosen_forge) + for(var/mob/person in cache.contents) + SEND_SIGNAL(person, COMSIG_BITRUNNER_CACHE_SEVER) - points += generated_domain.reward_points - playsound(src, 'sound/machines/terminal_success.ogg', 30, 2) + spark_at_location(cache) // abracadabra! + qdel(cache) // and it's gone! + SEND_SIGNAL(src, COMSIG_BITRUNNER_DOMAIN_COMPLETE, cache, generated_domain.reward_points) - var/obj/machinery/byteforge/chosen_forge = pick(nearby_forges) - if(isnull(chosen_forge)) - stack_trace("Failed to find a turf to spawn loot crate on.") - return FALSE + points += generated_domain.reward_points + playsound(src, 'sound/machines/terminal_success.ogg', 30, vary = TRUE) var/bonus = calculate_rewards() @@ -36,11 +33,11 @@ certificate.name = "certificate of domain completion" certificate.update_appearance() - var/obj/structure/closet/crate/secure/bitrunning/decrypted/reward_crate = new(src, generated_domain, bonus) - reward_crate.manifest = certificate - reward_crate.update_appearance() + var/obj/structure/closet/crate/secure/bitrunning/decrypted/reward_cache = new(src, generated_domain, bonus) + reward_cache.manifest = certificate + reward_cache.update_appearance() - chosen_forge.start_to_spawn(reward_crate) + chosen_forge.start_to_spawn(reward_cache) return TRUE /// Returns the markdown text containing domain completion information @@ -51,18 +48,20 @@ var/bonuses = calculate_rewards() + var/domain_threats = length(spawned_threat_refs) + var/time_difference = world.time - generated_domain.start_time var/completion_time = "### Completion Time: [DisplayTimeText(time_difference)]\n" - var/grade = "\n---\n\n# Rating: [grade_completion(generated_domain.difficulty, domain_threats, base_points, domain_randomized, time_difference)]" + var/grade = "\n---\n\n# Rating: [grade_completion(time_difference)]" var/text = "# Certificate of Domain Completion\n\n---\n\n" text += "### [generated_domain.name][domain_randomized ? " (Randomized)" : ""]\n" text += "- **Difficulty:** [generated_domain.difficulty]\n" text += "- **Threats:** [domain_threats]\n" - text += "- **Base Points:** [base_points][domain_randomized ? " +1" : ""]\n\n" + text += "- **Base Reward:** [base_points][domain_randomized ? " +1" : ""]\n\n" text += "- **Total Bonus:** [bonuses]x\n\n" if(bonuses <= 1) @@ -91,12 +90,11 @@ return text /// Grades the player's run based on several factors -/obj/machinery/quantum_server/proc/grade_completion(difficulty, threats, points, randomized, completion_time) - var/score = threats * 5 - score += points - score += randomized ? 1 : 0 +/obj/machinery/quantum_server/proc/grade_completion(completion_time) + var/score = length(spawned_threat_refs) * 5 + score += generated_domain.reward_points - var/base = difficulty + 1 + var/base = generated_domain.difficulty + 1 var/time_score = 1 if(completion_time <= 1 MINUTES) diff --git a/code/modules/bitrunning/server/map_handling.dm b/code/modules/bitrunning/server/map_handling.dm index 741fad476f0a8d..061a60b858bce9 100644 --- a/code/modules/bitrunning/server/map_handling.dm +++ b/code/modules/bitrunning/server/map_handling.dm @@ -91,7 +91,7 @@ var/turf/goal_turfs = list() var/turf/crate_turfs = list() - for(var/thing in GLOB.landmarks_list) + for(var/obj/effect/landmark/bitrunning/thing in GLOB.landmarks_list) if(istype(thing, /obj/effect/landmark/bitrunning/hololadder_spawn)) exit_turfs += get_turf(thing) qdel(thing) // i'm worried about multiple servers getting confused so lets clean em up @@ -110,6 +110,11 @@ qdel(thing) continue + if(istype(thing, /obj/effect/landmark/bitrunning/loot_signal)) + var/turf/signaler_turf = get_turf(thing) + signaler_turf.AddComponent(/datum/component/bitrunning_points, generated_domain) + qdel(thing) + if(!length(exit_turfs)) CRASH("Failed to find exit turfs on generated domain.") if(!length(goal_turfs)) @@ -142,7 +147,7 @@ /obj/machinery/quantum_server/proc/reset(fast = FALSE) is_ready = FALSE - SEND_SIGNAL(src, COMSIG_BITRUNNER_SEVER_AVATAR) + sever_connections() if(!fast) notify_spawned_threats() @@ -155,12 +160,11 @@ update_use_power(IDLE_POWER_USE) domain_randomized = FALSE - domain_threats = 0 retries_spent = 0 /// Deletes all the tile contents /obj/machinery/quantum_server/proc/scrub_vdom() - SEND_SIGNAL(src, COMSIG_BITRUNNER_SEVER_AVATAR) /// just in case someone's connected + sever_connections() /// just in case someone's connected SEND_SIGNAL(src, COMSIG_BITRUNNER_DOMAIN_SCRUBBED) // avatar cleanup just in case if(length(generated_domain.reservations)) diff --git a/code/modules/bitrunning/server/obj_generation.dm b/code/modules/bitrunning/server/obj_generation.dm index 6fd220402420b6..41918980360fb9 100644 --- a/code/modules/bitrunning/server/obj_generation.dm +++ b/code/modules/bitrunning/server/obj_generation.dm @@ -8,15 +8,21 @@ to_wear.belt = /obj/item/bitrunning_host_monitor to_wear.glasses = null to_wear.gloves = null - to_wear.l_hand = null to_wear.l_pocket = null - to_wear.r_hand = null to_wear.r_pocket = null to_wear.suit = null to_wear.suit_store = null avatar.equipOutfit(to_wear, visualsOnly = TRUE) + var/obj/item/clothing/under/jumpsuit = avatar.w_uniform + if(istype(jumpsuit)) + jumpsuit.set_armor(/datum/armor/clothing_under) + + var/obj/item/clothing/head/hat = avatar.get_clothing_on_part(HEAD) + if(istype(hat)) + hat.set_armor(null) + var/thing = avatar.get_active_held_item() if(!isnull(thing)) qdel(thing) diff --git a/code/modules/bitrunning/server/quantum_server.dm b/code/modules/bitrunning/server/quantum_server.dm index b869fb7f02e2a0..8d596cc0da952d 100644 --- a/code/modules/bitrunning/server/quantum_server.dm +++ b/code/modules/bitrunning/server/quantum_server.dm @@ -16,12 +16,8 @@ var/datum/lazy_template/virtual_domain/generated_domain /// The loaded safehouse, map_template/safehouse var/datum/map_template/safehouse/generated_safehouse - /// The connected console - var/datum/weakref/console_ref /// If the current domain was a random selection var/domain_randomized = FALSE - /// If any threats were spawned, adds to rewards - var/domain_threats = 0 /// Prevents multiple user actions. Handled by loading domains and cooldowns var/is_ready = TRUE /// List of available domains @@ -57,9 +53,6 @@ /obj/machinery/quantum_server/LateInitialize() . = ..() - if(isnull(console_ref)) - find_console() - radio = new(src) radio.set_frequency(FREQ_SUPPLY) radio.subspace_transmission = TRUE @@ -146,4 +139,3 @@ servo_bonus = servo_rating - SEND_SIGNAL(src, COMSIG_BITRUNNER_SERVER_UPGRADED, servo_rating) diff --git a/code/modules/bitrunning/server/signal_handlers.dm b/code/modules/bitrunning/server/signal_handlers.dm index b0464b351faf04..c41c0b529fc835 100644 --- a/code/modules/bitrunning/server/signal_handlers.dm +++ b/code/modules/bitrunning/server/signal_handlers.dm @@ -2,10 +2,7 @@ /obj/machinery/quantum_server/proc/on_broken(datum/source) SIGNAL_HANDLER - if(isnull(generated_domain)) - return - - SEND_SIGNAL(src, COMSIG_BITRUNNER_SEVER_AVATAR) + sever_connections() /// Whenever a corpse spawner makes a new corpse, add it to the list of potential mutations /obj/machinery/quantum_server/proc/on_corpse_spawned(datum/source, mob/living/corpse) @@ -18,7 +15,7 @@ SIGNAL_HANDLER if(generated_domain) - SEND_SIGNAL(src, COMSIG_BITRUNNER_SEVER_AVATAR) + sever_connections() scrub_vdom() if(is_ready) @@ -49,25 +46,14 @@ /obj/machinery/quantum_server/proc/on_goal_turf_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) SIGNAL_HANDLER - if(!istype(arrived, /obj/structure/closet/crate/secure/bitrunning/encrypted)) + var/obj/machinery/byteforge/chosen_forge = get_random_nearby_forge() + if(isnull(chosen_forge)) return - var/obj/structure/closet/crate/secure/bitrunning/encrypted/loot_crate = arrived - if(!istype(loot_crate)) + if(istype(arrived, /obj/structure/closet/crate/secure/bitrunning/encrypted)) + generate_loot(arrived, chosen_forge) return - for(var/mob/person in loot_crate.contents) - if(isnull(person.mind)) - person.forceMove(get_turf(loot_crate)) - - var/datum/component/avatar_connection/connection = person.GetComponent(/datum/component/avatar_connection) - connection?.full_avatar_disconnect() - - spark_at_location(loot_crate) - qdel(loot_crate) - SEND_SIGNAL(src, COMSIG_BITRUNNER_DOMAIN_COMPLETE, arrived, generated_domain.reward_points) - generate_loot() - /// Handles examining the server. Shows cooldown time and efficiency. /obj/machinery/quantum_server/proc/on_goal_turf_examined(datum/source, mob/examiner, list/examine_text) SIGNAL_HANDLER @@ -83,8 +69,11 @@ if(isliving(thing)) // so we can mutate them var/mob/living/creature = thing - if(creature.can_be_cybercop) - mutation_candidate_refs.Add(WEAKREF(creature)) + if(ismegafauna(creature)) + creature.AddElement(/datum/element/virtual_elite_mob) + continue + + mutation_candidate_refs.Add(WEAKREF(creature)) continue if(istype(thing, /obj/effect/mob_spawn/ghost_role)) // so we get threat alerts @@ -98,10 +87,11 @@ UnregisterSignal(source, COMSIG_LAZY_TEMPLATE_LOADED) + /// Just in case there's any special handling for the domain + generated_domain.setup_domain(created_atoms) + /// Handles when cybercops are summoned into the area or ghosts click a ghost role spawner /obj/machinery/quantum_server/proc/on_threat_created(datum/source, mob/living/threat) SIGNAL_HANDLER - domain_threats += 1 - spawned_threat_refs.Add(WEAKREF(threat)) - SEND_SIGNAL(src, COMSIG_BITRUNNER_THREAT_CREATED) // notify players + add_threats(threat) diff --git a/code/modules/bitrunning/server/threats.dm b/code/modules/bitrunning/server/threats.dm new file mode 100644 index 00000000000000..451b4c48c190f4 --- /dev/null +++ b/code/modules/bitrunning/server/threats.dm @@ -0,0 +1,21 @@ +/// Adds threats to the list and notifies players +/obj/machinery/quantum_server/proc/add_threats(mob/living/threat) + spawned_threat_refs.Add(WEAKREF(threat)) + SEND_SIGNAL(src, COMSIG_BITRUNNER_THREAT_CREATED) + +/// Finds any mobs with minds in the zones and gives them the bad news +/obj/machinery/quantum_server/proc/notify_spawned_threats() + for(var/datum/weakref/baddie_ref as anything in spawned_threat_refs) + var/mob/living/baddie = baddie_ref.resolve() + if(isnull(baddie?.mind) || baddie.stat >= UNCONSCIOUS) + continue + + var/atom/movable/screen/alert/bitrunning/alert = baddie.throw_alert( + ALERT_BITRUNNER_RESET, + /atom/movable/screen/alert/bitrunning, + new_master = src, + ) + alert.name = "Queue Deletion" + alert.desc = "The server is resetting. Oblivion awaits." + + to_chat(baddie, span_userdanger("You have been flagged for deletion! Thank you for your service.")) diff --git a/code/modules/bitrunning/server/util.dm b/code/modules/bitrunning/server/util.dm index 9570fd43915189..3d8b2c07880ac3 100644 --- a/code/modules/bitrunning/server/util.dm +++ b/code/modules/bitrunning/server/util.dm @@ -7,19 +7,6 @@ update_appearance() radio.talk_into(src, "Thermal systems within operational parameters. Proceeding to domain configuration.", RADIO_CHANNEL_SUPPLY) -/// Attempts to connect to a quantum console -/obj/machinery/quantum_server/proc/find_console() - var/obj/machinery/computer/quantum_console/console = console_ref?.resolve() - if(console) - return console - - for(var/direction in GLOB.cardinals) - var/obj/machinery/computer/quantum_console/nearby_console = locate(/obj/machinery/computer/quantum_console, get_step(src, direction)) - if(nearby_console) - console_ref = WEAKREF(nearby_console) - nearby_console.server_ref = WEAKREF(src) - return nearby_console - /// Compiles a list of available domains. /obj/machinery/quantum_server/proc/get_available_domains() var/list/levels = list() @@ -91,6 +78,15 @@ domain_randomized = TRUE return available["id"] +/// Locates any turfs with forges on them, returns a random one +/obj/machinery/quantum_server/proc/get_random_nearby_forge() + var/list/nearby_forges = list() + + for(var/obj/machinery/byteforge/forge in oview(MAX_DISTANCE, src)) + nearby_forges += forge + + return pick(nearby_forges) + /// Gets all mobs originally generated by the loaded domain and returns a list that are capable of being antagged /obj/machinery/quantum_server/proc/get_valid_domain_targets() // A: No one is playing @@ -116,20 +112,12 @@ return nearby_forges -/// Finds any mobs with minds in the zones and gives them the bad news -/obj/machinery/quantum_server/proc/notify_spawned_threats() - for(var/datum/weakref/baddie_ref as anything in spawned_threat_refs) - var/mob/living/baddie = baddie_ref.resolve() - if(isnull(baddie) || baddie.stat >= UNCONSCIOUS || isnull(baddie.mind)) - continue - - baddie.throw_alert( - ALERT_BITRUNNER_RESET, - /atom/movable/screen/alert/bitrunning/qserver_threat_deletion, - new_master = src, - ) +/// Severs any connected users +/obj/machinery/quantum_server/proc/sever_connections() + if(isnull(generated_domain) || !length(avatar_connection_refs)) + return - to_chat(baddie, span_userdanger("You have been flagged for deletion! Thank you for your service.")) + SEND_SIGNAL(src, COMSIG_BITRUNNER_QSRV_SEVER) /// Do some magic teleport sparks /obj/machinery/quantum_server/proc/spark_at_location(obj/cache) diff --git a/code/modules/bitrunning/virtual_domain/domains/ash_drake.dm b/code/modules/bitrunning/virtual_domain/domains/ash_drake.dm index 02bb91abc5888f..83d65a7fb46a05 100644 --- a/code/modules/bitrunning/virtual_domain/domains/ash_drake.dm +++ b/code/modules/bitrunning/virtual_domain/domains/ash_drake.dm @@ -8,11 +8,3 @@ map_name = "ash_drake" reward_points = BITRUNNER_REWARD_MEDIUM safehouse_path = /datum/map_template/safehouse/lavaland_boss - -/mob/living/simple_animal/hostile/megafauna/dragon/virtual_domain - can_be_cybercop = FALSE - crusher_loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - health = 1600 - loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - maxHealth = 1600 - true_spawn = FALSE diff --git a/code/modules/bitrunning/virtual_domain/domains/beach_bar.dm b/code/modules/bitrunning/virtual_domain/domains/beach_bar.dm index a6fb3e921e054a..f632b0681bf4b4 100644 --- a/code/modules/bitrunning/virtual_domain/domains/beach_bar.dm +++ b/code/modules/bitrunning/virtual_domain/domains/beach_bar.dm @@ -8,15 +8,14 @@ map_name = "beach_bar" safehouse_path = /datum/map_template/safehouse/mine -/obj/item/reagent_containers/cup/glass/drinkingglass/filled/virtual_domain - name = "pina colada" - desc = "Whose drink is this? Not yours, that's for sure. Well, it's not like they're going to miss it." - list_reagents = list(/datum/reagent/consumable/ethanol/pina_colada = 30) - -/obj/item/reagent_containers/cup/glass/drinkingglass/filled/virtual_domain/Initialize(mapload, vol) +/datum/lazy_template/virtual_domain/beach_bar/setup_domain(list/created_atoms) . = ..() - AddComponent(/datum/component/bitrunning_points, \ - signal_type = COMSIG_GLASS_DRANK, \ - points_per_signal = 0.5, \ - ) + for(var/obj/item/reagent_containers/cup/glass/drink in created_atoms) + RegisterSignal(drink, COMSIG_GLASS_DRANK, PROC_REF(on_drink_drank)) + +/// Eventually reveal the cache +/datum/lazy_template/virtual_domain/beach_bar/proc/on_drink_drank(datum/source) + SIGNAL_HANDLER + + add_points(0.5) diff --git a/code/modules/bitrunning/virtual_domain/domains/blood_drunk_miner.dm b/code/modules/bitrunning/virtual_domain/domains/blood_drunk_miner.dm index abf2e0fc5a9405..ad5d22f517512e 100644 --- a/code/modules/bitrunning/virtual_domain/domains/blood_drunk_miner.dm +++ b/code/modules/bitrunning/virtual_domain/domains/blood_drunk_miner.dm @@ -8,11 +8,3 @@ map_name = "blood_drunk_miner" reward_points = BITRUNNER_REWARD_MEDIUM safehouse_path = /datum/map_template/safehouse/lavaland_boss - -/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/virtual_domain - can_be_cybercop = FALSE - crusher_loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - health = 1600 - loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - maxHealth = 1600 - true_spawn = FALSE diff --git a/code/modules/bitrunning/virtual_domain/domains/breeze_bay.dm b/code/modules/bitrunning/virtual_domain/domains/breeze_bay.dm new file mode 100644 index 00000000000000..62fd3117a94e5c --- /dev/null +++ b/code/modules/bitrunning/virtual_domain/domains/breeze_bay.dm @@ -0,0 +1,22 @@ +/datum/lazy_template/virtual_domain/breeze_bay + name = "Breeze Bay" + desc = "A beach front town with a large forest to the north." + help_text = "It's simple! Enjoy some rays, catch some fish, and have a good time! Don't get bit by the crabs, though." + key = "breeze_bay" + map_name = "breeze_bay" + safehouse_path = /datum/map_template/safehouse/wood + +/datum/lazy_template/virtual_domain/breeze_bay/setup_domain(list/created_atoms) + . = ..() + + for(var/obj/item/fishing_rod/rod in created_atoms) + RegisterSignal(rod, COMSIG_FISHING_ROD_CAUGHT_FISH, PROC_REF(on_fish_caught)) + +/// Eventually reveal the cache +/datum/lazy_template/virtual_domain/breeze_bay/proc/on_fish_caught(datum/source, reward) + SIGNAL_HANDLER + + if(isnull(reward)) + return + + add_points(2) diff --git a/code/modules/bitrunning/virtual_domain/domains/bubblegum.dm b/code/modules/bitrunning/virtual_domain/domains/bubblegum.dm index bede97177cb7d4..4ac4a6476bd240 100644 --- a/code/modules/bitrunning/virtual_domain/domains/bubblegum.dm +++ b/code/modules/bitrunning/virtual_domain/domains/bubblegum.dm @@ -9,11 +9,3 @@ map_name = "bubblegum" reward_points = BITRUNNER_REWARD_HIGH safehouse_path = /datum/map_template/safehouse/lavaland_boss - -/mob/living/simple_animal/hostile/megafauna/bubblegum/virtual_domain - can_be_cybercop = FALSE - crusher_loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - health = 2000 - loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - maxHealth = 2000 - true_spawn = FALSE diff --git a/code/modules/bitrunning/virtual_domain/domains/colossus.dm b/code/modules/bitrunning/virtual_domain/domains/colossus.dm index 35ba4eee0ca89f..9baa011263b3b6 100644 --- a/code/modules/bitrunning/virtual_domain/domains/colossus.dm +++ b/code/modules/bitrunning/virtual_domain/domains/colossus.dm @@ -9,10 +9,3 @@ reward_points = BITRUNNER_REWARD_HIGH safehouse_path = /datum/map_template/safehouse/lavaland_boss -/mob/living/simple_animal/hostile/megafauna/colossus/virtual_domain - can_be_cybercop = FALSE - crusher_loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - health = 2000 - maxHealth = 2000 - true_spawn = FALSE diff --git a/code/modules/bitrunning/virtual_domain/domains/hierophant.dm b/code/modules/bitrunning/virtual_domain/domains/hierophant.dm index 142623f4f812e5..5b67c9d9bf22cb 100644 --- a/code/modules/bitrunning/virtual_domain/domains/hierophant.dm +++ b/code/modules/bitrunning/virtual_domain/domains/hierophant.dm @@ -8,11 +8,3 @@ map_name = "hierophant" reward_points = BITRUNNER_REWARD_HIGH safehouse_path = /datum/map_template/safehouse/lavaland_boss - -/mob/living/simple_animal/hostile/megafauna/hierophant/virtual_domain - can_be_cybercop = FALSE - crusher_loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - health = 1700 - loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - maxHealth = 1700 - true_spawn = FALSE diff --git a/code/modules/bitrunning/virtual_domain/domains/legion.dm b/code/modules/bitrunning/virtual_domain/domains/legion.dm deleted file mode 100644 index f1ba146f3801b9..00000000000000 --- a/code/modules/bitrunning/virtual_domain/domains/legion.dm +++ /dev/null @@ -1,20 +0,0 @@ -/datum/lazy_template/virtual_domain/legion - name = "Chamber of Echoes" - cost = BITRUNNER_COST_MEDIUM - desc = "A chilling realm that houses Legion's necropolis. Those who succumb to it are forever damned." - difficulty = BITRUNNER_DIFFICULTY_MEDIUM - forced_outfit = /datum/outfit/job/miner - key = "legion" - map_name = "legion" - reward_points = BITRUNNER_REWARD_MEDIUM - safehouse_path = /datum/map_template/safehouse/lavaland_boss - -/mob/living/simple_animal/hostile/megafauna/legion/virtual_domain - can_be_cybercop = FALSE - crusher_loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - health = 1500 - loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - maxHealth = 1500 - true_spawn = FALSE - -// You may be thinking, what about those mini-legions? They're not part of the initial created_atoms list diff --git a/code/modules/bitrunning/virtual_domain/domains/wendigo.dm b/code/modules/bitrunning/virtual_domain/domains/wendigo.dm index fcad3db6faf76f..fa0d15b92e9f5a 100644 --- a/code/modules/bitrunning/virtual_domain/domains/wendigo.dm +++ b/code/modules/bitrunning/virtual_domain/domains/wendigo.dm @@ -9,11 +9,3 @@ reward_points = BITRUNNER_REWARD_HIGH safehouse_path = /datum/map_template/safehouse/lavaland_boss -/mob/living/simple_animal/hostile/megafauna/wendigo/virtual_domain - can_be_cybercop = FALSE - crusher_loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - guaranteed_butcher_results = list(/obj/item/wendigo_skull = 1) - health = 2000 - loot = list(/obj/structure/closet/crate/secure/bitrunning/encrypted) - maxHealth = 2000 - true_spawn = FALSE diff --git a/code/modules/bitrunning/virtual_domain/virtual_domain.dm b/code/modules/bitrunning/virtual_domain/virtual_domain.dm index 202376a2c3344f..5e6cb0f2582e51 100644 --- a/code/modules/bitrunning/virtual_domain/virtual_domain.dm +++ b/code/modules/bitrunning/virtual_domain/virtual_domain.dm @@ -36,3 +36,11 @@ var/test_only = FALSE /// The safehouse to load into the map var/datum/map_template/safehouse/safehouse_path = /datum/map_template/safehouse/den + +/// Sends a point to any loot signals on the map +/datum/lazy_template/virtual_domain/proc/add_points(points_to_add) + SEND_SIGNAL(src, COMSIG_BITRUNNER_GOAL_POINT, points_to_add) + +/// Overridable proc to be called after the map is loaded. +/datum/lazy_template/virtual_domain/proc/setup_domain(list/created_atoms) + return diff --git a/code/modules/buildmode/buildmode.dm b/code/modules/buildmode/buildmode.dm index 0e16a13b54a8f2..df18fcf4e634c4 100644 --- a/code/modules/buildmode/buildmode.dm +++ b/code/modules/buildmode/buildmode.dm @@ -135,17 +135,7 @@ preview.name = initial(typepath.name) // Scale the preview if it's bigger than one tile - var/mutable_appearance/preview_overlay = new(typepath) - var/list/icon_dimensions = get_icon_dimensions(initial(typepath.icon)) - var/width = icon_dimensions["width"] - var/height = icon_dimensions["height"] - var/scale = 1 - if(width > world.icon_size || height > world.icon_size) - if(width >= height) - scale = world.icon_size / width - else - scale = world.icon_size / height - preview_overlay.transform = preview_overlay.transform.Scale(scale) + var/mutable_appearance/preview_overlay = get_small_overlay(new typepath) preview_overlay.appearance_flags |= TILE_BOUND preview_overlay.layer = FLOAT_LAYER preview_overlay.plane = FLOAT_PLANE diff --git a/code/modules/capture_the_flag/ctf_controller.dm b/code/modules/capture_the_flag/ctf_controller.dm index 8e51f8ef73332d..f5695ae65dcf1d 100644 --- a/code/modules/capture_the_flag/ctf_controller.dm +++ b/code/modules/capture_the_flag/ctf_controller.dm @@ -47,7 +47,13 @@ ctf_enabled = TRUE for(var/team in teams) var/obj/machinery/ctf/spawner/spawner = teams[team].spawner - notify_ghosts("[spawner.name] has been activated!", source = spawner, action = NOTIFY_ORBIT, header = "CTF has been activated") + notify_ghosts( + "[spawner.name] has been activated!", + source = spawner, + action = NOTIFY_ORBIT, + header = "CTF has been activated", + notify_flags = NOTIFY_CATEGORY_DEFAULT, + ) /datum/ctf_controller/proc/stop_ctf() ctf_enabled = FALSE diff --git a/code/modules/capture_the_flag/ctf_game.dm b/code/modules/capture_the_flag/ctf_game.dm index bfebcc706ca0f7..b7d97be8ecde9a 100644 --- a/code/modules/capture_the_flag/ctf_game.dm +++ b/code/modules/capture_the_flag/ctf_game.dm @@ -516,11 +516,17 @@ message_admins("[key_name_admin(user)] has [ctf_enabled ? "enabled" : "disabled"] CTF!") else if(automated) message_admins("CTF has finished a round and automatically restarted.") - notify_ghosts("CTF has automatically restarted after a round finished in [initial(ctf_area.name)]!",'sound/effects/ghost2.ogg') + notify_ghosts( + "CTF has automatically restarted after a round finished in [initial(ctf_area.name)]!", + 'sound/effects/ghost2.ogg', + ) else message_admins("The players have spoken! Voting has enabled CTF!") if(!automated) - notify_ghosts("CTF has been [ctf_enabled? "enabled" : "disabled"] in [initial(ctf_area.name)]!",'sound/effects/ghost2.ogg') + notify_ghosts( + "CTF has been [ctf_enabled? "enabled" : "disabled"] in [initial(ctf_area.name)]!", + 'sound/effects/ghost2.ogg', + ) #undef CTF_LOADING_UNLOADED #undef CTF_LOADING_LOADING diff --git a/code/modules/cargo/bounties/virus.dm b/code/modules/cargo/bounties/virus.dm index afa2a69819030b..33990ec1413857 100644 --- a/code/modules/cargo/bounties/virus.dm +++ b/code/modules/cargo/bounties/virus.dm @@ -16,14 +16,14 @@ /datum/bounty/virus/can_claim() return ..() && shipped -/datum/bounty/virus/applies_to(obj/shipped) +/datum/bounty/virus/applies_to(obj/export) if(shipped) return FALSE - if(shipped.flags_1 & HOLOGRAM_1) + if(export.flags_1 & HOLOGRAM_1) return FALSE - if(!istype(shipped, /obj/item/reagent_containers || !shipped.reagents || !shipped.reagents.reagent_list)) + if(!istype(export, /obj/item/reagent_containers || !export.reagents || !export.reagents.reagent_list)) return FALSE - var/datum/reagent/blood/blud = locate() in shipped.reagents.reagent_list + var/datum/reagent/blood/blud = locate() in export.reagents.reagent_list if(!blud) return FALSE for(var/datum/disease/advance/virus in blud.get_diseases()) @@ -31,8 +31,8 @@ return TRUE return FALSE -/datum/bounty/virus/ship(obj/shipped) - if(!applies_to(shipped)) +/datum/bounty/virus/ship(obj/export) + if(!applies_to(export)) return FALSE shipped = TRUE return TRUE diff --git a/code/modules/cargo/exports/lavaland.dm b/code/modules/cargo/exports/lavaland.dm index 31cc1319861028..51165be191c879 100644 --- a/code/modules/cargo/exports/lavaland.dm +++ b/code/modules/cargo/exports/lavaland.dm @@ -31,12 +31,12 @@ cost = CARGO_CRATE_VALUE * 40 unit_name = "lava planet artifact" export_types = list( - /obj/item/guardiancreator/miner, - /obj/item/rod_of_asclepius, /obj/item/dragons_blood, - /obj/item/melee/ghost_sword, + /obj/item/guardian_creator/miner, /obj/item/lava_staff, + /obj/item/melee/ghost_sword, /obj/item/prisoncube, + /obj/item/rod_of_asclepius, ) //Megafauna loot, except for ash drakes diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm index a449c8414952ce..149aaf6af86a83 100644 --- a/code/modules/cargo/expressconsole.dm +++ b/code/modules/cargo/expressconsole.dm @@ -149,7 +149,7 @@ if("add")//Generate Supply Order first - if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_EXPRESSPOD_CONSOLE)) + if(TIMER_COOLDOWN_RUNNING(src, COOLDOWN_EXPRESSPOD_CONSOLE)) say("Railgun recalibrating. Stand by.") return var/id = params["id"] diff --git a/code/modules/cargo/materials_market.dm b/code/modules/cargo/materials_market.dm index e2bedd2f19abf7..1a617e9e2dce13 100644 --- a/code/modules/cargo/materials_market.dm +++ b/code/modules/cargo/materials_market.dm @@ -1,3 +1,8 @@ +/// The maximum number of stacks you can place in 1 order +#define MAX_STACK_LIMIT 10 +/// The order rank for all galactic material market orders +#define GALATIC_MATERIAL_ORDER "Galactic Materials Market" + /obj/machinery/materials_market name = "galactic materials market" desc = "This machine allows the user to buy and sell sheets of minerals \ @@ -22,8 +27,6 @@ ) /// Are we ordering sheets from our own card balance or the cargo budget? var/ordering_private = TRUE - /// Currently, can we order sheets from our own card balance or the cargo budget? - var/can_buy_via_budget = FALSE /obj/machinery/materials_market/update_icon_state() if(panel_open) @@ -36,15 +39,21 @@ return ..() /obj/machinery/materials_market/wrench_act(mob/living/user, obj/item/tool) - ..() - default_unfasten_wrench(user, tool, time = 1.5 SECONDS) - return TOOL_ACT_TOOLTYPE_SUCCESS + . = ..() + if(default_unfasten_wrench(user, tool, time = 1.5 SECONDS) == SUCCESSFUL_UNFASTEN) + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/machinery/materials_market/screwdriver_act(mob/living/user, obj/item/tool) + . = ..() + if(default_deconstruction_screwdriver(user, "[base_icon_state]_open", "[base_icon_state]", tool)) + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/machinery/materials_market/crowbar_act(mob/living/user, obj/item/tool) + . = ..() + if(default_deconstruction_crowbar(tool)) + return TOOL_ACT_TOOLTYPE_SUCCESS /obj/machinery/materials_market/attackby(obj/item/O, mob/user, params) - if(default_deconstruction_screwdriver(user, "[base_icon_state]_open", "[base_icon_state]", O)) - return - else if(default_deconstruction_crowbar(O)) - return if(is_type_in_list(O, exportable_material_items)) var/amount = 0 var/value = 0 @@ -62,6 +71,7 @@ playsound(src, 'sound/machines/scanbuzz.ogg', 25, FALSE) return TRUE qdel(exportable) + var/obj/item/stock_block/new_block = new /obj/item/stock_block(drop_location()) new_block.export_value = amount * value * MARKET_PROFIT_MODIFIER new_block.export_mat = material_to_export @@ -71,6 +81,21 @@ return TRUE return ..() +/** + * Find the order purchased either privately or by cargo budget + * Arguments + * * [user][mob] - the user who placed this order + * * is_ordering_private - is the player ordering privatly. If FALSE it means they are using cargo budget + */ +/obj/machinery/materials_market/proc/find_order(mob/user, is_ordering_private) + for(var/datum/supply_order/order in SSshuttle.shopping_list) + // Must be a Galactic Materials Market order and payed by the null account(if ordered via cargo budget) or by correct user for private purchase + if(order.orderer_rank == GALATIC_MATERIAL_ORDER && ( \ + (!is_ordering_private && isnull(order.paying_account)) || \ + (is_ordering_private && !isnull(order.paying_account) && order.orderer == user) \ + )) + return order + return null /obj/machinery/materials_market/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -80,37 +105,74 @@ ui = new(user, src, "MatMarket", name) ui.open() +/obj/machinery/materials_market/ui_static_data(mob/user) + . = list() + .["CARGO_CRATE_VALUE"] = CARGO_CRATE_VALUE + /obj/machinery/materials_market/ui_data(mob/user) - var/data = list() + . = list() + + //can this player use cargo budget + var/can_buy_via_budget = FALSE + var/obj/item/card/id/used_id_card + if(isliving(user)) + var/mob/living/living_user = user + used_id_card = living_user.get_idcard(TRUE) + can_buy_via_budget = (ACCESS_CARGO in used_id_card?.GetAccess()) + + //if no cargo access then force private purchase + var/is_ordering_private = ordering_private || !can_buy_via_budget + + //find current order based on ordering mode & player + var/datum/supply_order/current_order = find_order(user, is_ordering_private) + var/material_data + var/trend_string + var/color_string + var/sheet_to_buy + var/requested_amount for(var/datum/material/traded_mat as anything in SSstock_market.materials_prices) - var/trend_string = "" - if(SSstock_market.materials_trends[traded_mat] == 0) - trend_string = "neutral" - else if(SSstock_market.materials_trends[traded_mat] == 1) - trend_string = "up" - else if(SSstock_market.materials_trends[traded_mat] == -1) - trend_string = "down" - var/color_string = "" - if (initial(traded_mat.greyscale_colors)) - color_string = splicetext(initial(traded_mat.greyscale_colors), 7, length(initial(traded_mat.greyscale_colors)), "") //slice it to a standard 6 char hex - else if(initial(traded_mat.color)) - color_string = initial(traded_mat.color) + //convert trend into text + switch(SSstock_market.materials_trends[traded_mat]) + if(0) + trend_string = "neutral" + if(1) + trend_string = "up" + else + trend_string = "down" + + //get mat color + var/initial_colors = initial(traded_mat.greyscale_colors) + if(initial_colors) + color_string = splicetext(initial_colors, 7, length(initial_colors), "") //slice it to a standard 6 char hex + else + initial_colors = initial(traded_mat.color) + if(initial_colors) + color_string = initial_colors + else + color_string = COLOR_CYAN + + //get sheet type from material + sheet_to_buy = initial(traded_mat.sheet_type) + if(!sheet_to_buy) + CRASH("Material with no sheet type being sold on materials market!") + + //get the ordered amount from the order + requested_amount = 0 + if(!isnull(current_order)) + requested_amount = current_order.pack.contains[sheet_to_buy] + + //send data material_data += list(list( "name" = initial(traded_mat.name), "price" = SSstock_market.materials_prices[traded_mat], "quantity" = SSstock_market.materials_quantity[traded_mat], "trend" = trend_string, "color" = color_string, + "requested" = requested_amount )) - can_buy_via_budget = FALSE - var/obj/item/card/id/used_id_card - if(isliving(user)) - var/mob/living/living_user = user - used_id_card = living_user.get_idcard(TRUE) - can_buy_via_budget = (ACCESS_CARGO in used_id_card?.GetAccess()) - + //get account balance var/balance = 0 if(!ordering_private) var/datum/bank_account/dept = SSeconomy.get_dep_account(ACCOUNT_CAR) @@ -119,16 +181,23 @@ else balance = used_id_card?.registered_account?.account_balance + //is market crashing var/market_crashing = FALSE if(HAS_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING)) market_crashing = TRUE - data["catastrophe"] = market_crashing - data["materials"] = material_data - data["creditBalance"] = balance - data["orderingPrive"] = ordering_private - data["canOrderCargo"] = can_buy_via_budget - return data + //get final order cost + var/current_cost = 0 + if(!isnull(current_order)) + current_cost = current_order.get_final_cost() + + //pack data + .["catastrophe"] = market_crashing + .["materials"] = material_data + .["creditBalance"] = balance + .["orderBalance"] = current_cost + .["orderingPrive"] = ordering_private + .["canOrderCargo"] = can_buy_via_budget /obj/machinery/materials_market/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) . = ..() @@ -141,12 +210,19 @@ if(isnull(used_id_card)) say("No ID Found") return + var/can_buy_via_budget = (ACCESS_CARGO in used_id_card?.GetAccess()) + + //if multiple users open the UI some of them may not have the required access so we recheck + var/is_ordering_private = ordering_private + if(!can_buy_via_budget) //no cargo access then force private purchase + is_ordering_private = TRUE switch(action) if("buy") var/material_str = params["material"] var/quantity = text2num(params["quantity"]) + //find material from it's name var/datum/material/material_bought var/obj/item/stack/sheet/sheet_to_buy for(var/datum/material/mat as anything in SSstock_market.materials_prices) @@ -155,12 +231,11 @@ break if(!material_bought) CRASH("Invalid material name passed to materials market!") + sheet_to_buy = initial(material_bought.sheet_type) + if(!sheet_to_buy) + CRASH("Material with no sheet type being sold on materials market!") - //if multiple users open the UI some of them may not have the required access so we recheck - var/is_ordering_private = ordering_private - if(!(ACCESS_CARGO in used_id_card.GetAccess())) //no cargo access then force private purchase - is_ordering_private = TRUE - + //get available bank account for purchasing var/datum/bank_account/account_payable if(is_ordering_private) account_payable = used_id_card.registered_account @@ -170,59 +245,85 @@ say("No bank account detected!") return - sheet_to_buy = initial(material_bought.sheet_type) - if(!sheet_to_buy) - CRASH("Material with no sheet type being sold on materials market!") - var/cost = SSstock_market.materials_prices[material_bought] * quantity - if(cost > account_payable.account_balance) - to_chat(living_user, span_warning("You don't have enough money to buy that!")) + //sanity checks for available quantity & budget + if(quantity > SSstock_market.materials_quantity[material_bought]) + say("Not enough materials on the market to purchase!") return + var/cost = SSstock_market.materials_prices[material_bought] * quantity + var/list/things_to_order = list() things_to_order += (sheet_to_buy) things_to_order[sheet_to_buy] = quantity + // We want to count how many stacks of all sheets we're ordering to make sure they don't exceed the limit of 10 // If we already have a custom order on SSshuttle, we should add the things to order to that order - for(var/datum/supply_order/order in SSshuttle.shopping_list) - // Must be a Galactic Materials Market order and payed by the null account(if ordered via cargo budget) or by correct user for private purchase - if(order.orderer_rank == "Galactic Materials Market" && ( \ - (!is_ordering_private && order.paying_account == null) || \ - (is_ordering_private && order.paying_account != null && order.orderer == living_user) \ - )) - // Check if this order exceeded its limit - var/prior_stacks = 0 - for(var/obj/item/stack/sheet/sheet as anything in order.pack.contains) - prior_stacks += ROUND_UP(order.pack.contains[sheet] / 50) - if(prior_stacks >= 10) - to_chat(usr, span_notice("You already have 10 stacks of sheets on order! Please wait for them to arrive before ordering more.")) - playsound(usr, 'sound/machines/synth_no.ogg', 35, FALSE) - return - // Append to this order - order.append_order(things_to_order, cost) + var/datum/supply_order/current_order = find_order(living_user, is_ordering_private) + if(!isnull(current_order)) + // Check if this order exceeded the market limit + var/prior_sheets = current_order.pack.contains[sheet_to_buy] + if(prior_sheets + quantity > SSstock_market.materials_quantity[material_bought] ) + say("There aren't enough sheets on the market! Please wait for more sheets to be traded before adding more.") + playsound(usr, 'sound/machines/synth_no.ogg', 35, FALSE) + return + + // Check if the order exceeded the purchase limit + var/prior_stacks = ROUND_UP(prior_sheets / MAX_STACK_SIZE) + if(prior_stacks >= MAX_STACK_LIMIT) + say("There are already 10 stacks of sheets on order! Please wait for them to arrive before ordering more.") + playsound(usr, 'sound/machines/synth_no.ogg', 35, FALSE) return - //Now we need to add a cargo order for quantity sheets of material_bought.sheet_type + // Prevents you from ordering more than the available budget + var/datum/bank_account/paying_account = account_payable + if(!isnull(current_order.paying_account)) //order is already being paid by another account + paying_account = current_order.paying_account + if(current_order.get_final_cost() + cost > paying_account.account_balance) + say("Order exceeds available budget! Please send it before purchasing more.") + return + + // Finally Append to this order + current_order.append_order(things_to_order, cost) + return TRUE + + + //Place a new order var/datum/supply_pack/custom/minerals/mineral_pack = new( purchaser = is_ordering_private ? living_user : "Cargo", \ cost = cost, \ contains = things_to_order, \ ) - var/datum/supply_order/new_order = new( + var/datum/supply_order/disposable/materials/new_order = new( pack = mineral_pack, orderer = living_user, - orderer_rank = "Galactic Materials Market", + orderer_rank = GALATIC_MATERIAL_ORDER, orderer_ckey = living_user.ckey, paying_account = is_ordering_private ? account_payable : null, - cost_type = "credit", + cost_type = "cr", can_be_cancelled = FALSE ) + //first time order compute the correct cost and compare + if(new_order.get_final_cost() > account_payable.account_balance) + say("Not enough money to start purchase!") + qdel(new_order) + return + say("Thank you for your purchase! It will arrive on the next cargo shuttle!") SSshuttle.shopping_list += new_order - return + return TRUE + if("toggle_budget") if(!can_buy_via_budget) return ordering_private = !ordering_private + return TRUE + + if("clear") + var/datum/supply_order/current_order = find_order(living_user, is_ordering_private) + if(!isnull(current_order)) + SSshuttle.shopping_list -= current_order + qdel(current_order) + return TRUE /obj/item/stock_block name = "stock block" @@ -238,6 +339,11 @@ /// Is this stock block currently updating it's value with the market (aka fluid)? var/fluid = FALSE +/obj/item/stock_block/Initialize(mapload) + . = ..() + addtimer(CALLBACK(src, PROC_REF(value_warning)), 2.5 MINUTES, TIMER_DELETE_ME) + addtimer(CALLBACK(src, PROC_REF(update_value)), 5 MINUTES, TIMER_DELETE_ME) + /obj/item/stock_block/examine(mob/user) . = ..() . += span_notice("\The [src] is worth [export_value] cr, from selling [quantity] sheets of [initial(export_mat?.name)].") @@ -246,11 +352,6 @@ else . += span_notice("\The [src]'s value is still [span_boldnotice("locked in")]. [span_boldnotice("Sell it")] before it's value becomes liquid!") -/obj/item/stock_block/Initialize(mapload) - . = ..() - addtimer(CALLBACK(src, PROC_REF(value_warning)), 2.5 MINUTES) - addtimer(CALLBACK(src, PROC_REF(update_value)), 5 MINUTES) - /obj/item/stock_block/proc/value_warning() visible_message(span_warning("\The [src] is starting to become liquid!")) icon_state = "stock_block_fluid" @@ -266,3 +367,5 @@ update_appearance(UPDATE_ICON_STATE) visible_message(span_warning("\The [src] becomes liquid!")) +#undef MAX_STACK_LIMIT +#undef GALATIC_MATERIAL_ORDER diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm index 9217446d9b5d65..309567d51e9020 100644 --- a/code/modules/cargo/order.dm +++ b/code/modules/cargo/order.dm @@ -85,14 +85,18 @@ src.manifest_can_fail = manifest_can_fail src.can_be_cancelled = can_be_cancelled +/datum/supply_order/Destroy(force, ...) + QDEL_NULL(applied_coupon) + return ..() + //returns the total cost of this order. Its not the total price paid by cargo but the total value of this order /datum/supply_order/proc/get_final_cost() var/cost = pack.get_cost() if(applied_coupon) //apply discount price - cost -= (cost * applied_coupon.discount_pct_off) - if(!isnull(paying_account)) //privately purchased means 1.1x the cost + cost *= (1 - applied_coupon.discount_pct_off) + if(paying_account && !pack.goody) //privately purchased and not a goody means 1.1x the cost cost *= 1.1 - return cost + return round(cost) /datum/supply_order/proc/generateRequisition(turf/T) var/obj/item/paper/requisition_paper = new(T) @@ -201,6 +205,19 @@ pack.contains[i] = new_contents[i] pack.cost += cost_increase +/// Custom type of order who's supply pack can be safely deleted +/datum/supply_order/disposable + +/datum/supply_order/disposable/Destroy(force, ...) + QDEL_NULL(pack) + return ..() + +/// Custom material order to append cargo crate value to the final order cost +/datum/supply_order/disposable/materials + +/datum/supply_order/disposable/materials/get_final_cost() + return (..() + CARGO_CRATE_VALUE) + #undef MANIFEST_ERROR_CHANCE #undef MANIFEST_ERROR_NAME #undef MANIFEST_ERROR_CONTENTS diff --git a/code/modules/cargo/orderconsole.dm b/code/modules/cargo/orderconsole.dm index b59cee9def7528..38552e4cb9ab89 100644 --- a/code/modules/cargo/orderconsole.dm +++ b/code/modules/cargo/orderconsole.dm @@ -152,7 +152,7 @@ "cost" = pack.get_cost(), "orderer" = order.orderer, "reason" = order.reason, - "id" = order.id + "id" = order.id, )) data["amount_by_name"] = amount_by_name @@ -177,7 +177,7 @@ "id" = pack, "desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name. "goody" = P.goody, - "access" = P.access + "access" = P.access, )) return data @@ -259,7 +259,16 @@ applied_coupon = coupon_check break - var/datum/supply_order/order = new(pack = pack ,orderer = name, orderer_rank = rank, orderer_ckey = ckey, reason = reason, paying_account = account, coupon = applied_coupon, charge_on_purchase = TRUE) //SKYRAT EDIT CHANGE - ORIGINAL: var/datum/supply_order/order = new(pack = pack ,orderer = name, orderer_rank = rank, orderer_ckey = ckey, reason = reason, paying_account = account, coupon = applied_coupon) + var/datum/supply_order/order = new( + pack = pack , + orderer = name, + orderer_rank = rank, + orderer_ckey = ckey, + reason = reason, + paying_account = account, + coupon = applied_coupon, + charge_on_purchase = TRUE, // SKYRAT EDIT ADDITION + ) working_list += order if(self_paid) @@ -280,13 +289,14 @@ continue if(order.department_destination) say("Only the department that ordered this item may cancel it.") - return + return FALSE if(order.applied_coupon) say("Coupon refunded.") order.applied_coupon.forceMove(get_turf(src)) SSshuttle.shopping_list -= order - . = TRUE - break + qdel(order) + return TRUE + return FALSE /** * maps the ordename displayed on the ui to its supply pack id * * order_name - the name of the order diff --git a/code/modules/client/preferences/README.md b/code/modules/client/preferences/README.md index 0089953639883b..fabfb779c902b4 100644 --- a/code/modules/client/preferences/README.md +++ b/code/modules/client/preferences/README.md @@ -28,7 +28,7 @@ export const savefile_key_here: Feature = { // Necessary for game preferences, unused for others category: "CATEGORY", - // Optional, only shown in game preferences + // Optional, shown as a tooltip description: "This preference will blow your mind!", } ``` diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 9f0be80e7a8a57..3b03f1290082f3 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -215,35 +215,34 @@ if(BODY_ZONE_CHEST)//Listening to the chest user.visible_message(span_notice("[user] places [src] against [carbon_patient]'s [body_part] and listens attentively."), ignored_mobs = user) if(!user.can_hear()) - to_chat(user, span_notice("You place [src] against [carbon_patient]'s [body_part]. Fat load of good it does you though, since you can't hear")) + to_chat(user, span_notice("You place [src] against [carbon_patient]'s [body_part]. Fat load of good it does you though, since you can't hear.")) return else render_list += span_info("You place [src] against [carbon_patient]'s [body_part]:\n") //assess breathing - if(!lungs)//sanity check, enusure patient actually has lungs - render_list += "[M] doesn't have any lungs!\n" + if(isnull(lungs) \ + || carbon_patient.stat == DEAD \ + || (HAS_TRAIT(carbon_patient, TRAIT_FAKEDEATH)) \ + || (HAS_TRAIT(carbon_patient, TRAIT_NOBREATH))\ + || carbon_patient.failed_last_breath \ + || carbon_patient.losebreath)//If pt is dead or otherwise not breathing + render_list += "[M.p_Theyre()] not breathing!\n" + else if(lungs.damage > 10)//if breathing, check for lung damage + render_list += "You hear fluid in [M.p_their()] lungs!\n" + else if(oxy_loss > 10)//if they have suffocation damage + render_list += "[M.p_Theyre()] breathing heavily!\n" else - if(carbon_patient.stat == DEAD || (HAS_TRAIT(carbon_patient, TRAIT_FAKEDEATH)) || (HAS_TRAIT(carbon_patient, TRAIT_NOBREATH))|| carbon_patient.failed_last_breath || carbon_patient.losebreath)//If pt is dead or otherwise not breathing - render_list += "[M.p_Theyre()] not breathing!\n" - else if(lungs.damage > 10)//if breathing, check for lung damage - render_list += "You hear fluid in [M.p_their()] lungs!\n" - else if(oxy_loss > 10)//if they have suffocation damage - render_list += "[M.p_Theyre()] breathing heavily!\n" - else - render_list += "[M.p_Theyre()] breathing normally.\n"//they're okay :D + render_list += "[M.p_Theyre()] breathing normally.\n"//they're okay :D //assess heart if(body_part == BODY_ZONE_CHEST)//if we're listening to the chest - if(!heart)//sanity check, ensure the patient actually has a heart - render_list += "[M] doesn't have a heart!\n" + if(isnull(heart) || !heart.beating || carbon_patient.stat == DEAD) + render_list += "You don't hear a heartbeat!\n"//they're dead or their heart isn't beating + else if(heart.damage > 10 || carbon_patient.blood_volume <= BLOOD_VOLUME_OKAY) + render_list += "You hear a weak heartbeat.\n"//their heart is damaged, or they have critical blood else - if(!heart.beating || carbon_patient.stat == DEAD) - render_list += "You don't hear a heartbeat!\n"//they're dead or their heart isn't beating - else if(heart.damage > 10 || carbon_patient.blood_volume <= BLOOD_VOLUME_OKAY) - render_list += "You hear a weak heartbeat.\n"//their heart is damaged, or they have critical blood - else - render_list += "You hear a healthy heartbeat.\n"//they're okay :D + render_list += "You hear a healthy heartbeat.\n"//they're okay :D if(BODY_ZONE_PRECISE_GROIN)//If we're targeting the groin render_list += span_info("You carefully press down on [carbon_patient]'s abdomen:\n") @@ -254,7 +253,7 @@ var/appendix_okay = TRUE var/liver_okay = TRUE if(!liver)//sanity check, ensure the patient actually has a liver - render_list += "[M] doesn't have a liver!\n" + render_list += "You can't feel anything where [M.p_their()] liver would be.\n" liver_okay = FALSE else if(liver.damage > 10) @@ -262,7 +261,7 @@ liver_okay = FALSE if(!appendix)//sanity check, ensure the patient actually has an appendix - render_list += "[M] doesn't have an appendix!\n" + render_list += "You can't feel anything where [M.p_their()] appendix would be.\n" appendix_okay = FALSE else if(appendix.damage > 10 && carbon_patient.stat == CONSCIOUS) @@ -290,23 +289,20 @@ user.visible_message(span_notice("[user] presses their fingers against [carbon_patient]'s [body_part]."), ignored_mobs = user) //assess pulse (heart & blood level) - if(!heart)//sanity check, ensure the patient actually has a heart - render_list += "[M] doesn't have a heart!\n" + if(isnull(heart) || !heart.beating || carbon_patient.blood_volume <= BLOOD_VOLUME_OKAY || carbon_patient.stat == DEAD) + render_list += "You can't find a pulse!\n"//they're dead, their heart isn't beating, or they have critical blood else - if(!heart.beating || carbon_patient.blood_volume <= BLOOD_VOLUME_OKAY || carbon_patient.stat == DEAD) - render_list += "You can't find a pulse!\n"//they're dead, their heart isn't beating, or they have critical blood + if(heart.damage > 10) + heart_strength = span_danger("irregular")//their heart is damaged else - if(heart.damage > 10) - heart_strength = span_danger("irregular")//their heart is damaged - else - heart_strength = span_notice("regular")//they're okay :D + heart_strength = span_notice("regular")//they're okay :D - if(carbon_patient.blood_volume <= BLOOD_VOLUME_SAFE && carbon_patient.blood_volume > BLOOD_VOLUME_OKAY) - pulse_pressure = span_danger("thready")//low blood - else - pulse_pressure = span_notice("strong")//they're okay :D + if(carbon_patient.blood_volume <= BLOOD_VOLUME_SAFE && carbon_patient.blood_volume > BLOOD_VOLUME_OKAY) + pulse_pressure = span_danger("thready")//low blood + else + pulse_pressure = span_notice("strong")//they're okay :D - render_list += "[M.p_Their()] pulse is [pulse_pressure] and [heart_strength].\n" + render_list += "[M.p_Their()] pulse is [pulse_pressure] and [heart_strength].\n" //display our packaged information in an examine block for easy reading to_chat(user, examine_block(jointext(render_list, "")), type = MESSAGE_TYPE_INFO) diff --git a/code/modules/clothing/shoes/cowboy.dm b/code/modules/clothing/shoes/cowboy.dm index 0aa518bc1364d8..a033a561439ff3 100644 --- a/code/modules/clothing/shoes/cowboy.dm +++ b/code/modules/clothing/shoes/cowboy.dm @@ -38,11 +38,7 @@ occupant.forceMove(user.drop_location()) user.visible_message(span_warning("[user] recoils as something slithers out of [src]."), span_userdanger("You feel a sudden stabbing pain in your [pick("foot", "toe", "ankle")]!")) user.Knockdown(20) //Is one second paralyze better here? I feel you would fall on your ass in some fashion. - user.apply_damage(5, BRUTE, target_zone) - if(istype(occupant, /mob/living/simple_animal/hostile/retaliate)) - user.reagents.add_reagent(/datum/reagent/toxin, 7) - - + occupant.UnarmedAttack(user, proximity_flag = TRUE) /obj/item/clothing/shoes/cowboy/dropped(mob/living/user) . = ..() diff --git a/code/modules/clothing/spacesuits/bountyhunter.dm b/code/modules/clothing/spacesuits/bountyhunter.dm index 0c83e1b01d2247..9218deb5633fca 100644 --- a/code/modules/clothing/spacesuits/bountyhunter.dm +++ b/code/modules/clothing/spacesuits/bountyhunter.dm @@ -3,7 +3,7 @@ desc = "A custom version of the MK.II SWAT suit, modified to look rugged and tough. Works as a space suit, if you can find a helmet." icon_state = "hunter" inhand_icon_state = "swat_suit" - allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/knife/combat) + allowed = list(/obj/item/gun, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/knife/combat) armor_type = /datum/armor/space_hunter strip_delay = 130 resistance_flags = FIRE_PROOF | ACID_PROOF diff --git a/code/modules/clothing/spacesuits/freedom.dm b/code/modules/clothing/spacesuits/freedom.dm index 73343a82eeeb7c..b0a08f4cc7367b 100644 --- a/code/modules/clothing/spacesuits/freedom.dm +++ b/code/modules/clothing/spacesuits/freedom.dm @@ -25,7 +25,7 @@ desc = "An advanced, light suit, fabricated from a mixture of synthetic feathers and space-resistant material. A gun holster appears to be integrated into the suit and the wings appear to be stuck in 'freedom' mode." icon_state = "freedom" inhand_icon_state = null - allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals) + allowed = list(/obj/item/gun, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals) armor_type = /datum/armor/space_freedom strip_delay = 130 max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT diff --git a/code/modules/clothing/spacesuits/pirate.dm b/code/modules/clothing/spacesuits/pirate.dm index 34a495b4dbef8e..946c0c2b66fdd9 100644 --- a/code/modules/clothing/spacesuits/pirate.dm +++ b/code/modules/clothing/spacesuits/pirate.dm @@ -25,7 +25,7 @@ desc = "A modified suit to allow space pirates to board shuttles and stations while avoiding the maw of the void. Comes with additional protection and is lighter to move in." icon_state = "spacepirate" w_class = WEIGHT_CLASS_NORMAL - allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/melee/energy/sword/pirate, /obj/item/clothing/glasses/eyepatch, /obj/item/reagent_containers/cup/glass/bottle/rum) + allowed = list(/obj/item/gun, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/melee/energy/sword/pirate, /obj/item/clothing/glasses/eyepatch, /obj/item/reagent_containers/cup/glass/bottle/rum) slowdown = 0 armor_type = /datum/armor/space_pirate strip_delay = 40 diff --git a/code/modules/clothing/spacesuits/specialops.dm b/code/modules/clothing/spacesuits/specialops.dm index 3634066e72fd49..cf8fc2a475cc69 100644 --- a/code/modules/clothing/spacesuits/specialops.dm +++ b/code/modules/clothing/spacesuits/specialops.dm @@ -35,7 +35,7 @@ slowdown = 0 flags_inv = 0 w_class = WEIGHT_CLASS_NORMAL - allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals) + allowed = list(/obj/item/gun, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals) armor_type = /datum/armor/space_officer strip_delay = 130 max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT diff --git a/code/modules/clothing/spacesuits/syndi.dm b/code/modules/clothing/spacesuits/syndi.dm index d9939a466211e4..cbacf064052db4 100644 --- a/code/modules/clothing/spacesuits/syndi.dm +++ b/code/modules/clothing/spacesuits/syndi.dm @@ -38,7 +38,7 @@ GLOBAL_LIST_INIT(syndicate_space_suits_to_helmets,list( inhand_icon_state = "space_suit_syndicate" desc = "Has a tag on it: Totally not property of an enemy corporation, honest!" w_class = WEIGHT_CLASS_NORMAL - allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals) + allowed = list(/obj/item/gun, /obj/item/melee/baton, /obj/item/melee/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals) armor_type = /datum/armor/space_syndicate cell = /obj/item/stock_parts/cell/hyper var/helmet_type = /obj/item/clothing/head/helmet/space/syndicate diff --git a/code/modules/clothing/suits/reactive_armour.dm b/code/modules/clothing/suits/reactive_armour.dm index 6c33e287f033aa..9fec4dbe82b92b 100644 --- a/code/modules/clothing/suits/reactive_armour.dm +++ b/code/modules/clothing/suits/reactive_armour.dm @@ -226,7 +226,7 @@ emp_message = span_warning("The tesla capacitors beep ominously for a moment.") clothing_traits = list(TRAIT_TESLA_SHOCKIMMUNE) /// How strong are the zaps we give off? - var/zap_power = 1e7 + var/zap_power = 2.5e4 /// How far to the zaps we give off go? var/zap_range = 20 /// What flags do we pass to the zaps we give off? @@ -240,7 +240,7 @@ /obj/item/clothing/suit/armor/reactive/tesla/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) owner.visible_message(span_danger("[src] blocks [attack_text], sending out arcs of lightning!")) - tesla_zap(owner, zap_range, zap_power, zap_flags) + tesla_zap(source = owner, zap_range = zap_range, power = zap_power, cutoff = 1e3, zap_flags = zap_flags) reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration return TRUE diff --git a/code/modules/error_handler/error_handler.dm b/code/modules/error_handler/error_handler.dm index 1b3f6bca16d776..a6841d3975444c 100644 --- a/code/modules/error_handler/error_handler.dm +++ b/code/modules/error_handler/error_handler.dm @@ -26,6 +26,7 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0) Reboot(reason = 1) return + var/static/regex/stack_workaround = regex("[WORKAROUND_IDENTIFIER](.+?)[WORKAROUND_IDENTIFIER]") var/static/list/error_last_seen = list() var/static/list/error_cooldown = list() /* Error_cooldown items will either be positive(cooldown time) or negative(silenced error) If negative, starts at -1, and goes down by 1 each time that error gets skipped*/ @@ -33,6 +34,12 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0) if(!error_last_seen) // A runtime is occurring too early in start-up initialization return ..() + if(stack_workaround.Find(E.name)) + var/list/data = json_decode(stack_workaround.group[1]) + E.file = data[1] + E.line = data[2] + E.name = stack_workaround.Replace(E.name, "") + var/erroruid = "[E.file][E.line]" var/last_seen = error_last_seen[erroruid] var/cooldown = error_cooldown[erroruid] || 0 diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index bd192dbef22084..4951c1915479ae 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -261,7 +261,12 @@ Runs the event /datum/round_event/proc/announce_to_ghosts(atom/atom_of_interest) if(control.alert_observers) if (atom_of_interest) - notify_ghosts("[control.name] has an object of interest: [atom_of_interest]!", source=atom_of_interest, action=NOTIFY_ORBIT, header="Something's Interesting!") + notify_ghosts( + "[control.name] has an object of interest: [atom_of_interest]!", + source = atom_of_interest, + action = NOTIFY_ORBIT, + header = "Something's Interesting!", + ) return //Called when the tick is equal to the announce_when variable. diff --git a/code/modules/events/communications_blackout.dm b/code/modules/events/communications_blackout.dm index e6ad5d8d3bd7ce..f7ff1c2642c483 100644 --- a/code/modules/events/communications_blackout.dm +++ b/code/modules/events/communications_blackout.dm @@ -23,7 +23,7 @@ to_chat(A, "
[span_warning("[alert]")]
") if(prob(30) || fake) //most of the time, we don't want an announcement, so as to allow AIs to fake blackouts. - priority_announce(alert, null, ANNOUNCER_COMMSBLACKOUT) //SKYRAT EDIT CHANGE + priority_announce(alert, "Anomaly Alert", sound = ANNOUNCER_COMMSBLACKOUT) //SKYRAT EDIT CHANGE - ORIGINAL: priority_announce(alert, "Anomaly Alert") /datum/round_event/communications_blackout/start() diff --git a/code/modules/events/earthquake.dm b/code/modules/events/earthquake.dm index 498648986e49cc..4f20f26b93bf26 100644 --- a/code/modules/events/earthquake.dm +++ b/code/modules/events/earthquake.dm @@ -93,7 +93,11 @@ priority_announce("Planetary monitoring systems indicate a devastating seismic event in the near future.", "Seismic Report") /datum/round_event/earthquake/start() - notify_ghosts("The earthquake's epicenter has been located: [get_area_name(epicenter)]!", source = epicenter, header = "Rumble Rumble Rumble!") + notify_ghosts( + "The earthquake's epicenter has been located: [get_area_name(epicenter)]!", + source = epicenter, + header = "Rumble Rumble Rumble!", + ) /datum/round_event/earthquake/tick() if(ISMULTIPLE(activeFor, 5)) diff --git a/code/modules/events/ghost_role/fugitive_event.dm b/code/modules/events/ghost_role/fugitive_event.dm index a70cf3e31b3249..11eaf3c78b2c14 100644 --- a/code/modules/events/ghost_role/fugitive_event.dm +++ b/code/modules/events/ghost_role/fugitive_event.dm @@ -134,9 +134,19 @@ var/mob/our_candidate = candidates[1] var/mob/spawned_mob = spawner.create_from_ghost(our_candidate) candidates -= our_candidate - notify_ghosts("[spawner.prompt_name] has awoken: [spawned_mob]!", source = spawned_mob, action = NOTIFY_ORBIT, header="Come look!") + notify_ghosts( + "[spawner.prompt_name] has awoken: [spawned_mob]!", + source = spawned_mob, + action = NOTIFY_ORBIT, + header = "Come look!", + ) else - notify_ghosts("[spawner.prompt_name] spawner has been created!", source = spawner, action = NOTIFY_ORBIT, header="Spawn Here!") + notify_ghosts( + "[spawner.prompt_name] spawner has been created!", + source = spawner, + action = NOTIFY_ORBIT, + header = "Spawn Here!", + ) priority_announce("Unidentified ship detected near the station.") diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm index 714e3838e34e3f..8ad0b48985f680 100644 --- a/code/modules/events/portal_storm.dm +++ b/code/modules/events/portal_storm.dm @@ -28,7 +28,7 @@ boss_types = list(/mob/living/basic/construct/artificer/hostile = 6) hostile_types = list( /mob/living/basic/construct/juggernaut/hostile = 8, - /mob/living/simple_animal/hostile/construct/wraith/hostile = 6, + /mob/living/basic/construct/wraith/hostile = 6, ) /datum/round_event/portal_storm diff --git a/code/modules/events/processor_overload.dm b/code/modules/events/processor_overload.dm index ebcbb27f2781d5..3c97ca91cdcca7 100644 --- a/code/modules/events/processor_overload.dm +++ b/code/modules/events/processor_overload.dm @@ -26,7 +26,7 @@ // whether it's, say, a tesla zapping tcomms, or some selective // modification of the tcomms bus if(prob(80) || fake) - priority_announce(alert) + priority_announce(alert, "Anomaly Alert") /datum/round_event/processor_overload/start() diff --git a/code/modules/events/radiation_leak.dm b/code/modules/events/radiation_leak.dm index 0fbe29927666f3..b97cc19d9cc90e 100644 --- a/code/modules/events/radiation_leak.dm +++ b/code/modules/events/radiation_leak.dm @@ -60,7 +60,7 @@ priority_announce("A radiation leak has been detected in [location_descriptor || "an unknown area"]. \ All crew are to evacuate the affected area. Our [pick("mechanics", "engineers", "scientists", "interns", "sensors", "readings")] \ - report that a machine within is causing it - repair it quickly to stop the leak.") + report that a machine within is causing it - repair it quickly to stop the leak.", "[command_name()] Engineering Division") /datum/round_event/radiation_leak/start() var/obj/machinery/the_source_of_our_problems = picked_machine_ref?.resolve() diff --git a/code/modules/events/scrubber_overflow.dm b/code/modules/events/scrubber_overflow.dm index 6aad17f00faa1f..7f24648a9e5a73 100644 --- a/code/modules/events/scrubber_overflow.dm +++ b/code/modules/events/scrubber_overflow.dm @@ -67,7 +67,7 @@ deadchat_broadcast(" has just been[random ? " randomly" : ""] triggered[cause ? " by [cause]" : ""]!", "Scrubber Overflow: [initial(forced_reagent_type.name)]", message_type=DEADCHAT_ANNOUNCEMENT) /datum/round_event/scrubber_overflow/announce(fake) - priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "Atmospherics alert") + priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "[command_name()] Engineering Division") /datum/round_event/scrubber_overflow/setup() for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/temp_vent as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/atmospherics/components/unary/vent_scrubber)) diff --git a/code/modules/events/shuttle_loan/shuttle_loan_event.dm b/code/modules/events/shuttle_loan/shuttle_loan_event.dm index 96db32c044d6f9..c7248a36266074 100644 --- a/code/modules/events/shuttle_loan/shuttle_loan_event.dm +++ b/code/modules/events/shuttle_loan/shuttle_loan_event.dm @@ -43,7 +43,7 @@ SSshuttle.shuttle_loan = src /datum/round_event/shuttle_loan/proc/loan_shuttle() - priority_announce(situation.thanks_msg, "Cargo shuttle commandeered by CentCom.") + priority_announce(situation.thanks_msg, "Cargo shuttle commandeered by [command_name()].") dispatched = TRUE var/datum/bank_account/dep_account = SSeconomy.get_dep_account(ACCOUNT_CAR) diff --git a/code/modules/events/tram_malfunction.dm b/code/modules/events/tram_malfunction.dm index 26e0f2feefa475..18ee4afb7a18c9 100644 --- a/code/modules/events/tram_malfunction.dm +++ b/code/modules/events/tram_malfunction.dm @@ -35,7 +35,7 @@ end_when = rand(TRAM_MALFUNCTION_TIME_LOWER, TRAM_MALFUNCTION_TIME_UPPER) /datum/round_event/tram_malfunction/announce() - priority_announce("Our automated control system has lost contact with the tram's onboard computer. Please take extra care while engineers diagnose and resolve the issue.", "CentCom Engineering Division") + priority_announce("Our automated control system has lost contact with the tram's onboard computer. Please take extra care while engineers diagnose and resolve the issue.", "[command_name()] Engineering Division") /datum/round_event/tram_malfunction/start() for(var/datum/transport_controller/linear/tram/malfunctioning_controller as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) @@ -47,7 +47,7 @@ for(var/datum/transport_controller/linear/tram/malfunctioning_controller as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM]) if(malfunctioning_controller.specific_transport_id == specific_transport_id && malfunctioning_controller.controller_status & COMM_ERROR) malfunctioning_controller.end_malf_event() - priority_announce("The software on the tram has been reset, normal operations are now resuming. Sorry for any inconvienence this may have caused.", "CentCom Engineering Division") + priority_announce("The software on the tram has been reset, normal operations are now resuming. Sorry for any inconvienence this may have caused.", "[command_name()] Engineering Division") return #undef TRAM_MALFUNCTION_TIME_UPPER diff --git a/code/modules/events/wizard/shuffle.dm b/code/modules/events/wizard/shuffle.dm index 517501e48586d2..0ffe8966eea977 100644 --- a/code/modules/events/wizard/shuffle.dm +++ b/code/modules/events/wizard/shuffle.dm @@ -87,7 +87,7 @@ var/list/mobs_to_swap = list() for(var/mob/living/carbon/human/alive_human in GLOB.alive_mob_list) - if(alive_human.stat != CONSCIOUS || !alive_human.mind || IS_WIZARD(alive_human)) + if(alive_human.stat != CONSCIOUS || isnull(alive_human.mind) || IS_WIZARD(alive_human) || HAS_TRAIT(alive_human, TRAIT_NO_MINDSWAP)) continue //the wizard(s) are spared on this one mobs_to_swap += alive_human diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm index b04f2a4f595820..7dcaf0861c3ff7 100644 --- a/code/modules/events/wormholes.dm +++ b/code/modules/events/wormholes.dm @@ -54,6 +54,7 @@ GLOBAL_LIST_EMPTY(all_wormholes) // So we can pick wormholes to teleport to icon_state = "anom" mech_sized = TRUE light_on = FALSE + wibbles = FALSE /obj/effect/portal/wormhole/Initialize(mapload, _creator, _lifespan = 0, obj/effect/portal/_linked, automatic_link = FALSE, turf/hard_target_override) . = ..() diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index 26b7693f4aa86e..90fb2afc796b86 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -441,13 +441,13 @@ //Fish breeding stops if fish count exceeds this. #define AQUARIUM_MAX_BREEDING_POPULATION 20 -/obj/item/fish/proc/ready_to_reproduce(being_targetted = FALSE) +/obj/item/fish/proc/ready_to_reproduce(being_targeted = FALSE) var/obj/structure/aquarium/aquarium = loc if(!istype(aquarium)) return FALSE - if(being_targetted && HAS_TRAIT(src, TRAIT_FISH_NO_MATING)) + if(being_targeted && HAS_TRAIT(src, TRAIT_FISH_NO_MATING)) return FALSE - if(!being_targetted && length(aquarium.get_fishes()) >= AQUARIUM_MAX_BREEDING_POPULATION) + if(!being_targeted && length(aquarium.get_fishes()) >= AQUARIUM_MAX_BREEDING_POPULATION) return FALSE return aquarium.allow_breeding && health >= initial(health) * 0.8 && stable_population > 1 && world.time >= breeding_wait diff --git a/code/modules/fishing/sources/_fish_source.dm b/code/modules/fishing/sources/_fish_source.dm index 657b2f30968b74..7ef43238957757 100644 --- a/code/modules/fishing/sources/_fish_source.dm +++ b/code/modules/fishing/sources/_fish_source.dm @@ -66,7 +66,7 @@ GLOBAL_LIST_INIT(specific_fish_icons, zebra_typecacheof(list( return /// Can we fish in this spot at all. Returns DENIAL_REASON or null if we're good to go -/datum/fish_source/proc/reason_we_cant_fish(obj/item/fishing_rod/rod, mob/fisherman) +/datum/fish_source/proc/reason_we_cant_fish(obj/item/fishing_rod/rod, mob/fisherman, atom/parent) return rod.reason_we_cant_fish(src) /** diff --git a/code/modules/fishing/sources/source_types.dm b/code/modules/fishing/sources/source_types.dm index e2e5491dd1d3db..edab6dc0db5cfd 100644 --- a/code/modules/fishing/sources/source_types.dm +++ b/code/modules/fishing/sources/source_types.dm @@ -216,7 +216,7 @@ fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 10 -/datum/fish_source/lavaland/reason_we_cant_fish(obj/item/fishing_rod/rod, mob/fisherman) +/datum/fish_source/lavaland/reason_we_cant_fish(obj/item/fishing_rod/rod, mob/fisherman, atom/parent) . = ..() var/turf/approx = get_turf(fisherman) //todo pass the parent if(!SSmapping.level_trait(approx.z, ZTRAIT_MINING)) @@ -277,7 +277,7 @@ ) fishing_difficulty = FISHING_DEFAULT_DIFFICULTY - 5 -/datum/fish_source/holographic/reason_we_cant_fish(obj/item/fishing_rod/rod, mob/fisherman) +/datum/fish_source/holographic/reason_we_cant_fish(obj/item/fishing_rod/rod, mob/fisherman, atom/parent) . = ..() if(!istype(get_area(fisherman), /area/station/holodeck)) return "You need to be inside the Holodeck to catch holographic fish." @@ -310,3 +310,63 @@ /obj/item/fish/mastodon = 1, ) fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 15 + +#define RANDOM_SEED "Random seed" + +/datum/fish_source/hydro_tray + catalog_description = "Hydroponics trays" + fish_table = list( + FISHING_DUD = 25, + /obj/item/food/grown/grass = 25, + RANDOM_SEED = 16, + /obj/item/seeds/grass = 6, + /obj/item/seeds/random = 1, + /mob/living/basic/frog = 1, + /mob/living/basic/axolotl = 1, + ) + fish_counts = list( + /obj/item/food/grown/grass = 10, + /obj/item/seeds/grass = 4, + RANDOM_SEED = 4, + /obj/item/seeds/random = 1, + /mob/living/basic/frog = 1, + /mob/living/basic/axolotl = 1, + ) + fishing_difficulty = FISHING_DEFAULT_DIFFICULTY - 10 + +/datum/fish_source/hydro_tray/reason_we_cant_fish(obj/item/fishing_rod/rod, mob/fisherman, atom/parent) + if(!istype(parent, /obj/machinery/hydroponics/constructable)) + return ..() + + var/obj/machinery/hydroponics/constructable/basin = parent + if(basin.waterlevel <= 0) + return "There's no water in [parent] to fish in." + if(basin.myseed) + return "There's a plant growing in [parent]." + + return ..() + +/datum/fish_source/hydro_tray/spawn_reward(reward_path, mob/fisherman, turf/fishing_spot) + if(reward_path != RANDOM_SEED) + var/mob/living/created_reward = ..() + if(istype(created_reward)) + created_reward.name = "small [created_reward.name]" + created_reward.update_transform(0.75) + return created_reward + + var/static/list/seeds_to_draw_from + if(isnull(seeds_to_draw_from)) + seeds_to_draw_from = subtypesof(/obj/item/seeds) + // These two are already covered innately + seeds_to_draw_from -= /obj/item/seeds/random + seeds_to_draw_from -= /obj/item/seeds/grass + // -1 yield are unharvestable plants so we don't care + // 20 rarirty is where most of the wacky plants are so let's ignore them + for(var/obj/item/seeds/seed_path as anything in seeds_to_draw_from) + if(initial(seed_path.yield) == -1 || initial(seed_path.rarity) >= PLANT_MODERATELY_RARE) + seeds_to_draw_from -= seed_path + + var/picked_path = pick(seeds_to_draw_from) + return new picked_path(get_turf(fishing_spot)) + +#undef RANDOM_SEED diff --git a/code/modules/food_and_drinks/machinery/icecream_vat.dm b/code/modules/food_and_drinks/machinery/icecream_vat.dm index 607c54e6ff19d4..5c860c57a92c03 100644 --- a/code/modules/food_and_drinks/machinery/icecream_vat.dm +++ b/code/modules/food_and_drinks/machinery/icecream_vat.dm @@ -10,6 +10,7 @@ use_power = NO_POWER_USE layer = BELOW_OBJ_LAYER max_integrity = 300 + interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON|INTERACT_MACHINE_SET_MACHINE var/list/product_types = list() var/selected_flavour = ICE_CREAM_VANILLA var/obj/item/reagent_containers/beaker diff --git a/code/modules/food_and_drinks/machinery/microwave.dm b/code/modules/food_and_drinks/machinery/microwave.dm index 8488025149a988..a95357ef2f0b97 100644 --- a/code/modules/food_and_drinks/machinery/microwave.dm +++ b/code/modules/food_and_drinks/machinery/microwave.dm @@ -218,7 +218,7 @@ . = ..() // All of these will use a full icon state instead - if(panel_open || dirty == MAX_MICROWAVE_DIRTINESS || broken || dirty_anim_playing) + if(panel_open || dirty >= MAX_MICROWAVE_DIRTINESS || broken || dirty_anim_playing) return . var/ingredient_count = 0 @@ -296,7 +296,7 @@ icon_state = "[base_icon_state]mwb" else if(dirty_anim_playing) icon_state = "[base_icon_state]mwbloody1" - else if(dirty == MAX_MICROWAVE_DIRTINESS) + else if(dirty >= MAX_MICROWAVE_DIRTINESS) icon_state = open ? "[base_icon_state]mwbloodyo" : "[base_icon_state]mwbloody" else if(operating) icon_state = "[base_icon_state]back_on" @@ -310,80 +310,83 @@ return ..() /obj/machinery/microwave/wrench_act(mob/living/user, obj/item/tool) - . = ..() - if(dirty >= MAX_MICROWAVE_DIRTINESS) - return FALSE if(default_unfasten_wrench(user, tool)) update_appearance() return TOOL_ACT_TOOLTYPE_SUCCESS /obj/machinery/microwave/crowbar_act(mob/living/user, obj/item/tool) - if(operating) - return if(!default_deconstruction_crowbar(tool)) return return TOOL_ACT_TOOLTYPE_SUCCESS /obj/machinery/microwave/screwdriver_act(mob/living/user, obj/item/tool) - if(operating) - return - if(dirty >= MAX_MICROWAVE_DIRTINESS) - return if(default_deconstruction_screwdriver(user, icon_state, icon_state, tool)) update_appearance() return TOOL_ACT_TOOLTYPE_SUCCESS -/obj/machinery/microwave/attackby(obj/item/item, mob/living/user, params) +/obj/machinery/microwave/wirecutter_act(mob/living/user, obj/item/tool) + if(broken != REALLY_BROKEN) + return + + user.visible_message( + span_notice("[user] starts to fix part of [src]."), + span_notice("You start to fix part of [src]..."), + ) + + if(!tool.use_tool(src, user, 2 SECONDS, volume = 50)) + return TOOL_ACT_SIGNAL_BLOCKING + + user.visible_message( + span_notice("[user] fixes part of [src]."), + span_notice("You fix part of [src]."), + ) + broken = KINDA_BROKEN // Fix it a bit + update_appearance() + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/machinery/microwave/welder_act(mob/living/user, obj/item/tool) + if(broken != KINDA_BROKEN) + return + + user.visible_message( + span_notice("[user] starts to fix part of [src]."), + span_notice("You start to fix part of [src]..."), + ) + + if(!tool.use_tool(src, user, 2 SECONDS, amount = 1, volume = 50)) + return TOOL_ACT_SIGNAL_BLOCKING + + user.visible_message( + span_notice("[user] fixes [src]."), + span_notice("You fix [src]."), + ) + broken = NOT_BROKEN + update_appearance() + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/machinery/microwave/tool_act(mob/living/user, obj/item/tool, tool_type, is_right_clicking) if(operating) return + if(dirty >= MAX_MICROWAVE_DIRTINESS) + return + + . = ..() + if(. & TOOL_ACT_MELEE_CHAIN_BLOCKING) + return - if(panel_open && is_wire_tool(item)) + if(panel_open && is_wire_tool(tool)) wires.interact(user) - return TRUE + return TOOL_ACT_SIGNAL_BLOCKING + +/obj/machinery/microwave/attackby(obj/item/item, mob/living/user, params) + if(operating) + return if(broken > NOT_BROKEN) - if(broken == REALLY_BROKEN && item.tool_behaviour == TOOL_WIRECUTTER) // If it's broken and they're using a TOOL_WIRECUTTER - user.visible_message(span_notice("[user] starts to fix part of \the [src]."), span_notice("You start to fix part of \the [src]...")) - if(item.use_tool(src, user, 20)) - user.visible_message(span_notice("[user] fixes part of \the [src]."), span_notice("You fix part of \the [src].")) - broken = KINDA_BROKEN // Fix it a bit - else if(broken == KINDA_BROKEN && item.tool_behaviour == TOOL_WELDER) // If it's broken and they're doing the wrench - user.visible_message(span_notice("[user] starts to fix part of \the [src]."), span_notice("You start to fix part of \the [src]...")) - if(item.use_tool(src, user, 20)) - user.visible_message(span_notice("[user] fixes \the [src]."), span_notice("You fix \the [src].")) - broken = NOT_BROKEN - update_appearance() - return FALSE //to use some fuel - else + if(IS_EDIBLE(item)) balloon_alert(user, "it's broken!") return TRUE - return - - if(istype(item, /obj/item/reagent_containers/spray)) - var/obj/item/reagent_containers/spray/clean_spray = item - open(autoclose = 2 SECONDS) - if(clean_spray.reagents.has_reagent(/datum/reagent/space_cleaner, clean_spray.amount_per_transfer_from_this)) - clean_spray.reagents.remove_reagent(/datum/reagent/space_cleaner, clean_spray.amount_per_transfer_from_this,1) - playsound(loc, 'sound/effects/spray3.ogg', 50, TRUE, -6) - user.visible_message(span_notice("[user] cleans \the [src]."), span_notice("You clean \the [src].")) - dirty = 0 - update_appearance() - else - to_chat(user, span_warning("You need more space cleaner!")) - return TRUE - - if(istype(item, /obj/item/soap) || istype(item, /obj/item/reagent_containers/cup/rag)) - var/cleanspeed = 50 - if(istype(item, /obj/item/soap)) - var/obj/item/soap/used_soap = item - cleanspeed = used_soap.cleanspeed - user.visible_message(span_notice("[user] starts to clean \the [src]."), span_notice("You start to clean \the [src]...")) - open(autoclose = cleanspeed + 1 SECONDS) - if(do_after(user, cleanspeed, target = src)) - user.visible_message(span_notice("[user] cleans \the [src]."), span_notice("You clean \the [src].")) - dirty = 0 - update_appearance() - return TRUE + return ..() if(istype(item, /obj/item/stock_parts/cell) && cell_powered) var/swapped = FALSE @@ -402,12 +405,16 @@ return TRUE if(!anchored) - balloon_alert(user, "not secured!") + if(IS_EDIBLE(item)) + balloon_alert(user, "not secured!") + return TRUE return ..() if(dirty >= MAX_MICROWAVE_DIRTINESS) // The microwave is all dirty so can't be used! - balloon_alert(user, "it's too dirty!") - return TRUE + if(IS_EDIBLE(item)) + balloon_alert(user, "it's too dirty!") + return TRUE + return ..() if(vampire_charging_capable && istype(item, /obj/item/modular_computer/pda) && ingredients.len > 0) balloon_alert(user, "max 1 pda!") @@ -509,7 +516,6 @@ if(isAI(user) && (machine_stat & NOPOWER)) return - user.set_machine(src) switch(choice) if("eject") eject() @@ -522,6 +528,15 @@ if("examine") examine(user) +/obj/machinery/microwave/wash(clean_types) + . = ..() + if(operating || !(clean_types & CLEAN_SCRUB)) + return . + + dirty = 0 + update_appearance() + return . || TRUE + /obj/machinery/microwave/proc/eject() var/atom/drop_loc = drop_location() for(var/atom/movable/movable_ingredient as anything in ingredients) @@ -578,7 +593,12 @@ non_food_ingedients-- if(istype(potential_fooditem, /obj/item/modular_computer/pda) && prob(75)) pda_failure = TRUE - notify_ghosts("[cooker] has overheated their PDA!", source = src, action = NOTIFY_JUMP, flashwindow = FALSE, header = "Hunger Games: Catching Fire") + notify_ghosts( + "[cooker] has overheated their PDA!", + source = src, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Hunger Games: Catching Fire", + ) // If we're cooking non-food items we can fail randomly if(length(non_food_ingedients) && prob(min(dirty * 5, 100))) diff --git a/code/modules/hallucination/body.dm b/code/modules/hallucination/body.dm index 5167b63c5eed4a..2d017f969679de 100644 --- a/code/modules/hallucination/body.dm +++ b/code/modules/hallucination/body.dm @@ -151,11 +151,11 @@ body_floats = TRUE /datum/hallucination/body/weird/faceless - body_image_file = 'icons/mob/simple/traders.dmi' + body_image_file = 'icons/obj/trader_signs.dmi' body_image_state = "faceless" /datum/hallucination/body/weird/bones - body_image_file = 'icons/mob/simple/traders.dmi' + body_image_file = 'icons/obj/trader_signs.dmi' body_image_state = "mrbones" /datum/hallucination/body/weird/freezer diff --git a/code/modules/hallucination/hazard.dm b/code/modules/hallucination/hazard.dm index 7209087d4be095..1dfdfd23970e73 100644 --- a/code/modules/hallucination/hazard.dm +++ b/code/modules/hallucination/hazard.dm @@ -86,6 +86,10 @@ image_state = "flux" image_layer = OBJ_LAYER + 0.01 +/obj/effect/client_image_holder/hallucination/danger/anomaly/generate_image() + . = ..() + apply_wibbly_filters(.) + /obj/effect/client_image_holder/hallucination/danger/anomaly/Initialize(mapload, list/mobs_which_see_us, datum/hallucination/parent) . = ..() START_PROCESSING(SSobj, src) diff --git a/code/modules/hallucination/mother.dm b/code/modules/hallucination/mother.dm index 70c4f13d173a92..bc2b312cc0b80d 100644 --- a/code/modules/hallucination/mother.dm +++ b/code/modules/hallucination/mother.dm @@ -16,7 +16,7 @@ mother = new(spawn_loc, hallucinator, src) mother.AddComponent(/datum/component/leash, owner = hallucinator, distance = get_dist(hallucinator, mother)) //basically makes mother follow them point_at(hallucinator) - talk("[hallucinator]!!!!") + talk("[capitalize(hallucinator.real_name)]!!!!") // Your mother won't be fooled by paltry disguises var/list/scold_lines = list( pick(list("CLEAN YOUR ROOM THIS INSTANT!", "IT'S TIME TO WAKE UP FOR SCHOOL!!")), pick(list("YOU INSULT YOUR GRANDPARENTS!", "USELESS!")), @@ -75,7 +75,19 @@ image_state = "" /obj/effect/client_image_holder/hallucination/your_mother/Initialize(mapload, list/mobs_which_see_us, datum/hallucination/parent) - . = ..() - var/mob/living/carbon/hallucinator = parent.hallucinator - image_icon = getFlatIcon(get_dynamic_human_appearance(/datum/outfit/yourmother, hallucinator.dna.species.type)) - regenerate_image() + var/mob/living/hallucinator = parent.hallucinator + if (ishuman(hallucinator)) + var/mob/living/carbon/dna_haver = hallucinator + image_icon = getFlatIcon(get_dynamic_human_appearance(/datum/outfit/yourmother, dna_haver.dna.species.type)) + return ..() + + if (istype(hallucinator, /mob/living/basic/pet/dog/corgi/ian)) + image_icon = getFlatIcon(get_dynamic_human_appearance(/datum/outfit/job/hop)) + name = "Head of Personnel" + return ..() + + image_icon = hallucinator.icon + image_state = hallucinator.icon_state + image_pixel_x = hallucinator.pixel_x + image_pixel_y = hallucinator.pixel_y + return ..() diff --git a/code/modules/hallucination/station_message.dm b/code/modules/hallucination/station_message.dm index eb55e548b3edd8..97b37e77cd9e26 100644 --- a/code/modules/hallucination/station_message.dm +++ b/code/modules/hallucination/station_message.dm @@ -16,8 +16,14 @@ /datum/hallucination/station_message/shuttle_dock /datum/hallucination/station_message/shuttle_dock/start() - priority_announce("[SSshuttle.emergency || "The Emergency Shuttle"] has docked with the station. You have 3 minutes to board the Emergency Shuttle.", \ - null, ANNOUNCER_SHUTTLEDOCK, ANNOUNCEMENT_TYPE_PRIORITY, players = list(hallucinator)) + priority_announce( + text = "[SSshuttle.emergency] has docked with the station. You have [DisplayTimeText(SSshuttle.emergency_dock_time)] to board the emergency shuttle.", + title = "Emergency Shuttle Arrival", + sound = ANNOUNCER_SHUTTLEDOCK, + sender_override = "Emergency Shuttle Uplink Alert", + players = list(hallucinator), + color_override = "orange", + ) return ..() /datum/hallucination/station_message/malf_ai @@ -49,7 +55,13 @@ var/message_with_name = pick(ascension_bodies) message_with_name = replacetext(message_with_name, "%FAKENAME%", totally_real_heretic.real_name) - priority_announce("[generate_heretic_text()] [message_with_name] [generate_heretic_text()]","[generate_heretic_text()]", ANNOUNCER_SPANOMALIES, players = list(hallucinator)) + priority_announce( + text = "[generate_heretic_text()] [message_with_name] [generate_heretic_text()]", + title = "[generate_heretic_text()]", + sound = ANNOUNCER_SPANOMALIES, + players = list(hallucinator), + color_override = "pink", + ) return ..() /datum/hallucination/station_message/cult_summon @@ -65,10 +77,13 @@ var/area/fake_summon_area_type = pick(GLOB.the_station_areas - hallucinator_area.type) var/area/fake_summon_area = GLOB.areas_by_type[fake_summon_area_type] - priority_announce("Figments from an eldritch god are being summoned by [totally_real_cult_leader.real_name] \ - into [fake_summon_area] from an unknown dimension. Disrupt the ritual at all costs!", \ - "Central Command Higher Dimensional Affairs", \ - sound = 'sound/ambience/antag/bloodcult/bloodcult_scribe.ogg', has_important_message = TRUE, players = list(hallucinator)) + priority_announce( + text = "Figments from an eldritch god are being summoned by [totally_real_cult_leader.real_name] into [fake_summon_area] from an unknown dimension. Disrupt the ritual at all costs!", + title = "[command_name()] Higher Dimensional Affairs", + sound = 'sound/ambience/antag/bloodcult/bloodcult_scribe.ogg', + has_important_message = TRUE, + players = list(hallucinator), + ) return ..() /datum/hallucination/station_message/meteors diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index f66fe88a7e56c0..035f44ae11d266 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -27,6 +27,8 @@ var/poster_icon = "holiday_unfinished" /// Color scheme for this holiday var/list/holiday_colors + /// The default pattern of the holiday, if the requested pattern is null. + var/holiday_pattern = PATTERN_DEFAULT // This proc gets run before the game starts when the holiday is activated. Do festive shit here. /datum/holiday/proc/celebrate() @@ -78,7 +80,7 @@ return FALSE /// Procs to return holiday themed colors for recoloring atoms -/datum/holiday/proc/get_holiday_colors(atom/thing_to_color, pattern = PATTERN_DEFAULT) +/datum/holiday/proc/get_holiday_colors(atom/thing_to_color, pattern = holiday_pattern) if(!holiday_colors) return switch(pattern) @@ -87,7 +89,7 @@ if(PATTERN_VERTICAL_STRIPE) return holiday_colors[(thing_to_color.x % holiday_colors.len) + 1] -/proc/request_holiday_colors(atom/thing_to_color, pattern = PATTERN_DEFAULT) +/proc/request_holiday_colors(atom/thing_to_color, pattern) switch(pattern) if(PATTERN_RANDOM) return "#[random_short_color()]" @@ -98,7 +100,9 @@ return for(var/holiday_key in GLOB.holidays) var/datum/holiday/holiday_real = GLOB.holidays[holiday_key] - return holiday_real.get_holiday_colors(thing_to_color, pattern) + if(!holiday_real.holiday_colors) + continue + return holiday_real.get_holiday_colors(thing_to_color, pattern || holiday_real.holiday_pattern) // The actual holidays @@ -132,6 +136,12 @@ timezones = list(TIMEZONE_NZDT, TIMEZONE_CHADT) begin_day = 6 begin_month = FEBRUARY + holiday_colors = list( + COLOR_UNION_JACK_BLUE, + COLOR_WHITE, + COLOR_UNION_JACK_RED, + COLOR_WHITE, + ) /datum/holiday/nz/getStationPrefix() return pick("Aotearoa","Kiwi","Fish 'n' Chips","Kākāpō","Southern Cross") @@ -222,6 +232,12 @@ begin_day = 17 begin_month = MARCH holiday_hat = /obj/item/clothing/head/soft/green + holiday_colors = list( + COLOR_IRISH_GREEN, + COLOR_WHITE, + COLOR_IRISH_ORANGE, + ) + holiday_pattern = PATTERN_VERTICAL_STRIPE /datum/holiday/no_this_is_patrick/getStationPrefix() return pick("Blarney","Green","Leprechaun","Booze") @@ -264,6 +280,11 @@ begin_day = 20 begin_month = APRIL holiday_hat = /obj/item/clothing/head/rasta + holiday_colors = list( + COLOR_ETHIOPIA_GREEN, + COLOR_ETHIOPIA_YELLOW, + COLOR_ETHIOPIA_RED, + ) /datum/holiday/fourtwenty/getStationPrefix() return pick("Snoop","Blunt","Toke","Dank","Cheech","Chong") @@ -366,12 +387,12 @@ begin_day = 23 end_day = 29 holiday_colors = list( - COLOR_PRIDE_PURPLE, - COLOR_PRIDE_BLUE, - COLOR_PRIDE_GREEN, - COLOR_PRIDE_YELLOW, - COLOR_PRIDE_ORANGE, - COLOR_PRIDE_RED, + COLOR_PRIDE_PURPLE, + COLOR_PRIDE_BLUE, + COLOR_PRIDE_GREEN, + COLOR_PRIDE_YELLOW, + COLOR_PRIDE_ORANGE, + COLOR_PRIDE_RED, ) // JULY @@ -398,6 +419,14 @@ begin_month = JULY mail_holiday = TRUE holiday_hat = /obj/item/clothing/head/cowboy/brown + holiday_colors = list( + COLOR_OLD_GLORY_BLUE, + COLOR_OLD_GLORY_RED, + COLOR_WHITE, + COLOR_OLD_GLORY_RED, + COLOR_WHITE, + ) + /datum/holiday/usa/getStationPrefix() return pick("Independent","American","Burger","Bald Eagle","Star-Spangled", "Fireworks") @@ -414,9 +443,15 @@ begin_month = JULY holiday_hat = /obj/item/clothing/head/beret mail_holiday = TRUE + holiday_colors = list( + COLOR_FRENCH_BLUE, + COLOR_WHITE, + COLOR_FRENCH_RED + ) + holiday_pattern = PATTERN_VERTICAL_STRIPE /datum/holiday/france/getStationPrefix() - return pick("Francais","Fromage", "Zut", "Merde") + return pick("Francais", "Fromage", "Zut", "Merde", "Sacrebleu") /datum/holiday/france/greet() return "Do you hear the people sing?" @@ -463,6 +498,7 @@ name = "Independence Day of Ukraine" begin_month = AUGUST begin_day = 24 + holiday_colors = list(COLOR_TRUE_BLUE, COLOR_TANGERINE_YELLOW) /datum/holiday/ukraine/getStationPrefix() return pick("Kyiv", "Ukraine") @@ -576,6 +612,11 @@ begin_day = 6 begin_month = NOVEMBER end_day = 7 + holiday_colors = list( + COLOR_MEDIUM_DARK_RED, + COLOR_GOLD, + COLOR_MEDIUM_DARK_RED, + ) /datum/holiday/october_revolution/getStationPrefix() return pick("Communist", "Soviet", "Bolshevik", "Socialist", "Red", "Workers'") @@ -662,6 +703,10 @@ end_day = 27 holiday_hat = /obj/item/clothing/head/costume/santa mail_holiday = TRUE + holiday_colors = list( + COLOR_CHRISTMAS_GREEN, + COLOR_CHRISTMAS_RED, + ) /datum/holiday/xmas/getStationPrefix() return pick( diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index 1f2951b33566e2..67256249732090 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -315,6 +315,11 @@ if(!food_to_convert) break + if(food_to_convert.flags_1 & HOLOGRAM_1) + qdel(food_to_convert) + current_item_count = max(current_item_count - 1, 0) + continue + convert_to_biomass(food_to_convert) use_power(active_power_usage * seconds_per_tick) diff --git a/code/modules/hydroponics/grown/beans.dm b/code/modules/hydroponics/grown/beans.dm index 8643c616b4757f..fb827377114046 100644 --- a/code/modules/hydroponics/grown/beans.dm +++ b/code/modules/hydroponics/grown/beans.dm @@ -14,7 +14,7 @@ icon_grow = "soybean-grow" icon_dead = "soybean-dead" genes = list(/datum/plant_gene/trait/repeated_harvest) - mutatelist = list(/obj/item/seeds/soya/koi) + mutatelist = list(/obj/item/seeds/soya/koi, /obj/item/seeds/soya/butter) reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05, /datum/reagent/consumable/nutriment/fat/oil = 0.03) //Vegetable oil! /obj/item/food/grown/soybeans @@ -26,7 +26,7 @@ foodtypes = VEGETABLES grind_results = list(/datum/reagent/consumable/soymilk = 0) tastes = list("soy" = 1) - wine_power = 20 + distill_reagent = /datum/reagent/consumable/soysauce // Koibean /obj/item/seeds/soya/koi @@ -39,7 +39,7 @@ potency = 10 mutatelist = null reagents_add = list(/datum/reagent/toxin/carpotoxin = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05) - rarity = 20 + rarity = PLANT_MODERATELY_RARE /obj/item/food/grown/koibeans seed = /obj/item/seeds/soya/koi @@ -50,6 +50,38 @@ tastes = list("koi" = 1) wine_power = 40 +//Butterbeans, the beans wid da butta! +// Butterbeans! - Squeeze for a single butter slice! +/obj/item/seeds/soya/butter + name = "pack of butterbean seeds" + desc = "These seeds grow into butterbean plants." + icon_state = "seed-butterbean" + species = "butterbean" + plantname = "butterbean Plants" + product = /obj/item/food/grown/butterbeans + potency = 10 + mutatelist = null + reagents_add = list(/datum/reagent/consumable/milk = 0.05, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/cream = 0.05) + rarity = 20 + +/obj/item/food/grown/butterbeans + seed = /obj/item/seeds/soya/butter + name = "butterbean" + desc = "Soft, creamy and milky... You could almost smear them over toast." + icon_state = "butterbeans" + foodtypes = VEGETABLES | DAIRY + tastes = list("creamy butter" = 1) + distill_reagent = /datum/reagent/consumable/yoghurt + +/obj/item/food/grown/butterbeans/attack_self(mob/living/user) + user.visible_message(span_notice("[user] crushes [src] into a pat of butter."), span_notice("You crush [src] into something that resembles butter.")) + playsound(user, 'sound/effects/blobattack.ogg', 50, TRUE) + var/obj/item/food/butterslice/butties = new(null) + butties.reagents.set_all_reagents_purity(seed.get_reagent_purity()) + qdel(src) + user.put_in_hands(butties) + return TRUE + // Green Beans /obj/item/seeds/greenbean name = "pack of green bean seeds" @@ -96,7 +128,7 @@ mutatelist = null reagents_add = list(/datum/reagent/consumable/nutriment = 0.05, /datum/reagent/ants = 0.1) //IRL jumping beans contain insect larve, hence the ants graft_gene = /datum/plant_gene/trait/stable_stats - rarity = 20 + rarity = PLANT_MODERATELY_RARE /obj/item/food/grown/jumpingbeans seed = /obj/item/seeds/greenbean/jump @@ -105,4 +137,3 @@ icon_state = "jumpingbean" foodtypes = FRUIT | BUGS tastes = list("bugs" = 1) - diff --git a/code/modules/hydroponics/grown/berries.dm b/code/modules/hydroponics/grown/berries.dm index 45b0db82ea3270..233765609200fd 100644 --- a/code/modules/hydroponics/grown/berries.dm +++ b/code/modules/hydroponics/grown/berries.dm @@ -92,7 +92,7 @@ mutatelist = null genes = list(/datum/plant_gene/trait/glow/white, /datum/plant_gene/trait/repeated_harvest) reagents_add = list(/datum/reagent/uranium = 0.25, /datum/reagent/iodine = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1) - rarity = 20 + rarity = PLANT_MODERATELY_RARE graft_gene = /datum/plant_gene/trait/glow/white /obj/item/food/grown/berries/glow @@ -188,3 +188,34 @@ juice_typepath = /datum/reagent/consumable/toechtauese_juice tastes = list("fiery itchy pain" = 1) distill_reagent = /datum/reagent/toxin/itching_powder + +/obj/item/seeds/lanternfruit + name = "pack of lanternfruit seeds" + desc = "These seeds grow into lanternfruit pods." + icon_state = "seed-lanternfruit" + species = "lanternfruit" + plantname = "Lanternfruit Pod" + product = /obj/item/food/grown/lanternfruit + lifespan = 35 + endurance = 35 + maturation = 5 + production = 5 + growthstages = 3 + instability = 15 + growing_icon = 'icons/obj/service/hydroponics/growing_fruits.dmi' + icon_grow = "lanternfruit-grow" + icon_dead = "lanternfruit-dead" + icon_harvest = "lanternfruit-harvest" + genes = list(/datum/plant_gene/trait/glow/yellow) + mutatelist = null + reagents_add = list(/datum/reagent/sulfur = 0.07, /datum/reagent/consumable/sugar = 0.07, /datum/reagent/consumable/liquidelectricity = 0.07) + graft_gene = /datum/plant_gene/trait/glow/yellow + +/obj/item/food/grown/lanternfruit + seed = /obj/item/seeds/lanternfruit + name = "lanternfruits" + desc = "A sofly glowing fruit with a handle-shaped stem, an Ethereal favorite!" + icon_state = "lanternfruit" + foodtypes = FRUIT + tastes = list("tv static" = 1, "sour pear" = 1, "grapefruit" = 1) + distill_reagent = /datum/reagent/consumable/ethanol/wine_voltaic diff --git a/code/modules/hydroponics/grown/chili.dm b/code/modules/hydroponics/grown/chili.dm index ee5c87a40c359c..9f6d3bbd08ce0e 100644 --- a/code/modules/hydroponics/grown/chili.dm +++ b/code/modules/hydroponics/grown/chili.dm @@ -39,7 +39,7 @@ lifespan = 25 maturation = 4 production = 4 - rarity = 20 + rarity = PLANT_MODERATELY_RARE genes = list(/datum/plant_gene/trait/chem_cooling) mutatelist = null reagents_add = list(/datum/reagent/consumable/frostoil = 0.25, /datum/reagent/consumable/nutriment/vitamin = 0.02, /datum/reagent/consumable/nutriment = 0.02) @@ -66,7 +66,7 @@ maturation = 10 production = 10 yield = 3 - rarity = 20 + rarity = PLANT_MODERATELY_RARE genes = list(/datum/plant_gene/trait/chem_heating, /datum/plant_gene/trait/backfire/chili_heat) mutatelist = null reagents_add = list(/datum/reagent/consumable/condensedcapsaicin = 0.3, /datum/reagent/consumable/capsaicin = 0.55, /datum/reagent/consumable/nutriment = 0.04) @@ -93,7 +93,7 @@ maturation = 10 production = 10 yield = 3 - rarity = 20 + rarity = PLANT_MODERATELY_RARE genes = list(/datum/plant_gene/trait/repeated_harvest) mutatelist = null reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.08, /datum/reagent/consumable/nutriment = 0.04) diff --git a/code/modules/hydroponics/grown/corn.dm b/code/modules/hydroponics/grown/corn.dm index 1b3a7979cf0587..8eab962d751181 100644 --- a/code/modules/hydroponics/grown/corn.dm +++ b/code/modules/hydroponics/grown/corn.dm @@ -13,7 +13,7 @@ growing_icon = 'icons/obj/service/hydroponics/growing_vegetables.dmi' icon_grow = "corn-grow" // Uses one growth icons set for all the subtypes icon_dead = "corn-dead" // Same for the dead icon - mutatelist = list(/obj/item/seeds/corn/snapcorn) + mutatelist = list(/obj/item/seeds/corn/snapcorn, /obj/item/seeds/corn/pepper) reagents_add = list(/datum/reagent/consumable/nutriment/fat/oil/corn = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1) /obj/item/food/grown/corn @@ -97,3 +97,29 @@ seed = /obj/item/seeds/corn/snapcorn name = "snap corn cob" desc = "A reminder of pranks gone by." + +//Pepper-corn - Heh funny. +/obj/item/seeds/corn/pepper + name = "pack of pepper-corn seeds" + desc = "If Peter picked a pack of pepper-corn..." + icon_state = "seed-peppercorn" + species = "peppercorn" + plantname = "Pepper-Corn Stalks" + product = /obj/item/food/grown/peppercorn + mutatelist = null + reagents_add = list(/datum/reagent/consumable/blackpepper = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1) + +/obj/item/food/grown/peppercorn + seed = /obj/item/seeds/corn/pepper + name = "ear of pepper-peppercorn" + desc = "This dusty monster needs god..." + icon_state = "peppercorn" + trash_type = /obj/item/grown/corncob/pepper + foodtypes = VEGETABLES + grind_results = list(/datum/reagent/consumable/blackpepper = 0) + tastes = list("pepper" = 1, "sneezing" = 1) + +/obj/item/grown/corncob/pepper + seed = /obj/item/seeds/corn/pepper + name = "pepper corn cob" + desc = "A reminder of genetic abominations gone by." diff --git a/code/modules/hydroponics/grown/flowers.dm b/code/modules/hydroponics/grown/flowers.dm index 333c7f57c4584c..84b1414335cafa 100644 --- a/code/modules/hydroponics/grown/flowers.dm +++ b/code/modules/hydroponics/grown/flowers.dm @@ -242,7 +242,7 @@ genes = list(/datum/plant_gene/trait/backfire/novaflower_heat, /datum/plant_gene/trait/attack/novaflower_attack, /datum/plant_gene/trait/preserved) mutatelist = null reagents_add = list(/datum/reagent/consumable/condensedcapsaicin = 0.25, /datum/reagent/consumable/capsaicin = 0.3, /datum/reagent/consumable/nutriment = 0, /datum/reagent/toxin/acid = 0.05) - rarity = 20 + rarity = PLANT_MODERATELY_RARE /obj/item/grown/novaflower seed = /obj/item/seeds/sunflower/novaflower diff --git a/code/modules/hydroponics/grown/korta_nut.dm b/code/modules/hydroponics/grown/korta_nut.dm index bf6ab82d474101..cfa6c1e5b51f33 100644 --- a/code/modules/hydroponics/grown/korta_nut.dm +++ b/code/modules/hydroponics/grown/korta_nut.dm @@ -39,7 +39,7 @@ production = 10 mutatelist = null reagents_add = list(/datum/reagent/consumable/korta_nectar = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1) - rarity = 20 + rarity = PLANT_MODERATELY_RARE /obj/item/food/grown/korta_nut/sweet seed = /obj/item/seeds/korta_nut/sweet diff --git a/code/modules/hydroponics/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm index f69f8a68317cb0..0e59231141fc43 100644 --- a/code/modules/hydroponics/grown/melon.dm +++ b/code/modules/hydroponics/grown/melon.dm @@ -50,7 +50,7 @@ genes = list(/datum/plant_gene/trait/glow/yellow, /datum/plant_gene/trait/anti_magic) mutatelist = null reagents_add = list(/datum/reagent/water/holywater = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1) - rarity = 20 + rarity = PLANT_MODERATELY_RARE graft_gene = /datum/plant_gene/trait/glow/yellow /obj/item/food/grown/holymelon diff --git a/code/modules/hydroponics/grown/mushrooms.dm b/code/modules/hydroponics/grown/mushrooms.dm index 074f9d5f8d2fb1..bfc50f0c483b3b 100644 --- a/code/modules/hydroponics/grown/mushrooms.dm +++ b/code/modules/hydroponics/grown/mushrooms.dm @@ -238,7 +238,7 @@ potency = 30 //-> brightness instability = 20 growthstages = 4 - rarity = 20 + rarity = PLANT_MODERATELY_RARE genes = list(/datum/plant_gene/trait/glow, /datum/plant_gene/trait/plant_type/fungal_metabolism) growing_icon = 'icons/obj/service/hydroponics/growing_mushrooms.dmi' mutatelist = list(/obj/item/seeds/glowshroom/glowcap, /obj/item/seeds/glowshroom/shadowshroom) diff --git a/code/modules/hydroponics/grown/pumpkin.dm b/code/modules/hydroponics/grown/pumpkin.dm index 561bd5119aa73b..11130c153344ab 100644 --- a/code/modules/hydroponics/grown/pumpkin.dm +++ b/code/modules/hydroponics/grown/pumpkin.dm @@ -48,7 +48,7 @@ product = /obj/item/food/grown/pumpkin/blumpkin mutatelist = null reagents_add = list(/datum/reagent/ammonia = 0.2, /datum/reagent/chlorine = 0.1, /datum/reagent/consumable/nutriment = 0.2) - rarity = 20 + rarity = PLANT_MODERATELY_RARE /obj/item/food/grown/pumpkin/blumpkin seed = /obj/item/seeds/pumpkin/blumpkin diff --git a/code/modules/hydroponics/grown/sugarcane.dm b/code/modules/hydroponics/grown/sugarcane.dm index 9a1646443dcd16..be2214ca1d048d 100644 --- a/code/modules/hydroponics/grown/sugarcane.dm +++ b/code/modules/hydroponics/grown/sugarcane.dm @@ -15,7 +15,7 @@ instability = 15 growthstages = 2 reagents_add = list(/datum/reagent/consumable/nutriment = 0.04, /datum/reagent/consumable/sugar = 0.25) - mutatelist = list(/obj/item/seeds/bamboo) + mutatelist = list(/obj/item/seeds/bamboo, /obj/item/seeds/sugarcane/saltcane) /obj/item/food/grown/sugarcane seed = /obj/item/seeds/sugarcane @@ -56,3 +56,25 @@ /obj/item/grown/log/bamboo/CheckAccepted(obj/item/I) return FALSE + +//Saltcane - Gross, salty shafts! +/obj/item/seeds/sugarcane/saltcane + name = "pack of saltcane seeds" + desc = "These seeds grow into saltcane." + icon_state = "seed-saltcane" + species = "saltcane" + plantname = "Saltcane" + product = /obj/item/food/grown/sugarcane/saltcane + genes = list(/datum/plant_gene/trait/repeated_harvest) + reagents_add = list(/datum/reagent/consumable/nutriment = 0.04, /datum/reagent/consumable/salt = 0.25) + mutatelist = null + +/obj/item/food/grown/sugarcane/saltcane + seed = /obj/item/seeds/sugarcane/saltcane + name = "saltcane" + desc = "Ungodly salty, bane of slugs, treasure of horses." + icon_state = "saltcane" + foodtypes = VEGETABLES | GROSS + +/obj/item/food/grown/sugarcane/saltcane/make_dryable() + AddElement(/datum/element/dryable, /obj/item/food/seaweedsheet/saltcane) //soooshi diff --git a/code/modules/hydroponics/grown/tea_coffee.dm b/code/modules/hydroponics/grown/tea_coffee.dm index 72ef53545d04c9..366dd8b45237ec 100644 --- a/code/modules/hydroponics/grown/tea_coffee.dm +++ b/code/modules/hydroponics/grown/tea_coffee.dm @@ -34,7 +34,7 @@ product = /obj/item/food/grown/tea/astra mutatelist = null reagents_add = list(/datum/reagent/medicine/synaptizine = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/toxin/teapowder = 0.1) - rarity = 20 + rarity = PLANT_MODERATELY_RARE /obj/item/food/grown/tea/astra seed = /obj/item/seeds/tea/astra @@ -83,7 +83,7 @@ product = /obj/item/food/grown/coffee/robusta mutatelist = null reagents_add = list(/datum/reagent/medicine/ephedrine = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/toxin/coffeepowder = 0.1) - rarity = 20 + rarity = PLANT_MODERATELY_RARE /obj/item/food/grown/coffee/robusta seed = /obj/item/seeds/coffee/robusta diff --git a/code/modules/hydroponics/grown/tobacco.dm b/code/modules/hydroponics/grown/tobacco.dm index c47bdfc32f6646..87f8253a4d96b5 100644 --- a/code/modules/hydroponics/grown/tobacco.dm +++ b/code/modules/hydroponics/grown/tobacco.dm @@ -32,7 +32,7 @@ product = /obj/item/food/grown/tobacco/space mutatelist = null reagents_add = list(/datum/reagent/medicine/salbutamol = 0.05, /datum/reagent/drug/nicotine = 0.08, /datum/reagent/consumable/nutriment = 0.03) - rarity = 20 + rarity = PLANT_MODERATELY_RARE /obj/item/food/grown/tobacco/space seed = /obj/item/seeds/tobacco/space diff --git a/code/modules/hydroponics/grown/tomato.dm b/code/modules/hydroponics/grown/tomato.dm index c2fa44c76625f4..e676d822bbf1a8 100644 --- a/code/modules/hydroponics/grown/tomato.dm +++ b/code/modules/hydroponics/grown/tomato.dm @@ -37,7 +37,7 @@ product = /obj/item/food/grown/tomato/blood mutatelist = null reagents_add = list(/datum/reagent/blood = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1) - rarity = 20 + rarity = PLANT_MODERATELY_RARE /obj/item/food/grown/tomato/blood seed = /obj/item/seeds/tomato/blood @@ -63,7 +63,7 @@ mutatelist = list(/obj/item/seeds/tomato/blue/bluespace) genes = list(/datum/plant_gene/trait/slip, /datum/plant_gene/trait/repeated_harvest) reagents_add = list(/datum/reagent/lube = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1) - rarity = 20 + rarity = PLANT_MODERATELY_RARE graft_gene = /datum/plant_gene/trait/slip /obj/item/food/grown/tomato/blue diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm index 3012a1f14793b4..046e835c50ca51 100644 --- a/code/modules/hydroponics/grown/towercap.dm +++ b/code/modules/hydroponics/grown/towercap.dm @@ -28,7 +28,7 @@ product = /obj/item/grown/log/steel mutatelist = null reagents_add = list(/datum/reagent/cellulose = 0.05, /datum/reagent/iron = 0.05) - rarity = 20 + rarity = PLANT_MODERATELY_RARE /obj/item/grown/log seed = /obj/item/seeds/tower diff --git a/code/modules/hydroponics/grown/weeds/nettle.dm b/code/modules/hydroponics/grown/weeds/nettle.dm index 316cc7723acb82..98868b8d6e748b 100644 --- a/code/modules/hydroponics/grown/weeds/nettle.dm +++ b/code/modules/hydroponics/grown/weeds/nettle.dm @@ -29,7 +29,7 @@ genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/plant_type/weed_hardy, /datum/plant_gene/trait/stinging, /datum/plant_gene/trait/attack/nettle_attack/death, /datum/plant_gene/trait/backfire/nettle_burn/death) mutatelist = null reagents_add = list(/datum/reagent/toxin/acid/fluacid = 0.5, /datum/reagent/toxin/acid = 0.5) - rarity = 20 + rarity = PLANT_MODERATELY_RARE graft_gene = /datum/plant_gene/trait/stinging /obj/item/food/grown/nettle // "snack" diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 95f118a0c91571..cc95f5467f30b0 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -60,8 +60,8 @@ //SO HERE LIES THE "nutrilevel" VAR. IT'S DEAD AND I PUT IT OUT OF IT'S MISERY. USE "reagents" INSTEAD. ~ArcaneMusic, accept no substitutes. create_reagents(maxnutri, INJECTABLE) if(mapload) - reagents.add_reagent(/datum/reagent/plantnutriment/eznutriment, 10) //Half filled nutrient trays for dirt trays to have more to grow with in prison/lavaland. - waterlevel = 100 + reagents.add_reagent(/datum/reagent/plantnutriment/eznutriment, max(maxnutri / 2, 10)) //Half filled nutrient trays for dirt trays to have more to grow with in prison/lavaland. + waterlevel = maxwater . = ..() var/static/list/hovering_item_typechecks = list( @@ -161,6 +161,7 @@ AddComponent(/datum/component/simple_rotation) AddComponent(/datum/component/plumbing/hydroponics) AddComponent(/datum/component/usb_port, list(/obj/item/circuit_component/hydroponics)) + AddComponent(/datum/component/fishing_spot, /datum/fish_source/hydro_tray) /obj/machinery/hydroponics/constructable/RefreshParts() . = ..() diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index 48621abfd1a585..ecbcc397dbab50 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -323,13 +323,14 @@ GLOBAL_LIST_INIT(bibleitemstates, list( playsound(src,'sound/effects/pray_chaplain.ogg',60,TRUE) for(var/obj/item/soulstone/stone in sword.contents) stone.required_role = null - for(var/mob/living/simple_animal/shade/shade in stone) + for(var/mob/living/basic/shade/shade in stone) var/datum/antagonist/cult/cultist = shade.mind.has_antag_datum(/datum/antagonist/cult) if(cultist) cultist.silent = TRUE cultist.on_removal() - shade.icon_state = "shade_holy" - shade.name = "Purified [shade.name]" + shade.theme = THEME_HOLY + shade.name = "Purified [shade.real_name]" + shade.update_appearance(UPDATE_ICON_STATE) stone.release_shades(user) qdel(stone) new /obj/item/nullrod/claymore(get_turf(sword)) diff --git a/code/modules/library/book.dm b/code/modules/library/book.dm index e706872c710f74..19b65f82489ea5 100644 --- a/code/modules/library/book.dm +++ b/code/modules/library/book.dm @@ -21,8 +21,6 @@ /// whether or not we have been carved out var/carved = FALSE - /// Specific window size for the book, i.e: "1920x1080", Size x Width - var/window_size = null /// The initial title, for use in var editing and such var/starting_title /// The initial author, for use in var editing and such @@ -51,35 +49,53 @@ return data /obj/item/book/ui_interact(mob/living/user, datum/tgui/ui) - if(carved) - balloon_alert(user, "book is carved out!") - return - if(!length(book_data.get_content())) - balloon_alert(user, "book is blank!") - return - - if(istype(user) && !isnull(user.mind)) - LAZYINITLIST(user.mind.book_titles_read) - var/has_not_read_book = !(starting_title in user.mind.book_titles_read) - if(has_not_read_book) - user.add_mood_event("book_nerd", /datum/mood_event/book_nerd) - user.mind.book_titles_read[starting_title] = TRUE - ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "MarkdownViewer", name) ui.open() -/obj/item/book/attack_self(mob/user) +/// Proc that handles sending the book information to the user, as well as some housekeeping stuff. +/obj/item/book/proc/display_content(mob/living/user) + credit_book_to_reader(user) + ui_interact(user) + +/// Proc that checks if the user is capable of reading the book, for UI interactions and otherwise. Returns TRUE if they can, FALSE if they can't. +/obj/item/book/proc/can_read_book(mob/living/user) if(user.is_blind()) to_chat(user, span_warning("You are blind and can't read anything!")) - return + return FALSE if(!user.can_read(src)) + return FALSE + + if(carved) + balloon_alert(user, "book is carved out!") + return FALSE + + if(!length(book_data.get_content())) + balloon_alert(user, "book is blank!") + return FALSE + + return TRUE + +/// Proc that adds the book to a list on the user's mind so we know what works of art they've been catching up on. +/obj/item/book/proc/credit_book_to_reader(mob/living/user) + if(!isliving(user) || isnull(user.mind)) + return + + LAZYINITLIST(user.mind.book_titles_read) + if(starting_title in user.mind.book_titles_read) + return + + user.add_mood_event("book_nerd", /datum/mood_event/book_nerd) + user.mind.book_titles_read[starting_title] = TRUE + +/obj/item/book/attack_self(mob/user) + if(!can_read_book(user)) return user.visible_message(span_notice("[user] opens a book titled \"[book_data.title]\" and begins reading intently.")) - ui_interact(user) + display_content(user) /obj/item/book/attackby(obj/item/attacking_item, mob/living/user, params) if(burn_paper_product_attackby_check(attacking_item, user)) diff --git a/code/modules/mafia/controller.dm b/code/modules/mafia/controller.dm index 967ae9b39a30d9..a6e1e3c5f7f11c 100644 --- a/code/modules/mafia/controller.dm +++ b/code/modules/mafia/controller.dm @@ -56,9 +56,6 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) ///current timer for phase var/next_phase_timer - ///used for debugging in testing (doesn't put people out of the game, some other shit i forgot, who knows just don't set this in live) honestly kinda deprecated - var/debug = FALSE - ///was our game forced to start early? var/early_start = FALSE @@ -110,6 +107,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) /datum/mafia_controller/Destroy(force, ...) . = ..() end_game() + player_role_lookup.Cut() QDEL_NULL(map_deleter) if(GLOB.mafia_game == src) GLOB.mafia_game = null @@ -126,10 +124,9 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) * * Puts players in each role randomly * Arguments: * * setup_list: list of all the datum setups (fancy list of roles) that would work for the game - * * ready_ghosts: list of filtered, sane players (so not playing or disconnected) for the game to put into roles - * * ready_pdas: list of PDAs wanting to play the Mafia game. + * * ready_ghosts_and_pdas: list of filtered, sane (so not playing or disconnected) ghost ckeys & PDAs for the game to put into roles. */ -/datum/mafia_controller/proc/prepare_game(setup_list, ready_ghosts, ready_pdas) +/datum/mafia_controller/proc/prepare_game(setup_list, ready_ghosts_and_pdas) var/static/list/possible_maps = subtypesof(/datum/map_template/mafia) var/turf/spawn_area = get_turf(locate(/obj/effect/landmark/mafia_game_area) in GLOB.landmarks_list) @@ -141,8 +138,11 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) var/list/bounds = current_map.load(spawn_area) if(!bounds) CRASH("Loading mafia map failed!") - map_deleter.defineRegion(spawn_area, locate(spawn_area.x + 23,spawn_area.y + 23,spawn_area.z), replace = TRUE) //so we're ready to mass delete when round ends - +#ifdef UNIT_TESTS //unit test map is smaller + map_deleter.defineRegion(spawn_area, locate(spawn_area.x + 7, spawn_area.y + 7, spawn_area.z), replace = TRUE) //so we're ready to mass delete when round ends +#else + map_deleter.defineRegion(spawn_area, locate(spawn_area.x + 23, spawn_area.y + 23, spawn_area.z), replace = TRUE) //so we're ready to mass delete when round ends +#endif if(!landmarks.len)//we grab town center when we grab landmarks, if there is none (the first game signed up for let's grab them post load) for(var/obj/effect/landmark/mafia/possible_spawn in GLOB.landmarks_list) if(istype(possible_spawn, /obj/effect/landmark/mafia/town_center)) @@ -161,23 +161,14 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) var/list/spawnpoints = landmarks.Copy() for(var/datum/mafia_role/role as anything in all_roles) role.assigned_landmark = pick_n_take(spawnpoints) - var/selected_player - if(!debug) - if(length(ready_pdas)) - selected_player = pick(ready_pdas) - else - selected_player = pick(ready_ghosts) + var/selected_player //this can be a ckey or a PDA + selected_player = pick(ready_ghosts_and_pdas) + var/client/player_client = GLOB.directory[selected_player] + if(player_client) + role.player_key = selected_player else - if(length(ready_pdas)) - selected_player = peek(ready_pdas) - else - selected_player = peek(ready_ghosts) - if(selected_player in ready_pdas) role.player_pda = selected_player - ready_pdas -= selected_player - else - role.player_key = selected_player - ready_ghosts -= selected_player + ready_ghosts_and_pdas -= selected_player ///Sends a global message to all players, or just 'team' if set. /datum/mafia_controller/proc/send_message(msg, team, log_only = FALSE) @@ -400,11 +391,12 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) if(!rewarded.player_pda) return for(var/datum/tgui/window as anything in rewarded.player_pda.open_uis) - window.user?.client?.give_award(award, rewarded.body) + window.user?.client?.give_award(award, window.user.client.mob) /** * The end of the game is in two procs, because we want a bit of time for players to see eachothers roles. * Because of how check_victory works, the game is halted in other places by this point. + * We won't delete ourselves in a certain amount of time in unit tests, as the unit test will handle our deletion instead. * * What players do in this phase: * * See everyone's role postgame @@ -419,7 +411,9 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) roles.mafia_alert.update_text("[message]") roles.reveal_role(src) phase = MAFIA_PHASE_VICTORY_LAP +#ifndef UNIT_TESTS next_phase_timer = QDEL_IN_STOPPABLE(src, VICTORY_LAP_PERIOD_LENGTH) +#endif /** * Cleans up the game, resetting variables back to the beginning and removing the map with the generator. @@ -586,7 +580,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) if(phase != MAFIA_PHASE_VOTING) return - var/v = get_vote_count(player_role_lookup[source],"Day") + var/v = get_vote_count(get_role_player(source),"Day") var/mutable_appearance/MA = mutable_appearance('icons/obj/mafia.dmi',"vote_[v > 12 ? "over_12" : v]") overlay_list += MA @@ -612,310 +606,59 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) H.equipOutfit(outfit_to_distribute) H.status_flags |= GODMODE RegisterSignal(H, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(display_votes)) - var/datum/action/innate/mafia_panel/mafia_panel = new(null,src) - mafia_panel.Grant(H) var/obj/item/modular_computer/modpc = role.player_pda role.register_body(H) if(modpc) player_role_lookup[modpc] = role else - player_role_lookup[H] = role + player_role_lookup[role.player_key] = role var/client/player_client = GLOB.directory[role.player_key] if(player_client) role.put_player_in_body(player_client) role.greet() -/datum/mafia_controller/ui_static_data(atom/user) - var/list/data = list() - - if(usr.client?.holder) - data["admin_controls"] = TRUE //show admin buttons to start/setup/stop - data["is_observer"] = isobserver(user) - data["all_roles"] = current_setup_text - - if(phase == MAFIA_PHASE_SETUP) - return data - - var/datum/mafia_role/user_role = player_role_lookup[user] - if(user_role) - data["roleinfo"] = list( - "role" = user_role.name, - "desc" = user_role.desc, - "hud_icon" = user_role.hud_icon, - "revealed_icon" = user_role.revealed_icon, - ) - - return data - -/datum/mafia_controller/ui_data(atom/user) - var/list/data = list() - - data["phase"] = phase - if(turn) - data["turn"] = " - Day [turn]" - - if(phase == MAFIA_PHASE_SETUP) - data["lobbydata"] = list() - for(var/key in GLOB.mafia_signup + GLOB.mafia_bad_signup + GLOB.pda_mafia_signup) - var/list/lobby_member = list() - lobby_member["name"] = key - lobby_member["status"] = (key in GLOB.mafia_bad_signup) ? "Disconnected" : "Ready" - data["lobbydata"] += list(lobby_member) - return data - - data["timeleft"] = next_phase_timer ? timeleft(next_phase_timer) : 0 - - var/datum/mafia_role/user_role = player_role_lookup[user] - if(user_role) - data["user_notes"] = user_role.written_notes - data["messages"] = list() - var/list/ui_messages = list() - for(var/i = user_role.role_messages.len to 1 step -1) - ui_messages.Add(list(list( - "msg" = user_role.role_messages[i], - ))) - data["messages"] = ui_messages - - data["players"] = list() - for(var/datum/mafia_role/role as anything in all_roles) - var/list/player_info = list() - player_info["name"] = role.body.real_name - player_info["ref"] = REF(role) - player_info["alive"] = role.game_status == MAFIA_ALIVE - player_info["possible_actions"] = list() - - if(user_role) //not observer - for(var/datum/mafia_ability/action as anything in user_role.role_unique_actions) - if(action.validate_action_target(src, potential_target = role, silent = TRUE)) - player_info["possible_actions"] += list(list("name" = action, "ref" = REF(action))) - - data["players"] += list(player_info) - - return data - -/datum/mafia_controller/ui_assets(mob/user) - return list( - get_asset_datum(/datum/asset/spritesheet/mafia), - ) - -/datum/mafia_controller/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) - . = ..() - if(.) - return - var/datum/mafia_role/user_role = player_role_lookup[usr] - var/obj/item/modular_computer/modpc = ui.src_object +///From a 'user' (Either a mob or ModPC) or TGUI UI, will try to find the Mafia role from 'player_role_lookup'. +/datum/mafia_controller/proc/get_role_player(atom/user, datum/tgui/ui) + var/obj/item/modular_computer/modpc = ui?.src_object || user if(istype(modpc)) - user_role = player_role_lookup[modpc] - else - modpc = null - //Admin actions - if(ui.user.client.holder) - switch(action) - if("new_game") - if(phase == MAFIA_PHASE_SETUP) - return - basic_setup() - if("nuke") - qdel(src) - if("next_phase") - if(phase == MAFIA_PHASE_SETUP) - return - var/datum/timedevent/timer = SStimer.timer_id_dict[next_phase_timer] - if(!timer.spent) - var/datum/callback/tc = timer.callBack - deltimer(next_phase_timer) - tc.InvokeAsync() - return TRUE - if("players_home") - var/list/failed = list() - for(var/datum/mafia_role/player in all_roles) - if(!player.body) - failed += player - continue - player.body.forceMove(get_turf(player.assigned_landmark)) - if(failed.len) - to_chat(usr, "List of players who no longer had a body (if you see this, the game is runtiming anyway so just hit \"New Game\" to end it)") - for(var/datum/mafia_role/fail as anything in failed) - to_chat(usr, fail.player_key || fail.player_pda) - if("debug_setup") - var/list/debug_setup = list() - var/list/rolelist_dict = list("CANCEL", "FINISH") + GLOB.mafia_roles_by_name - var/done = FALSE - - while(!done) - to_chat(usr, "You have a total player count of [assoc_value_sum(debug_setup)] in this setup.") - var/chosen_role_name = tgui_input_list(usr, "Select a role!", "Custom Setup Creation", rolelist_dict) - if(!chosen_role_name) - return - switch(chosen_role_name) - if("CANCEL") - done = TRUE - return - if("FINISH") - done = TRUE - break - else - var/found_path = rolelist_dict[chosen_role_name] - var/role_count = tgui_input_number(usr, "How many? Zero to cancel.", "Custom Setup Creation", 0, 12) - if(role_count > 0) - debug_setup[found_path] = role_count - custom_setup = debug_setup - early_start = TRUE - try_autostart()//don't worry, this fails if there's a game in progress - if("cancel_setup") - custom_setup = list() - if("start_now") - forced_setup() - - switch(action) //both living and dead - if("mf_lookup") - var/role_lookup = params["role_name"] - var/datum/mafia_role/helper - for(var/datum/mafia_role/role as anything in all_roles) - if(role_lookup == role.name) - helper = role - break - helper.show_help(usr) - - if(!user_role)//just the dead - switch(action) - if("mf_signup") - var/client/ghost_client = ui.user.client - if(!SSticker.HasRoundStarted()) - to_chat(usr, span_warning("Wait for the round to start.")) - return - if(isnull(modpc)) - if(GLOB.mafia_signup[ghost_client.ckey]) - GLOB.mafia_signup -= ghost_client.ckey - GLOB.mafia_early_votes -= ghost_client.ckey //Remove their early start vote as well - to_chat(usr, span_notice("You unregister from Mafia.")) - return TRUE - else - GLOB.mafia_signup[ghost_client.ckey] = TRUE - to_chat(usr, span_notice("You sign up for Mafia.")) - else - if(GLOB.pda_mafia_signup[modpc]) - GLOB.pda_mafia_signup -= modpc - GLOB.mafia_early_votes -= modpc //Remove their early start vote as well - to_chat(usr, span_notice("You unregister from Mafia.")) - return TRUE - else - GLOB.pda_mafia_signup[modpc] = TRUE - to_chat(usr, span_notice("You sign up for Mafia.")) - if(phase == MAFIA_PHASE_SETUP) - check_signups() - try_autostart() - return TRUE - if("vote_to_start") - var/client/ghost_client = ui.user.client - if(phase != MAFIA_PHASE_SETUP) - to_chat(usr, span_notice("You cannot vote to start while a game is underway!")) - return - if(isnull(modpc)) - if(!GLOB.mafia_signup[ghost_client.ckey]) - to_chat(usr, span_notice("You must be signed up for this game to vote!")) - return - if(GLOB.mafia_early_votes[ghost_client.ckey]) - GLOB.mafia_early_votes -= ghost_client.ckey - to_chat(usr, span_notice("You are no longer voting to start the game early.")) - else - GLOB.mafia_early_votes[ghost_client.ckey] = ghost_client - to_chat(usr, span_notice("You vote to start the game early ([length(GLOB.mafia_early_votes)] out of [max(round(length(GLOB.mafia_signup) / 2), round(MAFIA_MIN_PLAYER_COUNT / 2))]).")) - if(check_start_votes()) //See if we have enough votes to start - forced_setup() - else - if(!GLOB.pda_mafia_signup[modpc]) - to_chat(usr, span_notice("You must be signed up for this game to vote!")) - return - if(GLOB.mafia_early_votes[modpc]) - GLOB.mafia_early_votes -= modpc - to_chat(usr, span_notice("You are no longer voting to start the game early.")) - else - GLOB.mafia_early_votes[modpc] = modpc - to_chat(usr, span_notice("You vote to start the game early ([length(GLOB.mafia_early_votes)] out of [max(round(length(GLOB.mafia_signup) / 2), round(MAFIA_MIN_PLAYER_COUNT / 2))]).")) - if(check_start_votes()) //See if we have enough votes to start - forced_setup() - return TRUE - - if(user_role && user_role.game_status == MAFIA_DEAD) - return + return player_role_lookup[modpc] + var/mob/mob_user = user + if(!istype(mob_user)) + CRASH("[user] is not a modPC nor a mob, but we are trying to find their role.") + return player_role_lookup[mob_user.ckey] - //User actions (just living) - switch(action) - if("change_notes") - if(user_role.game_status == MAFIA_DEAD) - return TRUE - user_role.written_notes = sanitize_text(params["new_notes"]) - user_role.send_message_to_player("notes saved", balloon_alert = TRUE) - return TRUE - if("send_message_to_chat") - if(user_role.game_status == MAFIA_DEAD) - return TRUE - var/message_said = sanitize_text(params["message"]) - user_role.body.say(message_said, forced = "mafia chat (sent by [ui.user.client])") - return TRUE - if("send_notes_to_chat") - if(user_role.game_status == MAFIA_DEAD || !user_role.written_notes) - return TRUE - if(phase == MAFIA_PHASE_NIGHT) - return TRUE - if(!COOLDOWN_FINISHED(user_role, note_chat_sending_cooldown)) - return FALSE - COOLDOWN_START(user_role, note_chat_sending_cooldown, MAFIA_NOTE_SENDING_COOLDOWN) - user_role.body.say("[user_role.written_notes]", forced = "mafia notes sending") - return TRUE - if("perform_action") - var/datum/mafia_role/target = locate(params["target"]) in all_roles - if(!istype(target)) - return - var/datum/mafia_ability/used_action = locate(params["action_ref"]) in user_role.role_unique_actions - if(!used_action) - return - switch(phase) - if(MAFIA_PHASE_DAY, MAFIA_PHASE_VOTING) - used_action.using_ability = TRUE - used_action.perform_action_target(src, target) - if(MAFIA_PHASE_NIGHT) - used_action.set_target(src, target) +/** + * Signs the player up for Mafia, or removes them from the list if they are already + * signed up. + * Args: + * - ghost_client: is the client of the observer signing up. This can be null in favor of modpc. + * - modpc: is a living player signing up through a PDA. This can be null in favor of ghost_client. + */ +/datum/mafia_controller/proc/signup_mafia(mob/user, client/ghost_client, obj/item/modular_computer/modpc) + if(!SSticker.HasRoundStarted()) + to_chat(user, span_warning("Wait for the round to start.")) + return FALSE + if(isnull(modpc)) + if(GLOB.mafia_signup[ghost_client.ckey]) + GLOB.mafia_signup -= ghost_client.ckey + GLOB.mafia_early_votes -= ghost_client.ckey //Remove their early start vote as well + to_chat(user, span_notice("You unregister from Mafia.")) + else + GLOB.mafia_signup[ghost_client.ckey] = TRUE + to_chat(user, span_notice("You sign up for Mafia.")) + else + if(GLOB.pda_mafia_signup[modpc]) + GLOB.pda_mafia_signup -= modpc + GLOB.mafia_early_votes -= modpc //Remove their early start vote as well + to_chat(user, span_notice("You unregister from Mafia.")) return TRUE - - if(user_role != on_trial) - switch(action) - if("vote_abstain") - if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_abstain_votes)) - return - user_role.send_message_to_player("You have decided to abstain.") - judgement_innocent_votes -= user_role - judgement_guilty_votes -= user_role - judgement_abstain_votes += user_role - if("vote_innocent") - if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_innocent_votes)) - return - user_role.send_message_to_player("Your vote on [on_trial.body.real_name] submitted as INNOCENT!") - judgement_abstain_votes -= user_role//no fakers, and... - judgement_guilty_votes -= user_role//no radical centrism - judgement_innocent_votes += user_role - if("vote_guilty") - if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_guilty_votes)) - return - user_role.send_message_to_player("Your vote on [on_trial.body.real_name] submitted as GUILTY!") - judgement_abstain_votes -= user_role//no fakers, and... - judgement_innocent_votes -= user_role//no radical centrism - judgement_guilty_votes += user_role - -/datum/mafia_controller/ui_state(mob/user) - return GLOB.always_state - -/datum/mafia_controller/ui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, null) - if(!ui) - ui = new(user, src, "MafiaPanel") - ui.open() - -/proc/assoc_value_sum(list/L) - . = 0 - for(var/key in L) - . += L[key] + else + GLOB.pda_mafia_signup[modpc] = TRUE + to_chat(user, span_notice("You sign up for Mafia.")) + if(phase == MAFIA_PHASE_SETUP) + check_signups() + try_autostart() + return TRUE /** * Returns a standard setup, with certain important/unique roles guaranteed. @@ -960,18 +703,16 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) /datum/mafia_controller/proc/basic_setup() var/req_players = MAFIA_MAX_PLAYER_COUNT var/list/setup = custom_setup - if(setup.len) + if(length(setup)) req_players = assoc_value_sum(setup) - var/list/filtered_pdas = GLOB.pda_mafia_signup - if(!isnull(filtered_pdas)) //pdas get priority - req_players -= length(GLOB.pda_mafia_signup) - var/list/filtered_keys = filter_players(req_players) - var/needed_players = length(filtered_keys) + length(filtered_pdas) + var/list/filtered_keys_and_pdas = filter_players(req_players) - if(!setup.len) //don't actually have one yet, so generate a max player random setup. it's good to do this here instead of above so it doesn't generate one every time a game could possibly start. - setup = generate_standard_setup(needed_players) - prepare_game(setup, filtered_keys, filtered_pdas) + //don't actually have one yet, so generate a max player random setup. + //it's good to do this here instead of above so it doesn't generate one every time a game could possibly start. + if(!length(setup)) + setup = generate_standard_setup(length(filtered_keys_and_pdas)) + prepare_game(setup, filtered_keys_and_pdas) start_game() /** @@ -982,17 +723,15 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) /datum/mafia_controller/proc/forced_setup() check_signups() //Refresh the signup list, so our numbers are accurate and we only take active players into consideration. - var/list/filtered_pdas = GLOB.pda_mafia_signup - var/list/filtered_keys = filter_players(length(GLOB.mafia_signup)) - var/req_players = length(filtered_keys) + length(filtered_pdas) - - if(!req_players) //If we have nobody signed up, we give up on starting + var/players_needed = GLOB.mafia_signup.len + GLOB.pda_mafia_signup.len + var/list/filtered_keys_and_pdas = filter_players(players_needed) + if(!length(filtered_keys_and_pdas)) //If we have nobody signed up, we give up on starting log_admin("Attempted to force a mafia game to start with nobody signed up!") return - var/list/setup = generate_standard_setup(req_players) + var/list/setup = generate_standard_setup(length(filtered_keys_and_pdas)) - prepare_game(setup, filtered_keys, filtered_pdas) + prepare_game(setup, filtered_keys_and_pdas) early_start = TRUE start_game() @@ -1006,10 +745,10 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) /datum/mafia_controller/proc/check_start_votes() check_signups() //Same as before. What a useful proc. - if(length(GLOB.mafia_signup) < MAFIA_MIN_PLAYER_COUNT) + if(length(GLOB.mafia_signup + GLOB.pda_mafia_signup) < MAFIA_MIN_PLAYER_COUNT) return FALSE //Make sure we have the minimum playercount to host a game first. - if(length(GLOB.mafia_early_votes) < round(length(GLOB.mafia_signup) / 2)) + if(length(GLOB.mafia_early_votes) < round(length(GLOB.mafia_signup + GLOB.pda_mafia_signup) / 2)) return FALSE return TRUE @@ -1023,38 +762,44 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) * This should only be run as we are in the process of starting a game. * * max_players - The maximum number of keys to put in our return list before we start telling people they're not getting in. - * filtered_keys - A list of player ckeys, to be included in the game. + * filtered_keys_and_pdas - A list of player ckeys and PDAs, to be included in the game. */ /datum/mafia_controller/proc/filter_players(max_players) //final list for all the players who will be in this game - var/list/filtered_keys = list() + var/list/filtered_keys_and_pdas = list() //cuts invalid players from signups (disconnected/not a ghost) - var/list/possible_keys = list() + var/list/possible_players = list() for(var/key in GLOB.mafia_signup) if(GLOB.directory[key]) var/client/C = GLOB.directory[key] if(isobserver(C.mob)) - possible_keys += key + possible_players += key continue GLOB.mafia_signup -= key //not valid to play when we checked so remove them from signups - //If we're not over capacity and don't need to notify anyone of their exclusion, return early. - if(length(possible_keys) < max_players) - return filtered_keys + for(var/obj/item/modular_computer/pda/pdas as anything in GLOB.pda_mafia_signup) + possible_players += pdas //if there were too many players, still start but only make filtered keys as big as it needs to be (cut excess) //also removes people who do get into final player list from the signup so they have to sign up again when game ends for(var/i in 1 to max_players) - var/chosen_key = pick_n_take(possible_keys) - filtered_keys += chosen_key - GLOB.mafia_signup -= chosen_key + if(!length(possible_players)) + break + var/chosen_key = pick_n_take(possible_players) + filtered_keys_and_pdas += chosen_key + if(chosen_key in GLOB.pda_mafia_signup) + GLOB.pda_mafia_signup -= chosen_key + else if(chosen_key in GLOB.mafia_signup) + GLOB.mafia_signup -= chosen_key //small message about not getting into this game for clarity on why they didn't get in - for(var/unpicked in possible_keys) + for(var/unpicked in possible_players) + if(!(unpicked in GLOB.mafia_signup)) + continue var/client/unpicked_client = GLOB.directory[unpicked] to_chat(unpicked_client, span_danger("Sorry, the starting mafia game has too many players and you were not picked.")) to_chat(unpicked_client, span_warning("You're still signed up, getting messages from the current round, and have another chance to join when the one starting now finishes.")) - return filtered_keys + return filtered_keys_and_pdas /** * Called when someone signs up, and sees if there are enough people in the signup list to begin. @@ -1073,6 +818,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) * If a disconnected player gets a non-ghost mob and reconnects, they will be first put back into mafia_signup then filtered by that. */ /datum/mafia_controller/proc/check_signups() +#ifndef UNIT_TESTS for(var/bad_key in GLOB.mafia_bad_signup) if(GLOB.directory[bad_key])//they have reconnected if we can search their key and get a client GLOB.mafia_bad_signup -= bad_key @@ -1086,6 +832,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) if(!isobserver(C.mob)) //they are back to playing the game, remove them from the signups GLOB.mafia_signup -= key +#endif /datum/action/innate/mafia_panel name = "Mafia Panel" @@ -1099,6 +846,10 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) . = ..() controller_panel = controller +/datum/action/innate/mafia_panel/Destroy() + . = ..() + controller_panel = null + /datum/action/innate/mafia_panel/Activate() controller_panel.ui_interact(owner) diff --git a/code/modules/mafia/controller_ui.dm b/code/modules/mafia/controller_ui.dm new file mode 100644 index 00000000000000..9caa25d9f74de1 --- /dev/null +++ b/code/modules/mafia/controller_ui.dm @@ -0,0 +1,261 @@ +// 'user' can be a modPC, hence why it's pathed to the atom +/datum/mafia_controller/ui_static_data(atom/user) + var/list/data = list() + + if(usr.client?.holder) + data["admin_controls"] = TRUE //show admin buttons to start/setup/stop + data["is_observer"] = isobserver(user) + data["all_roles"] = current_setup_text + + if(phase == MAFIA_PHASE_SETUP) + return data + + var/datum/mafia_role/user_role = get_role_player(user) + if(user_role) + data["roleinfo"] = list( + "role" = user_role.name, + "desc" = user_role.desc, + "hud_icon" = user_role.hud_icon, + "revealed_icon" = user_role.revealed_icon, + ) + + return data + +// 'user' can be a modPC, hence why it's pathed to the atom +/datum/mafia_controller/ui_data(atom/user) + var/list/data = list() + + data["phase"] = phase + if(turn) + data["turn"] = " - Day [turn]" + + if(phase == MAFIA_PHASE_SETUP) + data["lobbydata"] = list() + for(var/key in GLOB.mafia_signup + GLOB.mafia_bad_signup + GLOB.pda_mafia_signup) + var/list/lobby_member = list() + lobby_member["name"] = key + lobby_member["status"] = (key in GLOB.mafia_bad_signup) ? "Disconnected" : "Ready" + data["lobbydata"] += list(lobby_member) + return data + + data["timeleft"] = next_phase_timer ? timeleft(next_phase_timer) : 0 + + var/datum/mafia_role/user_role = get_role_player(user) + if(user_role) + data["user_notes"] = user_role.written_notes + var/list/ui_messages = list() + for(var/i = user_role.role_messages.len to 1 step -1) + ui_messages.Add(list(list( + "msg" = user_role.role_messages[i], + ))) + data["messages"] = ui_messages + + data["players"] = list() + for(var/datum/mafia_role/role as anything in all_roles) + var/list/player_info = list() + player_info["name"] = role.body.real_name + player_info["ref"] = REF(role) + player_info["alive"] = role.game_status == MAFIA_ALIVE + player_info["possible_actions"] = list() + + if(user_role) //not observer + for(var/datum/mafia_ability/action as anything in user_role.role_unique_actions) + if(action.validate_action_target(src, potential_target = role, silent = TRUE)) + player_info["possible_actions"] += list(list("name" = action, "ref" = REF(action))) + + data["players"] += list(player_info) + + return data + +/datum/mafia_controller/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/mafia), + ) + +/datum/mafia_controller/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + var/datum/mafia_role/user_role = get_role_player(usr, ui) + var/obj/item/modular_computer/modpc = ui.src_object + if(!istype(modpc)) + modpc = null + //Admin actions + if(ui.user.client.holder) + switch(action) + if("new_game") + if(phase == MAFIA_PHASE_SETUP) + return + basic_setup() + if("nuke") + qdel(src) + if("next_phase") + if(phase == MAFIA_PHASE_SETUP) + return + var/datum/timedevent/timer = SStimer.timer_id_dict[next_phase_timer] + if(!timer.spent) + var/datum/callback/tc = timer.callBack + deltimer(next_phase_timer) + tc.InvokeAsync() + return TRUE + if("players_home") + var/list/failed = list() + for(var/datum/mafia_role/player in all_roles) + if(!player.body) + failed += player + continue + player.body.forceMove(get_turf(player.assigned_landmark)) + if(failed.len) + to_chat(usr, "List of players who no longer had a body (if you see this, the game is runtiming anyway so just hit \"New Game\" to end it)") + for(var/datum/mafia_role/fail as anything in failed) + to_chat(usr, fail.player_key || fail.player_pda) + if("debug_setup") + var/list/debug_setup = list() + var/list/rolelist_dict = list("CANCEL", "FINISH") + GLOB.mafia_roles_by_name + var/done = FALSE + + while(!done) + to_chat(usr, "You have a total player count of [assoc_value_sum(debug_setup)] in this setup.") + var/chosen_role_name = tgui_input_list(usr, "Select a role!", "Custom Setup Creation", rolelist_dict) + if(!chosen_role_name) + return + switch(chosen_role_name) + if("CANCEL") + done = TRUE + return + if("FINISH") + done = TRUE + break + else + var/found_path = rolelist_dict[chosen_role_name] + var/role_count = tgui_input_number(usr, "How many? Zero to cancel.", "Custom Setup Creation", 0, 12) + if(role_count > 0) + debug_setup[found_path] = role_count + custom_setup = debug_setup + early_start = TRUE + try_autostart()//don't worry, this fails if there's a game in progress + if("cancel_setup") + custom_setup = list() + if("start_now") + forced_setup() + + switch(action) //both living and dead + if("mf_lookup") + var/role_lookup = params["role_name"] + var/datum/mafia_role/helper + for(var/datum/mafia_role/role as anything in all_roles) + if(role_lookup == role.name) + helper = role + break + helper.show_help(usr) + + if(!user_role)//just the dead + switch(action) + if("mf_signup") + if(signup_mafia(usr, ui.user.client, modpc)) + return TRUE + if("vote_to_start") + var/client/ghost_client = ui.user.client + if(phase != MAFIA_PHASE_SETUP) + to_chat(usr, span_notice("You cannot vote to start while a game is underway!")) + return + if(isnull(modpc)) + if(!GLOB.mafia_signup[ghost_client.ckey]) + to_chat(usr, span_notice("You must be signed up for this game to vote!")) + return + if(GLOB.mafia_early_votes[ghost_client.ckey]) + GLOB.mafia_early_votes -= ghost_client.ckey + to_chat(usr, span_notice("You are no longer voting to start the game early.")) + else + GLOB.mafia_early_votes[ghost_client.ckey] = ghost_client + to_chat(usr, span_notice("You vote to start the game early ([length(GLOB.mafia_early_votes)] out of [max(round(length(GLOB.mafia_signup + GLOB.pda_mafia_signup) / 2), round(MAFIA_MIN_PLAYER_COUNT / 2))]).")) + if(check_start_votes()) //See if we have enough votes to start + forced_setup() + else + if(!GLOB.pda_mafia_signup[modpc]) + to_chat(usr, span_notice("You must be signed up for this game to vote!")) + return + if(GLOB.mafia_early_votes[modpc]) + GLOB.mafia_early_votes -= modpc + to_chat(usr, span_notice("You are no longer voting to start the game early.")) + else + GLOB.mafia_early_votes[modpc] = modpc + to_chat(usr, span_notice("You vote to start the game early ([length(GLOB.mafia_early_votes)] out of [max(round(length(GLOB.mafia_signup + GLOB.pda_mafia_signup) / 2), round(MAFIA_MIN_PLAYER_COUNT / 2))]).")) + if(check_start_votes()) //See if we have enough votes to start + forced_setup() + return TRUE + + if(user_role && user_role.game_status == MAFIA_DEAD) + return + + //User actions (just living) + switch(action) + if("change_notes") + if(user_role.game_status == MAFIA_DEAD) + return TRUE + user_role.written_notes = sanitize_text(params["new_notes"]) + user_role.send_message_to_player("notes saved", balloon_alert = TRUE) + return TRUE + if("send_message_to_chat") + if(user_role.game_status == MAFIA_DEAD) + return TRUE + var/message_said = sanitize_text(params["message"]) + user_role.body.say(message_said, forced = "mafia chat (sent by [ui.user.client])") + return TRUE + if("send_notes_to_chat") + if(user_role.game_status == MAFIA_DEAD || !user_role.written_notes) + return TRUE + if(phase == MAFIA_PHASE_NIGHT) + return TRUE + if(!COOLDOWN_FINISHED(user_role, note_chat_sending_cooldown)) + return FALSE + COOLDOWN_START(user_role, note_chat_sending_cooldown, MAFIA_NOTE_SENDING_COOLDOWN) + user_role.body.say("[user_role.written_notes]", forced = "mafia notes sending") + return TRUE + if("perform_action") + var/datum/mafia_role/target = locate(params["target"]) in all_roles + if(!istype(target)) + return + var/datum/mafia_ability/used_action = locate(params["action_ref"]) in user_role.role_unique_actions + if(!used_action) + return + switch(phase) + if(MAFIA_PHASE_DAY, MAFIA_PHASE_VOTING) + used_action.using_ability = TRUE + used_action.perform_action_target(src, target) + if(MAFIA_PHASE_NIGHT) + used_action.set_target(src, target) + return TRUE + + if(user_role != on_trial) + switch(action) + if("vote_abstain") + if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_abstain_votes)) + return + user_role.send_message_to_player("You have decided to abstain.") + judgement_innocent_votes -= user_role + judgement_guilty_votes -= user_role + judgement_abstain_votes += user_role + if("vote_innocent") + if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_innocent_votes)) + return + user_role.send_message_to_player("Your vote on [on_trial.body.real_name] submitted as INNOCENT!") + judgement_abstain_votes -= user_role//no fakers, and... + judgement_guilty_votes -= user_role//no radical centrism + judgement_innocent_votes += user_role + if("vote_guilty") + if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_guilty_votes)) + return + user_role.send_message_to_player("Your vote on [on_trial.body.real_name] submitted as GUILTY!") + judgement_abstain_votes -= user_role//no fakers, and... + judgement_innocent_votes -= user_role//no radical centrism + judgement_guilty_votes += user_role + +/datum/mafia_controller/ui_state(mob/user) + return GLOB.always_state + +/datum/mafia_controller/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, null) + if(!ui) + ui = new(user, src, "MafiaPanel") + ui.open() diff --git a/code/modules/mafia/map_pieces.dm b/code/modules/mafia/map_pieces.dm index 0d27d6cd1b5ecf..f3a6baced78c58 100644 --- a/code/modules/mafia/map_pieces.dm +++ b/code/modules/mafia/map_pieces.dm @@ -28,48 +28,65 @@ /datum/map_template/mafia should_place_on_top = FALSE + ///The map suffix to put onto the mappath. + var/map_suffix ///A brief background tidbit var/description = "" ///What costume will this map force players to start with? var/custom_outfit +/datum/map_template/mafia/New(path = null, rename = null, cache = FALSE) + path = "_maps/map_files/Mafia/" + map_suffix + return ..() + +//we only have one map in unit tests for consistency. +#ifdef UNIT_TESTS +/datum/map_template/mafia/unit_test + name = "Mafia Unit Test" + description = "A map designed specifically for Unit Testing to ensure the game runs properly." + map_suffix = "mafia_unit_test.dmm" + +#else + /datum/map_template/mafia/summerball name = "Summerball 2020" description = "The original, the OG. The 2020 Summer ball was where mafia came from, with this map." - mappath = "_maps/map_files/Mafia/mafia_ball.dmm" - -/datum/map_template/mafia/syndicate - name = "Syndicate Megastation" - description = "Yes, it's a very confusing day at the Megastation. Will the syndicate conflict resolution operatives succeed?" - mappath = "_maps/map_files/Mafia/mafia_syndie.dmm" - custom_outfit = /datum/outfit/mafia/syndie - -/datum/map_template/mafia/lavaland - name = "Lavaland Excursion" - description = "The station has no idea what's going down on lavaland right now, we got changelings... traitors, and worst of all... lawyers roleblocking you every night." - mappath = "_maps/map_files/Mafia/mafia_lavaland.dmm" - custom_outfit = /datum/outfit/mafia/lavaland + map_suffix = "mafia_ball.dmm" /datum/map_template/mafia/ufo name = "Alien Mothership" description = "The haunted ghost UFO tour has gone south and now it's up to our fine townies and scare seekers to kill the actual real alien changelings..." - mappath = "_maps/map_files/Mafia/mafia_ayylmao.dmm" + map_suffix = "mafia_ayylmao.dmm" custom_outfit = /datum/outfit/mafia/abductee /datum/map_template/mafia/spider_clan name = "Spider Clan Kidnapping" description = "New and improved spider clan kidnappings are a lot less boring and have a lot more lynching. Damn westaboos!" - mappath = "_maps/map_files/Mafia/mafia_spiderclan.dmm" + map_suffix = "mafia_spiderclan.dmm" custom_outfit = /datum/outfit/mafia/ninja +/datum/map_template/mafia/gothic + name = "Vampire's Castle" + description = "Vampires and changelings clash to find out who's the superior bloodsucking monster in this creepy castle map." + map_suffix = "mafia_gothic.dmm" + custom_outfit = /datum/outfit/mafia/gothic + +/datum/map_template/mafia/syndicate + name = "Syndicate Megastation" + description = "Yes, it's a very confusing day at the Megastation. Will the syndicate conflict resolution operatives succeed?" + map_suffix = "mafia_syndie.dmm" + custom_outfit = /datum/outfit/mafia/syndie + /datum/map_template/mafia/snowy name = "Snowdin" description = "Based off of the icy moon map of the same name, the guy who reworked it did a good enough job to recieve a derivative piece of work based on it. Cool!" - mappath = "_maps/map_files/Mafia/mafia_snow.dmm" + map_suffix = "mafia_snow.dmm" custom_outfit = /datum/outfit/mafia/snowy -/datum/map_template/mafia/gothic - name = "Vampire's Castle" - description = "Vampires and changelings clash to find out who's the superior bloodsucking monster in this creepy castle map." - mappath = "_maps/map_files/Mafia/mafia_gothic.dmm" - custom_outfit = /datum/outfit/mafia/gothic +/datum/map_template/mafia/lavaland + name = "Lavaland Excursion" + description = "The station has no idea what's going down on lavaland right now, we got changelings... traitors, and worst of all... lawyers roleblocking you every night." + map_suffix = "mafia_lavaland.dmm" + custom_outfit = /datum/outfit/mafia/lavaland + +#endif diff --git a/code/modules/mafia/roles/roles.dm b/code/modules/mafia/roles/roles.dm index efe0d25c5b9882..f301a8ac02aace 100644 --- a/code/modules/mafia/roles/roles.dm +++ b/code/modules/mafia/roles/roles.dm @@ -27,6 +27,9 @@ var/mob/living/carbon/human/body var/obj/effect/landmark/mafia/assigned_landmark + ///The Mafia innate action panel that allows players to view the game's state. + var/datum/action/innate/mafia_panel/mafia_panel + ///how many votes submitted when you vote. used in voting and deciding victory. var/vote_power = 1 ///what they get equipped with when they are revealed @@ -49,6 +52,7 @@ /datum/mafia_role/New(datum/mafia_controller/game) . = ..() + mafia_panel = new(null, game) for(var/datum/mafia_ability/abilities as anything in role_unique_actions + /datum/mafia_ability/voting) role_unique_actions += new abilities(game, src) role_unique_actions -= abilities @@ -56,14 +60,21 @@ /datum/mafia_role/Destroy(force, ...) UnregisterSignal(body, COMSIG_MOB_SAY) QDEL_NULL(mafia_alert) - QDEL_NULL(body) + QDEL_NULL(mafia_panel) QDEL_LIST(role_unique_actions) - role_messages = null + //we null these instead of qdel because Mafia controller's mapdeleter deletes it all. + assigned_landmark = null + body = null + role_messages.Cut() return ..() /datum/mafia_role/proc/register_body(mob/living/carbon/human/new_body) + if(body) + UnregisterSignal(new_body, COMSIG_MOB_SAY) + mafia_panel.Remove(body) body = new_body RegisterSignal(new_body, COMSIG_MOB_SAY, PROC_REF(handle_speech)) + mafia_panel.Grant(new_body) /** * send_message_to_player @@ -118,14 +129,15 @@ * * Does not count as visiting, see visit proc. */ -/datum/mafia_role/proc/kill(datum/mafia_controller/game, datum/mafia_role/attacker, lynch=FALSE) +/datum/mafia_role/proc/kill(datum/mafia_controller/game, datum/mafia_role/attacker, lynch = FALSE) + if(game_status == MAFIA_DEAD) + return FALSE if(attacker && (attacker.role_flags & ROLE_ROLEBLOCKED)) return FALSE if(SEND_SIGNAL(src, COMSIG_MAFIA_ON_KILL, game, attacker, lynch) & MAFIA_PREVENT_KILL) return FALSE - if(game_status != MAFIA_DEAD) - game_status = MAFIA_DEAD - body.death() + game_status = MAFIA_DEAD + body.death() if(lynch) reveal_role(game, verbose = TRUE) game.living_roles -= src diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm index 54e167fb255414..f2734bb7b05b87 100644 --- a/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm +++ b/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm @@ -190,7 +190,12 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate) M.playsound_local(T, null, 100, FALSE, 0, FALSE, pressure_affected = FALSE, sound_to_use = legion_sound) flash_color(M, flash_color = "#FF0000", flash_time = 50) var/mutable_appearance/release_overlay = mutable_appearance('icons/effects/effects.dmi', "legiondoor") - notify_ghosts("Legion has been released in the [get_area(src)]!", source = src, alert_overlay = release_overlay, action = NOTIFY_JUMP, flashwindow = FALSE) + notify_ghosts( + "Legion has been released in the [get_area(src)]!", + source = src, + alert_overlay = release_overlay, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + ) /obj/effect/decal/necropolis_gate_decal icon = 'icons/effects/96x96.dmi' diff --git a/code/modules/mapfluff/ruins/spaceruin_code/clericsden.dm b/code/modules/mapfluff/ruins/spaceruin_code/clericsden.dm index 2ea63245661a6b..56b09ef7f79fa1 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/clericsden.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/clericsden.dm @@ -13,24 +13,3 @@ /obj/item/paper/fluff/ruins/clericsden/warning default_raw_text = "FATHER ODIVALLUS DO NOT GO FORWARD WITH THE RITUAL. THE ASTEROID WE'RE ANCHORED TO IS UNSTABLE, YOU WILL DESTROY THE STATION. I HOPE THIS REACHES YOU IN TIME. FATHER AURELLION." - -/mob/living/simple_animal/hostile/construct/proteon - name = "Proteon" - real_name = "Proteon" - desc = "A weaker construct meant to scour ruins for objects of Nar'Sie's affection. Those barbed claws are no joke." - icon_state = "proteon" - icon_living = "proteon" - maxHealth = 35 - health = 35 - melee_damage_lower = 8 - melee_damage_upper = 10 - retreat_distance = 4 //AI proteons will rapidly move in and out of combat to avoid conflict, but will still target and follow you. - attack_verb_continuous = "pinches" - attack_verb_simple = "pinch" - environment_smash = ENVIRONMENT_SMASH_WALLS - attack_sound = 'sound/weapons/punch2.ogg' - playstyle_string = "You are a Proteon. Your abilities in combat are outmatched by most combat constructs, but you are still fast and nimble. Run metal and supplies, and cooperate with your fellow cultists." - -/mob/living/simple_animal/hostile/construct/proteon/hostile //Style of mob spawned by trapped cult runes in the cleric ruin. - AIStatus = AI_ON - environment_smash = ENVIRONMENT_SMASH_STRUCTURES //standard ai construct behavior, breaks things if it wants, but not walls. diff --git a/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm b/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm new file mode 100644 index 00000000000000..5647b5aca2382a --- /dev/null +++ b/code/modules/mapfluff/ruins/spaceruin_code/meatderelict.dm @@ -0,0 +1,156 @@ +/obj/item/keycard/meatderelict/director + name = "directors keycard" + desc = "A fancy keycard. Likely unlocks the directors office. The name tag is all smudged." + color = "#990000" + puzzle_id = "md_director" + +/obj/item/keycard/meatderelict/engpost + name = "post keycard" + desc = "A fancy keycard. Has the engineering insignia on it." + color = "#f0da12" + puzzle_id = "md_engpost" + +/obj/item/keycard/meatderelict/armory + name = "armory keycard" + desc = "A red keycard. Has a really cool image of a gun on it. Fancy." + color = "#FF7276" + puzzle_id = "md_armory" + +/obj/item/paper/crumpled/bloody/fluff/meatderelict/directoroffice + name = "directors note" + default_raw_text = "The research was going smooth... but the experiment did not go as planned. He convulsed and screamed as he slowly mutated into... that thing. It started to spread everywhere, outside the lab too. There is no way we can cover up that we are not a teleport research outpost, so I locked down the lab, but they already know. They sent a squad to rescue us, but..." + +/obj/item/paper/crumpled/fluff/meatderelict/shieldgens + name = "shield gate marketing sketch" + default_raw_text = "The QR-109 Shield Gate is a robust hardlight machine capable of producing a strong shield to bar entry. With control panel integration, it can be enabled or disabled from anywhere, such as ship's Bridge, Engineering Bay, or wherever else! The rest is faded..." + +/obj/item/paper/crumpled/fluff/meatderelict + name = "engineer note" + default_raw_text = "I've overclocked the power generators to add that needed juice to the experiment, though they're a bit unstable." + +/obj/item/paper/crumpled/fluff/meatderelict/fridge + name = "engineer complaint" + default_raw_text = "Whoever keeps stealing my fucking ice cream from my fridge, I swear I will actually fuck you up. It is not cheap to get this delicious ice cream here, nor is it for you. And don't touch my snacks in the drawer!" + +/obj/machinery/computer/terminal/meatderelict + upperinfo = "COPYRIGHT 2500 NANOSOFT-TM - DO NOT REDISTRIBUTE - Now with audio!" //not that old + content = list( + "Experimental Test Satellite 37B
Nanotrasen™️ approved deep space experimentation lab

Entry 1:

Subject - \[Species 501-C-12\]
Date - \[REDACTED\]
We have acquired a biological sample of unknown origins \[Species 501-C-12\] from an NT outpost on the far reaches. Initial experiments have determined the sample to be a creature never previously recorded. It weighs approximately 7 grams and seems to be docile. Initial examinations determine that it is an extremely fast replicating organism which can alter its physiology to take multiple differing shapes. \[Recording Terminated\]
- Dr. Phil Cornelius", + "Entry 2:

Subject - \[Species 501-C-12\]
Date - \[REDACTED\]
The creature responds to electrical stimuli. It has failed to respond to Light, Heat, Cold, Oxygen, Plasma, CO2, Nitrogen. It, within moments, seemed to have generated muscle tissue within its otherwise shapeless form and moved away from the source of electricity. Feeding the creature has been a simple matter, it consumed just about any form of protein. It appears to rapidly digest and convert forms of protein into more of itself. Any undigestible products are simply left alone. Will continue to monitor creature and provide reports to Nanotrasen Central Command. \[Recording Terminated\]
- Dr. Phil Cornelius", + "Entry 3:

Subject - \[Species 501-C-12\]
Date - \[REDACTED\]
Any attempts at contacting Nanotrasen has failed. I've never seen anything like it. I... I don't think I'm going to survive much longer, I can hear it pushing on my room door. If anyone reads this, let my family know that I- \[Loud crash\]
GET BACK \[Gunshots\]
AHHHHHHHHHHHH \[Recording Terminated\]
- Dr. Phil Cornelius" + ) + +/obj/machinery/door/puzzle/meatderelict + name = "lockdown door" + desc = "A beaten door, still sturdy. Impervious to conventional methods of destruction, must be a way to open it nearby." + icon = 'icons/obj/doors/puzzledoor/danger.dmi' + puzzle_id = "md_prevault" + +/mob/living/basic/meteor_heart/opens_puzzle_door + ///the puzzle id we send on death + var/id + ///queue size, must match + var/queue_size = 2 + +/mob/living/basic/meteor_heart/opens_puzzle_door/Initialize(mapload) + . = ..() + new /obj/effect/puzzle_death_signal_holder(loc, src, id, queue_size) + +/obj/effect/puzzle_death_signal_holder // ok apparently registering signals on qdeling stuff is not very functional + ///delay + var/delay = 2.5 SECONDS + invisibility = INVISIBILITY_ABSTRACT + +/obj/effect/puzzle_death_signal_holder/Initialize(mapload, mob/listened, id, queue_size = 2) + . = ..() + if(isnull(id)) + return INITIALIZE_HINT_QDEL + RegisterSignal(listened, COMSIG_LIVING_DEATH, PROC_REF(on_death)) + SSqueuelinks.add_to_queue(src, id, queue_size) + +/obj/effect/puzzle_death_signal_holder/proc/on_death(datum/source) + SIGNAL_HANDLER + addtimer(CALLBACK(src, PROC_REF(send_sig)), delay) + +/obj/effect/puzzle_death_signal_holder/proc/send_sig() + SEND_SIGNAL(src, COMSIG_PUZZLE_COMPLETED) + qdel(src) + +/obj/machinery/puzzle_button/meatderelict + name = "lockdown panel" + desc = "A panel that controls the lockdown of this outpost." + id = "md_prevault" + +/obj/machinery/puzzle_button/meatderelict/open_doors() + . = ..() + playsound(src, 'sound/effects/alert.ogg', 100, TRUE) + visible_message(span_warning("[src] lets out an alarm as the lockdown is lifted!")) + +/obj/structure/puzzle_blockade/meat + name = "mass of meat and teeth" + desc = "A horrible mass of meat and teeth. Can it see you? You hope not. Virtually indestructible, must be a way around." + icon = 'icons/obj/structures.dmi' + icon_state = "meatblockade" + opacity = TRUE + +/obj/structure/puzzle_blockade/meat/try_signal(datum/source) + Shake(duration = 0.5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(open_up)), 0.5 SECONDS) + +/obj/structure/puzzle_blockade/meat/proc/open_up() + new /obj/effect/gibspawner/generic(drop_location()) + qdel(src) + +/obj/lightning_thrower + name = "overcharged SMES" + desc = "An overclocked SMES, bursting with power." + anchored = TRUE + density = TRUE + icon = 'icons/obj/machines/engine/other.dmi' + icon_state = "smes" + /// do we currently want to shock diagonal tiles? if not, we shock cardinals + var/throw_diagonals = FALSE + /// flags we apply to the shock + var/shock_flags = SHOCK_KNOCKDOWN | SHOCK_NOGLOVES + /// damage of the shock + var/shock_damage = 20 + /// list of turfs that are currently shocked so we can unregister the signal + var/list/signal_turfs = list() + /// how long do we shock + var/shock_duration = 0.5 SECONDS + +/obj/lightning_thrower/Initialize(mapload) + . = ..() + START_PROCESSING(SSprocessing, src) + +/obj/lightning_thrower/Destroy() + . = ..() + signal_turfs = null + STOP_PROCESSING(SSprocessing, src) + +/obj/lightning_thrower/process(seconds_per_tick) + var/list/dirs = throw_diagonals ? GLOB.diagonals : GLOB.cardinals + throw_diagonals = !throw_diagonals + playsound(src, 'sound/magic/lightningbolt.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE) + for(var/direction in dirs) + var/victim_turf = get_step(src, direction) + if(isclosedturf(victim_turf)) + continue + Beam(victim_turf, icon_state="lightning[rand(1,12)]", time = shock_duration) + RegisterSignal(victim_turf, COMSIG_ATOM_ENTERED, PROC_REF(shock_victim)) //we cant move anyway + signal_turfs += victim_turf + for(var/mob/living/victim in victim_turf) + shock_victim(null, victim) + addtimer(CALLBACK(src, PROC_REF(clear_signals)), shock_duration) + +/obj/lightning_thrower/proc/clear_signals(datum/source) + SIGNAL_HANDLER + for(var/turf in signal_turfs) + UnregisterSignal(turf, COMSIG_ATOM_ENTERED) + signal_turfs -= turf + +/obj/lightning_thrower/proc/shock_victim(datum/source, mob/living/victim) + SIGNAL_HANDLER + if(!istype(victim)) + return + victim.electrocute_act(shock_damage, src, flags = shock_flags) diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm index 7917da4d542302..47dca7b438e3cc 100644 --- a/code/modules/mapping/map_template.dm +++ b/code/modules/mapping/map_template.dm @@ -29,6 +29,8 @@ var/list/ceiling_baseturfs = list() /datum/map_template/New(path = null, rename = null, cache = FALSE) + SHOULD_CALL_PARENT(TRUE) + . = ..() if(path) mappath = path if(mappath) diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm index f42d572cb6cdd5..b4165a13cd0afc 100644 --- a/code/modules/mining/equipment/wormhole_jaunter.dm +++ b/code/modules/mining/equipment/wormhole_jaunter.dm @@ -102,6 +102,7 @@ mech_sized = TRUE //save your ripley innate_accuracy_penalty = 6 light_on = FALSE + wibbles = FALSE /obj/effect/portal/jaunt_tunnel/teleport(atom/movable/M) . = ..() diff --git a/code/modules/mining/fulton.dm b/code/modules/mining/fulton.dm index 20a436dc5c6f59..c8c8cf966bab4d 100644 --- a/code/modules/mining/fulton.dm +++ b/code/modules/mining/fulton.dm @@ -6,136 +6,179 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons) icon = 'icons/obj/fulton.dmi' icon_state = "extraction_pack" w_class = WEIGHT_CLASS_NORMAL - var/obj/structure/extraction_point/beacon + /// Beacon weakref + var/datum/weakref/beacon_ref + /// List of networks var/list/beacon_networks = list("station") + /// Number of uses left var/uses_left = 3 + /// Can be used indoors var/can_use_indoors - var/safe_for_living_creatures = 1 + /// Can be used on living creatures + var/safe_for_living_creatures = TRUE + /// Maximum force that can be used to extract var/max_force_fulton = MOVE_FORCE_STRONG /obj/item/extraction_pack/examine() . = ..() - . += "It has [uses_left] use\s remaining." + . += span_infoplain("It has [uses_left] use\s remaining.") + + var/obj/structure/extraction_point/beacon = beacon_ref?.resolve() + + if(isnull(beacon)) + beacon_ref = null + . += span_infoplain("It is not linked to a beacon.") + return + + . += span_infoplain("It is linked to [beacon.name].") /obj/item/extraction_pack/attack_self(mob/user) var/list/possible_beacons = list() - for(var/obj/structure/extraction_point/extraction_point as anything in GLOB.total_extraction_beacons) + for(var/datum/weakref/point_ref as anything in GLOB.total_extraction_beacons) + var/obj/structure/extraction_point/extraction_point = point_ref.resolve() + if(isnull(extraction_point)) + GLOB.total_extraction_beacons.Remove(point_ref) if(extraction_point.beacon_network in beacon_networks) possible_beacons += extraction_point if(!length(possible_beacons)) - to_chat(user, span_warning("There are no extraction beacons in existence!")) + balloon_alert(user, "no beacons") + return + + var/chosen_beacon = tgui_input_list(user, "Beacon to connect to", "Balloon Extraction Pack", sort_names(possible_beacons)) + if(isnull(chosen_beacon)) return - else - var/chosen_beacon = tgui_input_list(user, "Beacon to connect to", "Balloon Extraction Pack", sort_names(possible_beacons)) - if(isnull(chosen_beacon)) - return - beacon = chosen_beacon - to_chat(user, span_notice("You link the extraction pack to the beacon system.")) -/obj/item/extraction_pack/afterattack(atom/movable/A, mob/living/carbon/human/user, flag, params) + beacon_ref = WEAKREF(chosen_beacon) + balloon_alert(user, "linked!") + +/obj/item/extraction_pack/afterattack(atom/movable/thing, mob/living/carbon/human/user, proximity_flag, params) . = ..() . |= AFTERATTACK_PROCESSED_ITEM - if(!beacon) - to_chat(user, span_warning("[src] is not linked to a beacon, and cannot be used!")) - return - if(!(beacon in GLOB.total_extraction_beacons)) - beacon = null - to_chat(user, span_warning("The connected beacon has been destroyed!")) + + var/obj/structure/extraction_point/beacon = beacon_ref?.resolve() + if(isnull(beacon)) + balloon_alert(user, "not linked") + beacon_ref = null return + if(!can_use_indoors) - var/area/area = get_area(A) + var/area/area = get_area(thing) if(!area.outdoors) - to_chat(user, span_warning("[src] can only be used on things that are outdoors!")) + balloon_alert(user, "not outdoors") return - if(!flag) + + if(!proximity_flag || !istype(thing)) return - if(!istype(A)) + + if(!safe_for_living_creatures && check_for_living_mobs(thing)) + to_chat(user, span_warning("[src] is not safe for use with living creatures, they wouldn't survive the trip back!")) + balloon_alert(user, "not safe!") + return + + if(!isturf(thing.loc)) // no extracting stuff inside other stuff + return + if(thing.anchored || (thing.move_resist > max_force_fulton)) return - else - if(!safe_for_living_creatures && check_for_living_mobs(A)) - to_chat(user, span_warning("[src] is not safe for use with living creatures, they wouldn't survive the trip back!")) - return - if(!isturf(A.loc)) // no extracting stuff inside other stuff - return - if(A.anchored || (A.move_resist > max_force_fulton)) - return - to_chat(user, span_notice("You start attaching the pack to [A]...")) - if(do_after(user,50,target=A)) - to_chat(user, span_notice("You attach the pack to [A] and activate it.")) - if(loc == user) - user.back?.atom_storage?.attempt_insert(src, user, force = STORAGE_SOFT_LOCKED) - uses_left-- - if(uses_left <= 0) - user.transferItemToLoc(src, A, TRUE) - var/mutable_appearance/balloon - var/mutable_appearance/balloon2 - var/mutable_appearance/balloon3 - if(isliving(A)) - var/mob/living/M = A - M.Paralyze(320) // Keep them from moving during the duration of the extraction - if(M.buckled) - M.buckled.unbuckle_mob(M, TRUE) // Unbuckle them to prevent anchoring problems - else - A.set_anchored(TRUE) - A.set_density(FALSE) - var/obj/effect/extraction_holder/holder_obj = new(A.loc) - holder_obj.appearance = A.appearance - A.forceMove(holder_obj) - balloon2 = mutable_appearance('icons/effects/fulton_balloon.dmi', "fulton_expand") - balloon2.pixel_y = 10 - balloon2.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM - holder_obj.add_overlay(balloon2) - sleep(0.4 SECONDS) - balloon = mutable_appearance('icons/effects/fulton_balloon.dmi', "fulton_balloon") - balloon.pixel_y = 10 - balloon.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM - holder_obj.cut_overlay(balloon2) - holder_obj.add_overlay(balloon) - playsound(holder_obj.loc, 'sound/items/fultext_deploy.ogg', 50, TRUE, -3) - animate(holder_obj, pixel_z = 10, time = 20) - sleep(2 SECONDS) - animate(holder_obj, pixel_z = 15, time = 10) - sleep(1 SECONDS) - animate(holder_obj, pixel_z = 10, time = 10) - sleep(1 SECONDS) - animate(holder_obj, pixel_z = 15, time = 10) - sleep(1 SECONDS) - animate(holder_obj, pixel_z = 10, time = 10) - sleep(1 SECONDS) - playsound(holder_obj.loc, 'sound/items/fultext_launch.ogg', 50, TRUE, -3) - animate(holder_obj, pixel_z = 1000, time = 30) - if(ishuman(A)) - var/mob/living/carbon/human/L = A - L.SetUnconscious(0) - L.remove_status_effect(/datum/status_effect/drowsiness) - L.SetSleeping(0) - sleep(3 SECONDS) - var/list/flooring_near_beacon = list() - for(var/turf/open/floor in orange(1, beacon)) - flooring_near_beacon += floor - holder_obj.forceMove(pick(flooring_near_beacon)) - animate(holder_obj, pixel_z = 10, time = 50) - sleep(5 SECONDS) - animate(holder_obj, pixel_z = 15, time = 10) - sleep(1 SECONDS) - animate(holder_obj, pixel_z = 10, time = 10) - sleep(1 SECONDS) - balloon3 = mutable_appearance('icons/effects/fulton_balloon.dmi', "fulton_retract") - balloon3.pixel_y = 10 - balloon3.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM - holder_obj.cut_overlay(balloon) - holder_obj.add_overlay(balloon3) - sleep(0.4 SECONDS) - holder_obj.cut_overlay(balloon3) - A.set_anchored(FALSE) // An item has to be unanchored to be extracted in the first place. - A.set_density(initial(A.density)) - animate(holder_obj, pixel_z = 0, time = 5) - sleep(0.5 SECONDS) - A.forceMove(holder_obj.loc) - qdel(holder_obj) - if(uses_left <= 0) - qdel(src) + balloon_alert_to_viewers("attaching...") + playsound(thing, 'sound/items/zip.ogg', vol = 50, vary = TRUE) + if(isliving(thing)) + var/mob/living/creature = thing + if(creature.mind) + to_chat(thing, span_userdanger("You are being extracted! Stand still to proceed.")) + + if(!do_after(user, 5 SECONDS, target = thing)) + return + + balloon_alert_to_viewers("extracting!") + if(loc == user) + user.back?.atom_storage?.attempt_insert(src, user, force = STORAGE_SOFT_LOCKED) + uses_left-- + + if(uses_left <= 0) + user.transferItemToLoc(src, thing, TRUE) + + var/mutable_appearance/balloon + var/mutable_appearance/balloon2 + var/mutable_appearance/balloon3 + + if(isliving(thing)) + var/mob/living/creature = thing + creature.Paralyze(32 SECONDS) // Keep them from moving during the duration of the extraction + if(creature.buckled) + creature.buckled.unbuckle_mob(creature, TRUE) // Unbuckle them to prevent anchoring problems + else + thing.set_anchored(TRUE) + thing.set_density(FALSE) + + var/obj/effect/extraction_holder/holder_obj = new(get_turf(thing)) + holder_obj.appearance = thing.appearance + thing.forceMove(holder_obj) + balloon2 = mutable_appearance('icons/effects/fulton_balloon.dmi', "fulton_expand") + balloon2.pixel_y = 10 + balloon2.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM + holder_obj.add_overlay(balloon2) + + sleep(0.4 SECONDS) + + balloon = mutable_appearance('icons/effects/fulton_balloon.dmi', "fulton_balloon") + balloon.pixel_y = 10 + balloon.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM + holder_obj.cut_overlay(balloon2) + holder_obj.add_overlay(balloon) + playsound(holder_obj.loc, 'sound/items/fultext_deploy.ogg', vol = 50, vary = TRUE, extrarange = -3) + + animate(holder_obj, pixel_z = 10, time = 2 SECONDS) + animate(pixel_z = 15, time = 1 SECONDS) + animate(pixel_z = 10, time = 1 SECONDS) + animate(pixel_z = 15, time = 1 SECONDS) + animate(pixel_z = 10, time = 1 SECONDS) + sleep(6 SECONDS) + + playsound(holder_obj.loc, 'sound/items/fultext_launch.ogg', vol = 50, vary = TRUE, extrarange = -3) + animate(holder_obj, pixel_z = 1000, time = 3 SECONDS) + + if(ishuman(thing)) + var/mob/living/carbon/human/creature = thing + creature.SetUnconscious(0) + creature.remove_status_effect(/datum/status_effect/drowsiness) + creature.SetSleeping(0) + + sleep(3 SECONDS) + + var/turf/flooring_near_beacon = list() + var/turf/beacon_turf = get_turf(beacon) + for(var/turf/floor as anything in RANGE_TURFS(1, beacon_turf)) + if(!floor.is_blocked_turf()) + flooring_near_beacon += floor + + if(!length(flooring_near_beacon)) + flooring_near_beacon += beacon_turf + + holder_obj.forceMove(pick(flooring_near_beacon)) + + animate(holder_obj, pixel_z = 10, time = 5 SECONDS) + animate(pixel_z = 15, time = 1 SECONDS) + animate(pixel_z = 10, time = 1 SECONDS) + sleep(7 SECONDS) + + balloon3 = mutable_appearance('icons/effects/fulton_balloon.dmi', "fulton_retract") + balloon3.pixel_y = 10 + balloon3.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM + holder_obj.cut_overlay(balloon) + holder_obj.add_overlay(balloon3) + sleep(0.4 SECONDS) + + holder_obj.cut_overlay(balloon3) + thing.set_anchored(FALSE) // An item has to be unanchored to be extracted in the first place. + thing.set_density(initial(thing.density)) + animate(holder_obj, pixel_z = 0, time = 0.5 SECONDS) + sleep(0.5 SECONDS) + + thing.forceMove(holder_obj.loc) + qdel(holder_obj) + if(uses_left <= 0) + qdel(src) /obj/item/fulton_core name = "extraction beacon assembly kit" @@ -162,13 +205,9 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons) /obj/structure/extraction_point/Initialize(mapload) . = ..() name += " ([rand(100,999)]) ([get_area_name(src, TRUE)])" - GLOB.total_extraction_beacons += src + GLOB.total_extraction_beacons.Add(WEAKREF(src)) update_appearance(UPDATE_OVERLAYS) -/obj/structure/extraction_point/Destroy() - GLOB.total_extraction_beacons -= src - return ..() - /obj/structure/extraction_point/attack_hand(mob/living/user, list/modifiers) . = ..() balloon_alert_to_viewers("undeploying...") diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm index c66695091b06f6..950af6e8b8f735 100644 --- a/code/modules/mining/lavaland/ash_flora.dm +++ b/code/modules/mining/lavaland/ash_flora.dm @@ -269,7 +269,7 @@ yield = 4 potency = 15 growthstages = 3 - rarity = 20 + rarity = PLANT_MODERATELY_RARE reagents_add = list(/datum/reagent/consumable/nutriment = 0.1) species = "polypore" // silence unit test genes = list(/datum/plant_gene/trait/fire_resistance) diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm index 554002fed54a69..40185d34343a8d 100644 --- a/code/modules/mining/lavaland/megafauna_loot.dm +++ b/code/modules/mining/lavaland/megafauna_loot.dm @@ -674,9 +674,13 @@ return to_chat(user, span_notice("You call out for aid, attempting to summon spirits to your side.")) - notify_ghosts("[user] is raising [user.p_their()] [name], calling for your help!", - enter_link="(Click to help)", - source = user, ignore_key = POLL_IGNORE_SPECTRAL_BLADE, header = "Spectral blade") + notify_ghosts( + "[user] is raising [user.p_their()] [name], calling for your help!", + action = NOTIFY_ORBIT, + source = user, + ignore_key = POLL_IGNORE_SPECTRAL_BLADE, + header = "Spectral blade", + ) summon_cooldown = world.time + 600 diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 9d1d429466953d..8725fee2e22f42 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -55,7 +55,7 @@ if(12) new /obj/item/jacobs_ladder(src) if(13) - new /obj/item/guardiancreator/miner(src) + new /obj/item/guardian_creator/miner(src) if(14) new /obj/item/warp_cube/red(src) if(15) diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm index 28c51a38c86b2d..457bc438dfbac4 100644 --- a/code/modules/mining/lavaland/tendril_loot.dm +++ b/code/modules/mining/lavaland/tendril_loot.dm @@ -197,14 +197,14 @@ continue regurgitate_guardian(guardian) -/obj/item/clothing/neck/necklace/memento_mori/proc/consume_guardian(mob/living/simple_animal/hostile/guardian/guardian) +/obj/item/clothing/neck/necklace/memento_mori/proc/consume_guardian(mob/living/basic/guardian/guardian) new /obj/effect/temp_visual/guardian/phase/out(get_turf(guardian)) guardian.locked = TRUE guardian.forceMove(src) to_chat(guardian, span_userdanger("You have been locked away in your summoner's pendant!")) guardian.playsound_local(get_turf(guardian), 'sound/magic/summonitems_generic.ogg', 50, TRUE) -/obj/item/clothing/neck/necklace/memento_mori/proc/regurgitate_guardian(mob/living/simple_animal/hostile/guardian/guardian) +/obj/item/clothing/neck/necklace/memento_mori/proc/regurgitate_guardian(mob/living/basic/guardian/guardian) guardian.locked = FALSE guardian.recall(forced = TRUE) to_chat(guardian, span_notice("You have been returned back from your summoner's pendant!")) @@ -538,8 +538,11 @@ . = ..() if(!ishuman(exposed_mob) || exposed_mob.stat == DEAD) return + if(!(methods & (INGEST | TOUCH))) + return var/mob/living/carbon/human/exposed_human = exposed_mob - if(!HAS_TRAIT(exposed_human, TRAIT_CAN_USE_FLIGHT_POTION) || reac_volume < 5 || !exposed_human.dna) + var/obj/item/bodypart/chest/chest = exposed_human.get_bodypart(BODY_ZONE_CHEST) + if(!chest.wing_types || reac_volume < 5 || !exposed_human.dna) if((methods & INGEST) && show_message) to_chat(exposed_human, span_notice("You feel nothing but a terrible aftertaste.")) return @@ -547,16 +550,16 @@ to_chat(exposed_human, span_userdanger("A terrible pain travels down your back as your wings change shape!")) else to_chat(exposed_human, span_userdanger("A terrible pain travels down your back as wings burst out!")) - var/obj/item/organ/external/wings/functional/wings = get_wing_choice(exposed_human) + var/obj/item/organ/external/wings/functional/wings = get_wing_choice(exposed_human, chest) wings = new wings() wings.Insert(exposed_human) exposed_human.dna.species.handle_mutant_bodyparts(exposed_human) playsound(exposed_human.loc, 'sound/items/poster_ripped.ogg', 50, TRUE, -1) - exposed_human.adjustBruteLoss(20) + exposed_human.apply_damage(20, def_zone = BODY_ZONE_CHEST, forced = TRUE, wound_bonus = CANT_WOUND) exposed_human.emote("scream") -/datum/reagent/flightpotion/proc/get_wing_choice(mob/living/carbon/human/needs_wings) - var/list/wing_types = needs_wings.dna.species.wing_types.Copy() +/datum/reagent/flightpotion/proc/get_wing_choice(mob/needs_wings, obj/item/bodypart/chest/chest) + var/list/wing_types = chest.wing_types.Copy() if(wing_types.len == 1 || !needs_wings.client) return wing_types[1] var/list/radial_wings = list() diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index 4f28db93bc6e45..848ecac0fa33da 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -70,6 +70,7 @@ icon = 'icons/obj/machines/mining_machines.dmi' icon_state = "console" density = TRUE + interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON|INTERACT_MACHINE_SET_MACHINE /// Connected ore processing machine. var/obj/machinery/mineral/processing_unit/processing_machine diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm index 840c8e92900a89..7661549a77d9e8 100644 --- a/code/modules/mining/machine_silo.dm +++ b/code/modules/mining/machine_silo.dm @@ -8,6 +8,7 @@ GLOBAL_LIST_EMPTY(silo_access_logs) icon_state = "silo" density = TRUE circuit = /obj/item/circuitboard/machine/ore_silo + interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON|INTERACT_MACHINE_SET_MACHINE /// The machine UI's page of logs showing ore history. var/log_page = 1 diff --git a/code/modules/mining/satchel_ore_boxdm.dm b/code/modules/mining/satchel_ore_boxdm.dm index 564ec2e92b028f..607bbcd9f06d87 100644 --- a/code/modules/mining/satchel_ore_boxdm.dm +++ b/code/modules/mining/satchel_ore_boxdm.dm @@ -83,8 +83,6 @@ return if(!Adjacent(usr)) return - add_fingerprint(usr) - usr.set_machine(src) switch(action) if("removeall") dump_box_contents() diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index 0688778b04840e..1bb8e61ef2b9a3 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -46,20 +46,28 @@ /datum/emote/help/run_emote(mob/user, params, type_override, intentional) . = ..() var/list/keys = list() - var/list/message = list("Available emotes, you can use them with say \"*emote\": ") + var/list/message = list("Available emotes, you can use them with say [span_bold("\"*emote\"")]: \n") + message += span_smallnoticeital("Note - emotes highlighted in blue play a sound \n\n") for(var/key in GLOB.emote_list) - for(var/datum/emote/P in GLOB.emote_list[key]) - if(P.key in keys) + for(var/datum/emote/emote_action in GLOB.emote_list[key]) + if(emote_action.key in keys) continue - if(P.can_run_emote(user, status_check = FALSE , intentional = TRUE)) - keys += P.key + if(emote_action.can_run_emote(user, status_check = FALSE , intentional = TRUE)) + keys += emote_action.key keys = sort_list(keys) + + // the span formatting will mess up sorting so need to do it afterwards + for(var/i in 1 to keys.len) + for(var/datum/emote/emote_action in GLOB.emote_list[keys[i]]) + if(emote_action.get_sound(user) && emote_action.should_play_sound(user, intentional = TRUE)) + keys[i] = span_boldnotice(keys[i]) + message += keys.Join(", ") message += "." message = message.Join("") - to_chat(user, message) + to_chat(user, examine_block(message)) /datum/emote/flip key = "flip" diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index 4ad94270837eaf..585c8b6b97ba45 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -208,7 +208,7 @@ face_atom(target) if (!ignore_cooldown) changeNext_move(melee_attack_cooldown) - if(SEND_SIGNAL(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, target) & COMPONENT_HOSTILE_NO_ATTACK) + if(SEND_SIGNAL(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, target, Adjacent(target), modifiers) & COMPONENT_HOSTILE_NO_ATTACK) return FALSE //but more importantly return before attack_animal called var/result = target.attack_basic_mob(src, modifiers) SEND_SIGNAL(src, COMSIG_HOSTILE_POST_ATTACKINGTARGET, target, result) diff --git a/code/modules/mob/living/basic/basic_defense.dm b/code/modules/mob/living/basic/basic_defense.dm index 3fe35bcd266de9..a1093f914d83f6 100644 --- a/code/modules/mob/living/basic/basic_defense.dm +++ b/code/modules/mob/living/basic/basic_defense.dm @@ -11,13 +11,13 @@ var/shove_dir = get_dir(user, src) if(!Move(get_step(src, shove_dir), shove_dir)) log_combat(user, src, "shoved", "failing to move it") - user.visible_message(span_danger("[user.name] shoves [src]!"), - span_danger("You shove [src]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, list(src)) + user.visible_message(span_danger("[user.name] [response_disarm_continuous] [src]!"), + span_danger("You [response_disarm_simple] [src]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, list(src)) to_chat(src, span_userdanger("You're shoved by [user.name]!")) return TRUE log_combat(user, src, "shoved", "pushing it") - user.visible_message(span_danger("[user.name] shoves [src], pushing [p_them()]!"), - span_danger("You shove [src], pushing [p_them()]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, list(src)) + user.visible_message(span_danger("[user.name] [response_disarm_continuous] [src], pushing [p_them()]!"), + span_danger("You [response_disarm_simple] [src], pushing [p_them()]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, list(src)) to_chat(src, span_userdanger("You're pushed by [user.name]!")) return TRUE diff --git a/code/modules/mob/living/basic/blob_minions/blob_ai.dm b/code/modules/mob/living/basic/blob_minions/blob_ai.dm index fc21d030d07d1b..5aad05d4656ffc 100644 --- a/code/modules/mob/living/basic/blob_minions/blob_ai.dm +++ b/code/modules/mob/living/basic/blob_minions/blob_ai.dm @@ -4,7 +4,7 @@ */ /datum/ai_controller/basic_controller/blobbernaut blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = HARD_CRIT, ) @@ -21,7 +21,7 @@ */ /datum/ai_controller/basic_controller/blob_zombie blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = HARD_CRIT, ) @@ -39,7 +39,7 @@ */ /datum/ai_controller/basic_controller/blob_spore blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = HARD_CRIT, ) diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index 5682edf933907e..e55b91bade2ec5 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -391,8 +391,7 @@ /mob/living/basic/clown/mutant/glutton/Initialize(mapload) . = ..() - var/datum/action/cooldown/regurgitate/spit = new(src) - spit.Grant(src) + GRANT_ACTION(/datum/action/cooldown/regurgitate) AddElement(/datum/element/swabable, CELL_LINE_TABLE_GLUTTON, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/cheesiehonkers, /obj/item/food/cornchips), tame_chance = 30, bonus_tame_chance = 0, after_tame = CALLBACK(src, PROC_REF(tamed))) @@ -541,22 +540,15 @@ BB_EMOTE_SEE = list("bites into the banana", "plucks a banana off its head", "photosynthesizes"), BB_EMOTE_SOUND = list('sound/items/bikehorn.ogg'), ) - ///Our peel dropping ability - var/datum/action/cooldown/rustle/banana_rustle - ///Our banana bunch spawning ability - var/datum/action/cooldown/exquisite_bunch/banana_bunch /mob/living/basic/clown/banana/Initialize(mapload) . = ..() - banana_rustle = new() - banana_rustle.Grant(src) - banana_bunch = new() - banana_bunch.Grant(src) -/mob/living/basic/clown/banana/Destroy() - . = ..() - QDEL_NULL(banana_rustle) - QDEL_NULL(banana_bunch) + var/static/list/innate_actions = list( + /datum/action/cooldown/exquisite_bunch, + /datum/action/cooldown/rustle, + ) + grant_actions_by_list(innate_actions) ///drops peels around the mob when activated /datum/action/cooldown/rustle diff --git a/code/modules/mob/living/basic/clown/clown_ai.dm b/code/modules/mob/living/basic/clown/clown_ai.dm index f54c432140ee34..b3f5a9f9aef464 100644 --- a/code/modules/mob/living/basic/clown/clown_ai.dm +++ b/code/modules/mob/living/basic/clown/clown_ai.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/clown blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_BASIC_MOB_SPEAK_LINES = null, ) @@ -14,7 +14,7 @@ /datum/ai_controller/basic_controller/clown/murder blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_BASIC_MOB_SPEAK_LINES = null, BB_TARGET_MINIMUM_STAT = HARD_CRIT, ) diff --git a/code/modules/mob/living/basic/constructs/construct_ai.dm b/code/modules/mob/living/basic/constructs/construct_ai.dm deleted file mode 100644 index 367bce491838bd..00000000000000 --- a/code/modules/mob/living/basic/constructs/construct_ai.dm +++ /dev/null @@ -1,39 +0,0 @@ -/// Artificers -/datum/ai_controller/basic_controller/artificer - blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/same_faction/construct, - BB_FLEE_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_TARGET_WOUNDED_ONLY = TRUE, - ) - - ai_movement = /datum/ai_movement/basic_avoidance - idle_behavior = /datum/idle_behavior/idle_random_walk - planning_subtrees = list( - /datum/ai_planning_subtree/simple_find_wounded_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree, - /datum/ai_planning_subtree/target_retaliate/to_flee, - /datum/ai_planning_subtree/flee_target/from_flee_key, - ) - -/// Juggernauts -/datum/ai_controller/basic_controller/juggernaut - blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_TARGET_MINIMUM_STAT = SOFT_CRIT, - ) - - ai_movement = /datum/ai_movement/basic_avoidance - idle_behavior = /datum/idle_behavior/idle_random_walk - planning_subtrees = list( - /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree, - ) - -/// Targetting datum that will only allow mobs that constructs can heal. -/datum/targetting_datum/basic/same_faction/construct - target_wounded_key = BB_TARGET_WOUNDED_ONLY - -/datum/targetting_datum/basic/same_faction/construct/can_attack(mob/living/living_mob, atom/the_target, vision_range, check_faction = TRUE) - if(isconstruct(the_target) || istype(the_target, /mob/living/simple_animal/shade)) - return ..() - return FALSE diff --git a/code/modules/mob/living/basic/constructs/_construct.dm b/code/modules/mob/living/basic/cult/constructs/_construct.dm similarity index 73% rename from code/modules/mob/living/basic/constructs/_construct.dm rename to code/modules/mob/living/basic/cult/constructs/_construct.dm index fcafab622590cb..6181eb3d0f44db 100644 --- a/code/modules/mob/living/basic/constructs/_construct.dm +++ b/code/modules/mob/living/basic/cult/constructs/_construct.dm @@ -22,6 +22,7 @@ response_disarm_simple = "flail at" response_harm_continuous = "punches" response_harm_simple = "punch" + melee_attack_cooldown = CLICK_CD_MELEE // Vivid red, cause cult theme lighting_cutoff_red = 30 @@ -42,27 +43,32 @@ var/can_repair_self = FALSE /// Theme controls color. THEME_CULT is red THEME_WIZARD is purple and THEME_HOLY is blue var/theme = THEME_CULT - /// What flavor of gunk does this construct drop on death? - var/static/list/remains = list(/obj/item/ectoplasm/construct) - /// Can this construct smash walls? Gets the wall_smasher element if so. + /// Can this construct destroy walls? var/smashes_walls = FALSE + /// The different flavors of goop constructs can drop, depending on theme. + var/static/list/remains_by_theme = list( + THEME_CULT = list(/obj/item/ectoplasm/construct), + THEME_HOLY = list(/obj/item/ectoplasm/angelic), + THEME_WIZARD = list(/obj/item/ectoplasm/mystic), + ) /mob/living/basic/construct/Initialize(mapload) . = ..() AddElement(/datum/element/simple_flying) + var/list/remains = string_list(remains_by_theme[theme]) if(length(remains)) AddElement(/datum/element/death_drops, remains) if(smashes_walls) - AddElement(/datum/element/wall_smasher, strength_flag = ENVIRONMENT_SMASH_WALLS) + AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE) if(can_repair) AddComponent(\ /datum/component/healing_touch,\ heal_brute = 5,\ heal_burn = 0,\ heal_time = 0,\ - valid_targets_typecache = typecacheof(list(/mob/living/basic/construct, /mob/living/simple_animal/hostile/construct, /mob/living/simple_animal/shade)),\ + valid_targets_typecache = typecacheof(list(/mob/living/basic/construct, /mob/living/basic/shade)),\ valid_biotypes = MOB_MINERAL | MOB_SPIRIT,\ - self_targetting = can_repair_self ? HEALING_TOUCH_ANYONE : HEALING_TOUCH_NOT_SELF,\ + self_targeting = can_repair_self ? HEALING_TOUCH_ANYONE : HEALING_TOUCH_NOT_SELF,\ action_text = "%SOURCE% begins repairing %TARGET%'s dents.",\ complete_text = "%TARGET%'s dents are repaired.",\ show_health = TRUE,\ @@ -74,9 +80,7 @@ structure_types_typecache = structure_types,\ ) add_traits(list(TRAIT_HEALS_FROM_CULT_PYLONS, TRAIT_SPACEWALK), INNATE_TRAIT) - for(var/spell in construct_spells) - var/datum/action/new_spell = new spell(src) - new_spell.Grant(src) + grant_actions_by_list(construct_spells) var/spell_count = 1 for(var/datum/action/spell as anything in actions) @@ -123,34 +127,6 @@ /mob/living/basic/construct/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE) return FALSE -// Allows simple constructs to repair basic constructs. -/mob/living/basic/construct/attack_animal(mob/living/simple_animal/user, list/modifiers) - if(!isconstruct(user)) - if(src != user) - return ..() - return - - if(src == user) //basic constructs use the healing hands component instead - return - - var/mob/living/simple_animal/hostile/construct/doll = user - if(!doll.can_repair || (doll == src && !doll.can_repair_self)) - return ..() - if(theme != doll.theme) - return ..() - - if(health >= maxHealth) - to_chat(user, span_cult("You cannot repair [src]'s dents, as [p_they()] [p_have()] none!")) - return - - heal_overall_damage(brute = 5) - - Beam(user, icon_state = "sendbeam", time = 4) - user.visible_message( - span_danger("[user] repairs some of \the [src]'s dents."), - span_cult("You repair some of [src]'s dents, leaving [src] at [health]/[maxHealth] health."), - ) - /// Construct ectoplasm. Largely a placeholder, since the death drop element needs a unique list. /obj/item/ectoplasm/construct name = "blood-red ectoplasm" diff --git a/code/modules/mob/living/basic/constructs/artificer.dm b/code/modules/mob/living/basic/cult/constructs/artificer.dm similarity index 98% rename from code/modules/mob/living/basic/constructs/artificer.dm rename to code/modules/mob/living/basic/cult/constructs/artificer.dm index d3be414791b429..8856c0e66a2ada 100644 --- a/code/modules/mob/living/basic/constructs/artificer.dm +++ b/code/modules/mob/living/basic/cult/constructs/artificer.dm @@ -15,11 +15,11 @@ attack_verb_simple = "ram" attack_sound = 'sound/weapons/punch2.ogg' construct_spells = list( + /datum/action/cooldown/spell/aoe/magic_missile/lesser, + /datum/action/cooldown/spell/conjure/construct/lesser, /datum/action/cooldown/spell/conjure/cult_floor, /datum/action/cooldown/spell/conjure/cult_wall, /datum/action/cooldown/spell/conjure/soulstone, - /datum/action/cooldown/spell/conjure/construct/lesser, - /datum/action/cooldown/spell/aoe/magic_missile/lesser, /datum/action/innate/cult/create_rune/revive, ) playstyle_string = "You are an Artificer. You are incredibly weak and fragile, \ @@ -43,6 +43,7 @@ /mob/living/basic/construct/artificer/hostile ai_controller = /datum/ai_controller/basic_controller/artificer smashes_walls = FALSE + melee_attack_cooldown = 2 SECONDS // Alternate artificer themes /mob/living/basic/construct/artificer/angelic diff --git a/code/modules/mob/living/basic/cult/constructs/construct_ai.dm b/code/modules/mob/living/basic/cult/constructs/construct_ai.dm new file mode 100644 index 00000000000000..b8417affed94cf --- /dev/null +++ b/code/modules/mob/living/basic/cult/constructs/construct_ai.dm @@ -0,0 +1,90 @@ +/** + * Artificers + * + * Artificers will seek out and heal the most wounded construct or shade they can see. + * If there is no one to heal, they will run away from any non-allied mobs. + */ +/datum/ai_controller/basic_controller/artificer + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/same_faction/construct, + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGET_WOUNDED_ONLY = TRUE, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_wounded_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/target_retaliate/to_flee, + /datum/ai_planning_subtree/flee_target/from_flee_key, + ) + +/** + * Juggernauts + * + * Juggernauts slowly walk toward non-allied mobs and pummel them to death. + */ +/datum/ai_controller/basic_controller/juggernaut + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGET_MINIMUM_STAT = HARD_CRIT, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/attack_obstacle_in_path, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/** + * Proteons + * + * Proteons perform cowardly hit-and-run attacks, fleeing melee when struck but returning to fight again. + */ +/datum/ai_controller/basic_controller/proteon + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGET_MINIMUM_STAT = HARD_CRIT, + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate/to_flee, + /datum/ai_planning_subtree/flee_target/from_flee_key, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/attack_obstacle_in_path, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/** + * Wraiths + * + * Wraiths seek out the most injured non-allied mob to beat to death. + */ +/datum/ai_controller/basic_controller/wraith + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGET_MINIMUM_STAT = HARD_CRIT, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_wounded_target, + /datum/ai_planning_subtree/attack_obstacle_in_path, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/// Targeting strategy that will only allow mobs that constructs can heal. +/datum/targeting_strategy/basic/same_faction/construct + target_wounded_key = BB_TARGET_WOUNDED_ONLY + +/datum/targeting_strategy/basic/same_faction/construct/can_attack(mob/living/living_mob, atom/the_target, vision_range, check_faction = TRUE) + if(isconstruct(the_target) || istype(the_target, /mob/living/basic/shade)) + return ..() + return FALSE diff --git a/code/modules/mob/living/basic/constructs/harvester.dm b/code/modules/mob/living/basic/cult/constructs/harvester.dm similarity index 100% rename from code/modules/mob/living/basic/constructs/harvester.dm rename to code/modules/mob/living/basic/cult/constructs/harvester.dm diff --git a/code/modules/mob/living/basic/constructs/juggernaut.dm b/code/modules/mob/living/basic/cult/constructs/juggernaut.dm similarity index 97% rename from code/modules/mob/living/basic/constructs/juggernaut.dm rename to code/modules/mob/living/basic/cult/constructs/juggernaut.dm index 9d8f4567bd2689..6beee5554a3ca7 100644 --- a/code/modules/mob/living/basic/constructs/juggernaut.dm +++ b/code/modules/mob/living/basic/cult/constructs/juggernaut.dm @@ -19,8 +19,8 @@ mob_size = MOB_SIZE_LARGE force_threshold = 10 construct_spells = list( - /datum/action/cooldown/spell/forcewall/cult, /datum/action/cooldown/spell/basic_projectile/juggernaut, + /datum/action/cooldown/spell/forcewall/cult, /datum/action/innate/cult/create_rune/wall, ) playstyle_string = span_bold("You are a Juggernaut. Though slow, your shell can withstand heavy punishment, create shield walls, rip apart enemies and walls alike, and even deflect energy weapons.") @@ -31,6 +31,7 @@ /mob/living/basic/construct/juggernaut/hostile ai_controller = /datum/ai_controller/basic_controller/juggernaut smashes_walls = FALSE + melee_attack_cooldown = 2 SECONDS /mob/living/basic/construct/juggernaut/bullet_act(obj/projectile/bullet) if(!istype(bullet, /obj/projectile/energy) && !istype(bullet, /obj/projectile/beam)) @@ -58,5 +59,3 @@ /mob/living/basic/construct/juggernaut/mystic theme = THEME_WIZARD - -/mob/living/basic/construct/juggernaut/noncult diff --git a/code/modules/mob/living/basic/cult/constructs/proteon.dm b/code/modules/mob/living/basic/cult/constructs/proteon.dm new file mode 100644 index 00000000000000..2ff58d2463c0ba --- /dev/null +++ b/code/modules/mob/living/basic/cult/constructs/proteon.dm @@ -0,0 +1,39 @@ +/// Proteon - a very weak construct that only appears in NPC form in various ruins. +/mob/living/basic/construct/proteon + name = "Proteon" + real_name = "Proteon" + desc = "A weaker construct meant to scour ruins for objects of Nar'Sie's affection. Those barbed claws are no joke." + icon_state = "proteon" + icon_living = "proteon" + maxHealth = 35 + health = 35 + melee_damage_lower = 8 + melee_damage_upper = 10 + attack_verb_continuous = "pinches" + attack_verb_simple = "pinch" + smashes_walls = TRUE + attack_sound = 'sound/weapons/punch2.ogg' + playstyle_string = span_bold("You are a Proteon. Your abilities in combat are outmatched by most combat constructs, but you are still fast and nimble. Run metal and supplies, and cooperate with your fellow cultists.") + +/// Hostile NPC version +/mob/living/basic/construct/proteon/hostile + ai_controller = /datum/ai_controller/basic_controller/proteon + smashes_walls = FALSE + melee_attack_cooldown = 1.5 SECONDS + +/mob/living/basic/construct/proteon/hostile/Initialize(mapload) + . = ..() + var/datum/callback/retaliate_callback = CALLBACK(src, PROC_REF(ai_retaliate_behaviour)) + AddComponent(/datum/component/ai_retaliate_advanced, retaliate_callback) + +/// Set a timer to clear our retaliate list +/mob/living/basic/construct/proteon/hostile/proc/ai_retaliate_behaviour(mob/living/attacker) + if (!istype(attacker)) + return + var/random_timer = rand(2 SECONDS, 4 SECONDS) //for unpredictability + addtimer(CALLBACK(src, PROC_REF(clear_retaliate_list)), random_timer) + +/mob/living/basic/construct/proteon/hostile/proc/clear_retaliate_list() + if(!ai_controller.blackboard_key_exists(BB_BASIC_MOB_RETALIATE_LIST)) + return + ai_controller.clear_blackboard_key(BB_BASIC_MOB_RETALIATE_LIST) diff --git a/code/modules/mob/living/basic/cult/constructs/wraith.dm b/code/modules/mob/living/basic/cult/constructs/wraith.dm new file mode 100644 index 00000000000000..06a09b6446ed39 --- /dev/null +++ b/code/modules/mob/living/basic/cult/constructs/wraith.dm @@ -0,0 +1,50 @@ +/mob/living/basic/construct/wraith + name = "Wraith" + real_name = "Wraith" + desc = "A wicked, clawed shell constructed to assassinate enemies and sow chaos behind enemy lines." + icon_state = "wraith" + icon_living = "wraith" + maxHealth = 65 + health = 65 + melee_damage_lower = 20 + melee_damage_upper = 20 + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" + attack_sound = 'sound/weapons/bladeslice.ogg' + attack_vis_effect = ATTACK_EFFECT_SLASH + construct_spells = list( + /datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift, + /datum/action/innate/cult/create_rune/tele, + ) + playstyle_string = span_bold("You are a Wraith. Though relatively fragile, you are fast, deadly, and can phase through walls. Your attacks will lower the cooldown on phasing, moreso for fatal blows.") + +/mob/living/basic/construct/wraith/Initialize(mapload) + . = ..() + var/datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/jaunt = locate() in actions + if(isnull(jaunt)) + return . + AddComponent(/datum/component/recharging_attacks, recharged_action = jaunt) + +/// Hostile NPC version. Attempts to kill the lowest-health mob it can see. +/mob/living/basic/construct/wraith/hostile + ai_controller = /datum/ai_controller/basic_controller/wraith + melee_attack_cooldown = 1.5 SECONDS + +// Alternate wraith themes +/mob/living/basic/construct/wraith/angelic + theme = THEME_HOLY + construct_spells = list( + /datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/angelic, + /datum/action/innate/cult/create_rune/tele, + ) + +/mob/living/basic/construct/wraith/angelic/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_ANGELIC, INNATE_TRAIT) + +/mob/living/basic/construct/wraith/mystic + theme = THEME_WIZARD + construct_spells = list( + /datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/mystic, + /datum/action/innate/cult/create_rune/tele, + ) diff --git a/code/modules/mob/living/basic/cult/shade.dm b/code/modules/mob/living/basic/cult/shade.dm new file mode 100644 index 00000000000000..fac1d347665ef5 --- /dev/null +++ b/code/modules/mob/living/basic/cult/shade.dm @@ -0,0 +1,71 @@ +/mob/living/basic/shade + name = "Shade" + real_name = "Shade" + desc = "A bound spirit." + gender = PLURAL + icon = 'icons/mob/nonhuman-player/cult.dmi' + icon_state = "shade_cult" + icon_living = "shade_cult" + mob_biotypes = MOB_SPIRIT + maxHealth = 40 + health = 40 + speak_emote = list("hisses") + response_help_continuous = "puts their hand through" + response_help_simple = "put your hand through" + response_disarm_continuous = "flails at" + response_disarm_simple = "flail at" + response_harm_continuous = "punches" + response_harm_simple = "punch" + melee_damage_lower = 5 + melee_damage_upper = 12 + attack_verb_continuous = "metaphysically strikes" + attack_verb_simple = "metaphysically strike" + unsuitable_cold_damage = 0 + unsuitable_heat_damage = 0 + unsuitable_atmos_damage = 0 + speed = -1 + faction = list(FACTION_CULT) + basic_mob_flags = DEL_ON_DEATH + initial_language_holder = /datum/language_holder/construct + /// Theme controls color. THEME_CULT is red THEME_WIZARD is purple and THEME_HOLY is blue + var/theme = THEME_CULT + /// The different flavors of goop shades can drop, depending on theme. + var/static/list/remains_by_theme = list( + THEME_CULT = list(/obj/item/ectoplasm/construct), + THEME_HOLY = list(/obj/item/ectoplasm/angelic), + THEME_WIZARD = list(/obj/item/ectoplasm/mystic), + ) + +/mob/living/basic/shade/Initialize(mapload) + . = ..() + AddElement(/datum/element/simple_flying) + add_traits(list(TRAIT_HEALS_FROM_CULT_PYLONS, TRAIT_SPACEWALK, TRAIT_VENTCRAWLER_ALWAYS), INNATE_TRAIT) + if(isnull(theme)) + return + icon_state = "shade_[theme]" + var/list/remains = string_list(remains_by_theme[theme]) + if(length(remains)) + AddElement(/datum/element/death_drops, remains) + +/mob/living/basic/shade/update_icon_state() + . = ..() + if(!isnull(theme)) + icon_state = "shade_[theme]" + icon_living = icon_state + +/mob/living/basic/shade/death() + if(death_message == initial(death_message)) + death_message = "lets out a contented sigh as [p_their()] form unwinds." + ..() + +/mob/living/basic/shade/can_suicide() + if(istype(loc, /obj/item/soulstone)) //do not suicide inside the soulstone + return FALSE + return ..() + +/mob/living/basic/shade/attackby(obj/item/item, mob/user, params) + if(istype(item, /obj/item/soulstone)) + var/obj/item/soulstone/stone = item + stone.capture_shade(src, user) + else + . = ..() diff --git a/code/modules/mob/living/basic/drone/drones_as_items.dm b/code/modules/mob/living/basic/drone/drones_as_items.dm index 12e604bd9aad8e..d816c9b3060c0e 100644 --- a/code/modules/mob/living/basic/drone/drones_as_items.dm +++ b/code/modules/mob/living/basic/drone/drones_as_items.dm @@ -26,7 +26,13 @@ . = ..() var/area/area = get_area(src) if(area) - notify_ghosts("A drone shell has been created in \the [area.name].", source = src, action = NOTIFY_PLAY, flashwindow = FALSE, ignore_key = POLL_IGNORE_DRONE, notify_suiciders = FALSE) + notify_ghosts( + "A drone shell has been created in \the [area.name].", + source = src, + action = NOTIFY_PLAY, + notify_flags = (GHOST_NOTIFY_IGNORE_MAPLOAD), + ignore_key = POLL_IGNORE_DRONE, + ) /obj/effect/mob_spawn/ghost_role/drone/allow_spawn(mob/user, silent = FALSE) var/client/user_client = user.client diff --git a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm index 692a7f108d1898..dfaff9f4efc414 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm @@ -61,7 +61,7 @@ /datum/pet_command/beehive/enter, /datum/pet_command/beehive/exit, /datum/pet_command/follow/bee, - /datum/pet_command/point_targetting/attack/swirl, + /datum/pet_command/point_targeting/attack/swirl, /datum/pet_command/scatter, ) diff --git a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm index 67e98a5f3d3e84..0c48a9453811d5 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm @@ -83,9 +83,9 @@ if(valid_hives.len) return pick(valid_hives) -/datum/targetting_datum/basic/bee +/datum/targeting_strategy/basic/bee -/datum/targetting_datum/basic/bee/can_attack(mob/living/owner, atom/target, vision_range) +/datum/targeting_strategy/basic/bee/can_attack(mob/living/owner, atom/target, vision_range) if(!isliving(target)) return FALSE . = ..() @@ -117,7 +117,7 @@ required_distance = 0 ///swirl around the owner in menacing fashion -/datum/pet_command/point_targetting/attack/swirl +/datum/pet_command/point_targeting/attack/swirl command_name = "Swirl" command_desc = "Your pets will swirl around you and attack whoever you point at!" speech_commands = list("swirl", "spiral", "swarm") @@ -127,7 +127,7 @@ ///the owner we will swarm around var/key_to_swarm = BB_SWARM_TARGET -/datum/pet_command/point_targetting/attack/swirl/try_activate_command(mob/living/commander) +/datum/pet_command/point_targeting/attack/swirl/try_activate_command(mob/living/commander) var/mob/living/living_pawn = weak_parent.resolve() if(isnull(living_pawn)) return @@ -138,7 +138,7 @@ controller.set_blackboard_key(key_to_swarm, commander) return ..() -/datum/pet_command/point_targetting/attack/swirl/execute_action(datum/ai_controller/controller) +/datum/pet_command/point_targeting/attack/swirl/execute_action(datum/ai_controller/controller) if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET)) return ..() controller.queue_behavior(/datum/ai_behavior/swirl_around_target, BB_SWARM_TARGET) diff --git a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_subtree.dm b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_subtree.dm index 6379f239ba0ba2..3d56dd990dcbdc 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_subtree.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_subtree.dm @@ -1,7 +1,7 @@ /datum/ai_controller/basic_controller/bee blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/bee, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/bee, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, ) ai_traits = STOP_MOVING_WHEN_PULLED @@ -25,7 +25,7 @@ /datum/ai_controller/basic_controller/queen_bee blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/bee, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/bee, ) ai_traits = STOP_MOVING_WHEN_PULLED diff --git a/code/modules/mob/living/basic/farm_animals/chicken/chick.dm b/code/modules/mob/living/basic/farm_animals/chicken/chick.dm index 311b311e8fd755..9e4af384aeeffe 100644 --- a/code/modules/mob/living/basic/farm_animals/chicken/chick.dm +++ b/code/modules/mob/living/basic/farm_animals/chicken/chick.dm @@ -66,7 +66,7 @@ /datum/ai_controller/basic_controller/chick blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_FIND_MOM_TYPES = list(/mob/living/basic/chicken), ) diff --git a/code/modules/mob/living/basic/farm_animals/chicken/chicken.dm b/code/modules/mob/living/basic/farm_animals/chicken/chicken.dm index 99ff6b52748298..9508f8fae3be6b 100644 --- a/code/modules/mob/living/basic/farm_animals/chicken/chicken.dm +++ b/code/modules/mob/living/basic/farm_animals/chicken/chicken.dm @@ -78,7 +78,7 @@ GLOBAL_VAR_INIT(chicken_count, 0) /datum/ai_controller/basic_controller/chicken blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED diff --git a/code/modules/mob/living/basic/farm_animals/cow/cow_ai.dm b/code/modules/mob/living/basic/farm_animals/cow/cow_ai.dm index 81e1d722b01e5c..e1e611a28c2a8a 100644 --- a/code/modules/mob/living/basic/farm_animals/cow/cow_ai.dm +++ b/code/modules/mob/living/basic/farm_animals/cow/cow_ai.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/cow blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, BB_BASIC_MOB_TIP_REACTING = FALSE, BB_BASIC_MOB_TIPPER = null, ) diff --git a/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm b/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm index 6eaef1bf5c3e56..f499859e19e911 100644 --- a/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm +++ b/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm @@ -44,7 +44,7 @@ /datum/ai_controller/basic_controller/cow/moonicorn blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items/moonicorn(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items/moonicorn, BB_BASIC_MOB_TIP_REACTING = FALSE, BB_BASIC_MOB_TIPPER = null, ) @@ -60,14 +60,14 @@ ) ///moonicorns will not attack people holding something that could tame them. -/datum/targetting_datum/basic/allow_items/moonicorn +/datum/targeting_strategy/basic/allow_items/moonicorn -/datum/targetting_datum/basic/allow_items/moonicorn/can_attack(mob/living/living_mob, atom/the_target, vision_range) +/datum/targeting_strategy/basic/allow_items/moonicorn/can_attack(mob/living/living_mob, atom/the_target, vision_range) . = ..() if(!.) return FALSE - if(isliving(the_target)) //Targetting vs living mobs + if(isliving(the_target)) //Targeting vs living mobs var/mob/living/living_target = the_target for(var/obj/item/food/grown/galaxythistle/tame_food in living_target.held_items) return FALSE //heyyy this can tame me! let's NOT fight diff --git a/code/modules/mob/living/basic/farm_animals/cow/cow_wisdom.dm b/code/modules/mob/living/basic/farm_animals/cow/cow_wisdom.dm index b62f57abf54dd2..4e80fd4bcfe932 100644 --- a/code/modules/mob/living/basic/farm_animals/cow/cow_wisdom.dm +++ b/code/modules/mob/living/basic/farm_animals/cow/cow_wisdom.dm @@ -22,7 +22,7 @@ return //cannot tame me! and I don't care about eatin' nothing, neither! /datum/ai_controller/basic_controller/cow/wisdom - //don't give a targetting datum + //don't give a targeting strategy blackboard = list( BB_BASIC_MOB_TIP_REACTING = FALSE, BB_BASIC_MOB_TIPPER = null, diff --git a/code/modules/mob/living/basic/farm_animals/deer.dm b/code/modules/mob/living/basic/farm_animals/deer.dm index 7907e6684431f4..7f2fbb68fe1b58 100644 --- a/code/modules/mob/living/basic/farm_animals/deer.dm +++ b/code/modules/mob/living/basic/farm_animals/deer.dm @@ -35,7 +35,7 @@ /datum/ai_controller/basic_controller/deer blackboard = list( BB_STATIONARY_MOVE_TO_TARGET = TRUE, - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/farm_animals/goat/goat_ai.dm b/code/modules/mob/living/basic/farm_animals/goat/goat_ai.dm index f8463b1967537c..5928344fee4e6d 100644 --- a/code/modules/mob/living/basic/farm_animals/goat/goat_ai.dm +++ b/code/modules/mob/living/basic/farm_animals/goat/goat_ai.dm @@ -1,7 +1,7 @@ /// Goats are normally content to sorta hang around and crunch any plant in sight, but they will go ape on someone who attacks them. /datum/ai_controller/basic_controller/goat blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm index cd184b2d253466..70e436b65d7758 100644 --- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm @@ -54,7 +54,7 @@ /mob/living/basic/gorilla/Initialize(mapload) . = ..() add_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP), ROUNDSTART_TRAIT) - AddElement(/datum/element/wall_smasher) + AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE) AddElement(/datum/element/dextrous) AddElement(/datum/element/footstep, FOOTSTEP_MOB_BAREFOOT) AddElement(/datum/element/basic_eating, heal_amt = 10, food_types = gorilla_food) diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_ai.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_ai.dm index daf5b7af0834b6..28a727fdb1bcef 100644 --- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_ai.dm +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_ai.dm @@ -1,7 +1,7 @@ /// Pretty basic, just click people to death. Also hunt and eat bananas. /datum/ai_controller/basic_controller/gorilla blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, BB_TARGET_MINIMUM_STAT = UNCONSCIOUS, BB_EMOTE_KEY = "ooga", BB_EMOTE_CHANCE = 40, @@ -27,7 +27,7 @@ /datum/ai_controller/basic_controller/gorilla/lesser blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, BB_EMOTE_KEY = "ooga", BB_EMOTE_CHANCE = 60, ) diff --git a/code/modules/mob/living/basic/farm_animals/pig.dm b/code/modules/mob/living/basic/farm_animals/pig.dm index c0ad3f6b349be5..94183d044c5315 100644 --- a/code/modules/mob/living/basic/farm_animals/pig.dm +++ b/code/modules/mob/living/basic/farm_animals/pig.dm @@ -47,7 +47,7 @@ /datum/ai_controller/basic_controller/pig blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED diff --git a/code/modules/mob/living/basic/farm_animals/pony.dm b/code/modules/mob/living/basic/farm_animals/pony.dm index e1765f0fdbac6b..df8f3a1fd4eec3 100644 --- a/code/modules/mob/living/basic/farm_animals/pony.dm +++ b/code/modules/mob/living/basic/farm_animals/pony.dm @@ -106,7 +106,7 @@ /datum/ai_controller/basic_controller/pony blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED diff --git a/code/modules/mob/living/basic/farm_animals/rabbit.dm b/code/modules/mob/living/basic/farm_animals/rabbit.dm index 19fd0120ba7e61..f77772ab17c7be 100644 --- a/code/modules/mob/living/basic/farm_animals/rabbit.dm +++ b/code/modules/mob/living/basic/farm_animals/rabbit.dm @@ -49,7 +49,7 @@ /datum/ai_controller/basic_controller/rabbit blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/farm_animals/sheep.dm b/code/modules/mob/living/basic/farm_animals/sheep.dm index ac320d80804194..e32da910ab99b8 100644 --- a/code/modules/mob/living/basic/farm_animals/sheep.dm +++ b/code/modules/mob/living/basic/farm_animals/sheep.dm @@ -81,7 +81,7 @@ /datum/ai_controller/basic_controller/sheep blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/festivus_pole.dm b/code/modules/mob/living/basic/festivus_pole.dm index 058b74bfad8726..aec6de74e1e4ce 100644 --- a/code/modules/mob/living/basic/festivus_pole.dm +++ b/code/modules/mob/living/basic/festivus_pole.dm @@ -40,19 +40,18 @@ ///how much charge we give off to cells around us when rubbed var/recharge_value = 75 + /mob/living/basic/festivus/Initialize(mapload) . = ..() AddComponent(/datum/component/seethrough_mob) var/static/list/death_loot = list(/obj/item/stack/rods) AddElement(/datum/element/death_drops, death_loot) AddComponent(/datum/component/aggro_emote, emote_list = string_list(list("growls")), emote_chance = 20) - var/datum/action/cooldown/mob_cooldown/charge_apc/charge_ability = new(src) - charge_ability.Grant(src) - ai_controller.set_blackboard_key(BB_FESTIVE_APC, charge_ability) + grant_actions_by_list(list(/datum/action/cooldown/mob_cooldown/charge_apc = BB_FESTIVE_APC)) /datum/ai_controller/basic_controller/festivus_pole blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_LOW_PRIORITY_HUNTING_TARGET = null, // APCs ) diff --git a/code/modules/mob/living/basic/guardian/guardian.dm b/code/modules/mob/living/basic/guardian/guardian.dm new file mode 100644 index 00000000000000..e36960a80ae7a2 --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian.dm @@ -0,0 +1,333 @@ +/** + * A mob which acts as a guardian angel to another mob, sharing health but protecting them using special powers. + * Usually either obtained in magical form by a wizard, or technological form by a traitor. Sometimes found by miners. + */ +/mob/living/basic/guardian + name = "Guardian Spirit" + real_name = "Guardian Spirit" + desc = "A mysterious being that stands by its charge, ever vigilant." + icon = 'icons/mob/nonhuman-player/guardian.dmi' + icon_state = "magicbase" + icon_living = "magicbase" + icon_dead = "magicbase" + gender = NEUTER + basic_mob_flags = DEL_ON_DEATH + mob_biotypes = MOB_SPECIAL + sentience_type = SENTIENCE_HUMANOID + hud_type = /datum/hud/guardian + faction = list() + speed = 0 + maxHealth = INFINITY // The spirit itself is invincible and passes damage to its host + health = INFINITY + damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) + unsuitable_atmos_damage = 0 + unsuitable_cold_damage = 0 + unsuitable_heat_damage = 0 + speak_emote = list("hisses") + bubble_icon = "guardian" + response_help_continuous = "passes through" + response_help_simple = "pass through" + response_disarm_continuous = "flails at" + response_disarm_simple = "flail at" + response_harm_continuous = "punches" + response_harm_simple = "punch" + attack_sound = 'sound/weapons/punch1.ogg' + attack_verb_continuous = "punches" + attack_verb_simple = "punch" + combat_mode = TRUE + obj_damage = 40 + melee_damage_lower = 15 + melee_damage_upper = 15 + melee_attack_cooldown = CLICK_CD_MELEE + light_system = MOVABLE_LIGHT + light_range = 3 + light_on = FALSE + + /// The summoner of the guardian, we share health with them and can't move too far away (usually) + var/mob/living/summoner + /// How far from the summoner the guardian can be. + var/range = 10 + + /// The guardian's colour, used for their sprite, chat, and some effects. + var/guardian_colour + /// Coloured overlay we apply + var/mutable_appearance/overlay + + /// Which toggle button the HUD uses. + var/toggle_button_type = /atom/movable/screen/guardian/toggle_mode/inactive + /// Name used by the guardian creator. + var/creator_name = "Error" + /// Description used by the guardian creator. + var/creator_desc = "This shouldn't be here! Report it on GitHub!" + /// Icon used by the guardian creator. + var/creator_icon = "fuck" + + /// What type of guardian are we? + var/guardian_type = null + /// How are we themed? + var/datum/guardian_fluff/theme + /// A string explaining to the guardian what they can do. + var/playstyle_string = span_boldholoparasite("You are a Guardian without any type. You shouldn't exist and are an affront to god!") + + /// Are we forced to not be able to manifest/recall? + var/locked = FALSE + /// Cooldown between manifests/recalls. + COOLDOWN_DECLARE(manifest_cooldown) + /// Cooldown between the summoner resetting the guardian's client. + COOLDOWN_DECLARE(resetting_cooldown) + + /// List of actions we give to our summoner + var/static/list/control_actions = list( + /datum/action/cooldown/mob_cooldown/guardian_comms, + /datum/action/cooldown/mob_cooldown/recall_guardian, + /datum/action/cooldown/mob_cooldown/replace_guardian, + ) + +/mob/living/basic/guardian/Initialize(mapload, datum/guardian_fluff/theme) + . = ..() + GLOB.parasites += src + src.theme = theme + theme?.apply(src) + var/list/death_loot = string_list(list(/obj/item/stack/sheet/mineral/wood)) + AddElement(/datum/element/death_drops, death_loot) + AddElement(/datum/element/simple_flying) + AddComponent(/datum/component/basic_inhands) + // life link + update_appearance(UPDATE_ICON) + manifest_effects() + +/mob/living/basic/guardian/Destroy() + GLOB.parasites -= src + if (is_deployed()) + recall_effects() + cut_summoner(different_person = TRUE) + return ..() + +/mob/living/basic/guardian/update_overlays() + . = ..() + . += overlay + +/mob/living/basic/guardian/Login() //if we have a mind, set its name to ours when it logs in + . = ..() + if (!. || isnull(client)) + return FALSE + if (isnull(summoner)) + to_chat(src, span_boldholoparasite("For some reason, somehow, you have no summoner. Please report this bug immediately.")) + stack_trace("Guardian created with client but no summoner.") + else + to_chat(src, span_holoparasite("You are a [theme.name], bound to serve [summoner.real_name].")) + to_chat(src, span_holoparasite("You are capable of manifesting or recalling to your master with the buttons on your HUD. You will also find a button to communicate with [summoner.p_them()] privately there.")) + to_chat(src, span_holoparasite("While personally invincible, you will die if [summoner.real_name] does, and any damage dealt to you will have a portion passed on to [summoner.p_them()] as you feed upon [summoner.p_them()] to sustain yourself.")) + to_chat(src, playstyle_string) + if (!isnull(guardian_colour)) + return // Already set up so we don't need to do it again + locked = TRUE + guardian_rename() + guardian_recolour() + locked = FALSE + +/mob/living/basic/guardian/mind_initialize() + . = ..() + if (isnull(summoner)) + to_chat(src, span_boldholoparasite("For some reason, somehow, you have no summoner. Please report this bug immediately.")) + return + mind.enslave_mind_to_creator(summoner) // Once our mind is created, we become enslaved to our summoner. cant be done in the first run of set_summoner, because by then we dont have a mind yet. + +/// Pick a new colour for our guardian +/mob/living/basic/guardian/proc/guardian_recolour() + if (isnull(client)) + return + var/chosen_guardian_colour = input(src, "What would you like your colour to be?", "Choose Your Colour", "#ffffff") as color|null + if (isnull(chosen_guardian_colour)) //redo proc until we get a color + to_chat(src, span_warning("Invalid colour, please try again.")) + return guardian_recolour() + set_guardian_colour(chosen_guardian_colour) + +/// Apply a new colour to our guardian +/mob/living/basic/guardian/proc/set_guardian_colour(colour) + guardian_colour = colour + set_light_color(guardian_colour) + overlay?.color = guardian_colour + update_appearance(UPDATE_ICON) + +/mob/living/basic/guardian/proc/guardian_rename() + if (isnull(client)) + return + + var/new_name = sanitize_name(reject_bad_text(tgui_input_text(src, "What would you like your name to be?", "Choose Your Name", generate_random_name(), MAX_NAME_LEN))) + if (!new_name) //redo proc until we get a good name + to_chat(src, span_warning("Invalid name, please try again.")) + return guardian_rename() + to_chat(src, span_notice("Your new name [span_name(new_name)] anchors itself in your mind.")) + fully_replace_character_name(null, new_name) + +/// Picks a random name as a suggestion +/mob/living/basic/guardian/proc/generate_random_name() + var/list/surname_options = list("Guardian") // Fallback in case you define a guardian with no theme + switch(theme?.fluff_type) + if (GUARDIAN_MAGIC) + surname_options = GLOB.guardian_fantasy_surnames + if (GUARDIAN_TECH) + surname_options = GLOB.guardian_tech_surnames + + return "[pick(GLOB.guardian_first_names)] [pick(surname_options)]" + +/mob/living/basic/guardian/melee_attack(atom/target, list/modifiers, ignore_cooldown) + if (!is_deployed()) + balloon_alert(src, "not tangible!") + return FALSE + return ..() + +/mob/living/basic/guardian/death(gibbed) + if (!QDELETED(summoner)) + to_chat(summoner, span_bolddanger("Your [name] died somehow!")) + summoner.dust() + return ..() + +/mob/living/basic/guardian/ex_act(severity, target) + switch(severity) + if (EXPLODE_DEVASTATE) + investigate_log("has been gibbed by an explosion.", INVESTIGATE_DEATHS) + gib() + return TRUE + if (EXPLODE_HEAVY) + adjustBruteLoss(60) + if (EXPLODE_LIGHT) + adjustBruteLoss(30) + + return TRUE + +/mob/living/basic/guardian/gib() + death(TRUE) + +/mob/living/basic/guardian/dust(just_ash, drop_items, force) + death(TRUE) + +/// Link up with a summoner mob. +/mob/living/basic/guardian/proc/set_summoner(mob/living/to_who, different_person = FALSE) + if (QDELETED(src)) + return // Just in case + if (QDELETED(to_who)) + ghostize(FALSE) + qdel(src) // No life of free invulnerability for you. + return + cut_summoner(different_person) + AddComponent(/datum/component/life_link, to_who, CALLBACK(src, PROC_REF(on_harm)), CALLBACK(src, PROC_REF(on_summoner_death))) + summoner = to_who + + for (var/action_type in control_actions) + if (locate(action_type) in summoner.actions) + continue + var/datum/action/new_action = new action_type(summoner) + new_action.Grant(summoner) + + if (different_person) + if (mind) + mind.enslave_mind_to_creator(to_who) + else //mindless guardian, manually give them factions + faction += summoner.faction + summoner.faction += "[REF(src)]" + remove_all_languages(LANGUAGE_MASTER) + copy_languages(to_who, LANGUAGE_MASTER) // make sure holoparasites speak same language as master + RegisterSignal(to_who, COMSIG_QDELETING, PROC_REF(on_summoner_deletion)) + RegisterSignal(to_who, COMSIG_LIVING_ON_WABBAJACKED, PROC_REF(on_summoner_wabbajacked)) + RegisterSignal(to_who, COMSIG_LIVING_SHAPESHIFTED, PROC_REF(on_summoner_shapeshifted)) + RegisterSignal(to_who, COMSIG_LIVING_UNSHAPESHIFTED, PROC_REF(on_summoner_unshapeshifted)) + recall(forced = TRUE) + leash_to(src, summoner) + if (to_who.stat == DEAD) + on_summoner_death(src, to_who) + summoner.updatehealth() + +/// Remove all references to our summoner +/mob/living/basic/guardian/proc/cut_summoner(different_person = FALSE) + if (isnull(summoner)) + return + if (is_deployed()) + recall_effects() + var/summoner_turf = get_turf(summoner) + if (!isnull(summoner_turf)) + forceMove(summoner_turf) + unleash() + UnregisterSignal(summoner, list(COMSIG_QDELETING, COMSIG_LIVING_ON_WABBAJACKED, COMSIG_LIVING_SHAPESHIFTED, COMSIG_LIVING_UNSHAPESHIFTED)) + if (different_person) + summoner.faction -= "[REF(src)]" + faction -= summoner.faction + mind?.remove_all_antag_datums() + if (!length(summoner.get_all_linked_holoparasites() - src)) + for (var/action_type in control_actions) + var/datum/action/remove_action = locate(action_type) in summoner.actions + if (isnull(remove_action)) + continue + remove_action.Remove(summoner) + summoner = null + +/// Connects these two mobs by a leash +/mob/living/basic/guardian/proc/leash_to(atom/movable/leashed, atom/movable/leashed_to) + leashed.AddComponent(\ + /datum/component/leash,\ + owner = leashed_to,\ + distance = range,\ + force_teleport_out_effect = /obj/effect/temp_visual/guardian/phase/out,\ + force_teleport_in_effect = /obj/effect/temp_visual/guardian/phase,\ + ) + +/// Removes the leash from this guardian +/mob/living/basic/guardian/proc/unleash() + qdel(GetComponent(/datum/component/leash)) + +/// Called when our owner dies. We fucked up, so now neither of us get to exist. +/mob/living/basic/guardian/proc/on_summoner_death(mob/living/source, mob/living/former_owner) + cut_summoner() + if (!isnull(former_owner.loc)) + forceMove(former_owner.loc) + to_chat(src, span_danger("Your summoner has died!")) + visible_message(span_bolddanger("\The [src] dies along with its user!")) + former_owner.visible_message(span_bolddanger("[former_owner]'s body is completely consumed by the strain of sustaining [src]!")) + former_owner.dust(drop_items = TRUE) + +/// Called when our health changes, inform our owner of why they are getting hurt (if they are) +/mob/living/basic/guardian/proc/on_harm(mob/living/source, mob/living/summoner, amount) + if (QDELETED(src) || QDELETED(summoner) || amount <= 2) + return + to_chat(summoner, span_bolddanger("[name] is under attack! You take damage!")) + summoner.visible_message(span_bolddanger("Blood sprays from [summoner] as [src] takes damage!")) + if(summoner.stat == UNCONSCIOUS || summoner.stat == HARD_CRIT) + to_chat(summoner, span_bolddanger("Your head pounds, you can't take the strain of sustaining [src] in this condition!")) + summoner.adjustOrganLoss(ORGAN_SLOT_BRAIN, amount * 0.5) + +/// When our owner is deleted, we go too. +/mob/living/basic/guardian/proc/on_summoner_deletion(mob/living/source) + SIGNAL_HANDLER + cut_summoner() + to_chat(src, span_danger("Your summoner is gone, you feel yourself fading!")) + ghostize(FALSE) + qdel(src) + +/// Signal proc for [COMSIG_LIVING_ON_WABBAJACKED], when our summoner is wabbajacked we should be alerted. +/mob/living/basic/guardian/proc/on_summoner_wabbajacked(mob/living/source, mob/living/new_mob) + SIGNAL_HANDLER + set_summoner(new_mob) + to_chat(src, span_holoparasite("Your summoner has changed form!")) + +/// Signal proc for [COMSIG_LIVING_SHAPESHIFTED], when our summoner is shapeshifted we should change to the new mob +/mob/living/basic/guardian/proc/on_summoner_shapeshifted(mob/living/source, mob/living/new_shape) + SIGNAL_HANDLER + set_summoner(new_shape) + to_chat(src, span_holoparasite("Your summoner has shapeshifted into that of a [new_shape]!")) + +/// Signal proc for [COMSIG_LIVING_UNSHAPESHIFTED], when our summoner unshapeshifts go back to that mob +/mob/living/basic/guardian/proc/on_summoner_unshapeshifted(mob/living/source, mob/living/old_summoner) + SIGNAL_HANDLER + set_summoner(old_summoner) + to_chat(src, span_holoparasite("Your summoner has shapeshifted back into their normal form!")) + +/mob/living/basic/guardian/wabbajack(what_to_randomize, change_flags = WABBAJACK) + visible_message(span_warning("[src] resists the polymorph!")) // Ha, no + +/mob/living/basic/guardian/can_suicide() + return FALSE // You gotta persuade your boss to end it instead, sorry + +/// Returns true if you are out and about +/mob/living/basic/guardian/proc/is_deployed() + return isnull(summoner) || loc != summoner diff --git a/code/modules/mob/living/simple_animal/guardian/guardian_creator.dm b/code/modules/mob/living/basic/guardian/guardian_creator.dm similarity index 60% rename from code/modules/mob/living/simple_animal/guardian/guardian_creator.dm rename to code/modules/mob/living/basic/guardian/guardian_creator.dm index ebd5658f07f4b3..7ebc9737b41064 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian_creator.dm +++ b/code/modules/mob/living/basic/guardian/guardian_creator.dm @@ -2,14 +2,15 @@ GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial()) /proc/setup_guardian_radial() . = list() - for(var/mob/living/simple_animal/hostile/guardian/guardian_path as anything in subtypesof(/mob/living/simple_animal/hostile/guardian)) + for(var/mob/living/basic/guardian/guardian_path as anything in subtypesof(/mob/living/basic/guardian)) var/datum/radial_menu_choice/option = new() option.name = initial(guardian_path.creator_name) option.image = image(icon = 'icons/hud/guardian.dmi', icon_state = initial(guardian_path.creator_icon)) option.info = span_boldnotice(initial(guardian_path.creator_desc)) .[guardian_path] = option -/obj/item/guardiancreator +/// An item which grants you your very own soul buddy +/obj/item/guardian_creator name = "enchanted deck of tarot cards" desc = "An enchanted deck of tarot cards, rumored to be a source of unimaginable power." icon = 'icons/obj/toys/playing_cards.dmi' @@ -31,36 +32,41 @@ GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial()) /// Message sent if we successfully get a guardian. var/success_message = span_holoparasite("%GUARDIAN has been summoned!") /// If true, you are given a random guardian rather than picking from a selection. - var/random = TRUE + var/random = FALSE /// If true, you can have multiple guardians at the same time. - var/allowmultiple = FALSE + var/allow_multiple = FALSE /// If true, lings can get guardians from this. - var/allowling = TRUE + var/allow_changeling = TRUE /// If true, a dextrous guardian can get their own guardian, infinite chain! - var/allowguardian = FALSE + var/allow_guardian = FALSE /// List of all the guardians this type can spawn. var/list/possible_guardians = list( //default, has everything but dextrous - /mob/living/simple_animal/hostile/guardian/assassin, - /mob/living/simple_animal/hostile/guardian/charger, - /mob/living/simple_animal/hostile/guardian/explosive, - /mob/living/simple_animal/hostile/guardian/gaseous, - /mob/living/simple_animal/hostile/guardian/gravitokinetic, - /mob/living/simple_animal/hostile/guardian/lightning, - /mob/living/simple_animal/hostile/guardian/protector, - /mob/living/simple_animal/hostile/guardian/ranged, - /mob/living/simple_animal/hostile/guardian/standard, - /mob/living/simple_animal/hostile/guardian/support, + /mob/living/basic/guardian/assassin, + /mob/living/basic/guardian/charger, + /mob/living/basic/guardian/explosive, + /mob/living/basic/guardian/gaseous, + /mob/living/basic/guardian/gravitokinetic, + /mob/living/basic/guardian/lightning, + /mob/living/basic/guardian/protector, + /mob/living/basic/guardian/ranged, + /mob/living/basic/guardian/standard, + /mob/living/basic/guardian/support, ) -/obj/item/guardiancreator/attack_self(mob/living/user) - if(isguardian(user) && !allowguardian) - to_chat(user, span_holoparasite("[mob_name] chains are not allowed.")) +/obj/item/guardian_creator/Initialize(mapload) + . = ..() + var/datum/guardian_fluff/using_theme = GLOB.guardian_themes[theme] + mob_name = using_theme.name + +/obj/item/guardian_creator/attack_self(mob/living/user) + if(isguardian(user) && !allow_guardian) + balloon_alert(user, "can't do that!") return var/list/guardians = user.get_all_linked_holoparasites() - if(length(guardians) && !allowmultiple) - to_chat(user, span_holoparasite("You already have a [mob_name]!")) + if(length(guardians) && !allow_multiple) + balloon_alert(user, "already have one!") return - if(user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling) && !allowling) + if(user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling) && !allow_changeling) to_chat(user, ling_failure) return if(used) @@ -71,19 +77,22 @@ GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial()) if(possible_guardian in possible_guardians) continue radial_options -= possible_guardian - var/mob/living/simple_animal/hostile/guardian/guardian_path + var/mob/living/basic/guardian/guardian_path if(random) guardian_path = pick(possible_guardians) else guardian_path = show_radial_menu(user, src, radial_options, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 42, require_near = TRUE) - if(!guardian_path) + if(isnull(guardian_path)) return used = TRUE to_chat(user, use_message) - var/guardian_type_name = "a random" - if(!random) - guardian_type_name = "the " + lowertext(initial(guardian_path.creator_name)) - var/list/mob/dead/observer/candidates = poll_ghost_candidates("Do you want to play as [guardian_type_name] [mob_name] of [user.real_name]?", ROLE_PAI, FALSE, 100, POLL_IGNORE_HOLOPARASITE) + var/guardian_type_name = random ? "Random" : capitalize(initial(guardian_path.creator_name)) + var/list/mob/dead/observer/candidates = poll_ghost_candidates( + "Do you want to play as [user.real_name]'s [guardian_type_name] [mob_name]?", + jobban_type = ROLE_PAI, + poll_time = 10 SECONDS, + ignore_category = POLL_IGNORE_HOLOPARASITE, + ) if(LAZYLEN(candidates)) var/mob/dead/observer/candidate = pick(candidates) spawn_guardian(user, candidate, guardian_path) @@ -91,124 +100,111 @@ GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial()) SEND_SIGNAL(src, COMSIG_TRAITOR_ITEM_USED(type)) else to_chat(user, failure_message) + used = FALSE -/obj/item/guardiancreator/proc/spawn_guardian(mob/living/user, mob/dead/candidate, guardian_path) +/// Actually create our guy +/obj/item/guardian_creator/proc/spawn_guardian(mob/living/user, mob/dead/candidate, guardian_path) if(QDELETED(user) || user.stat == DEAD) return var/list/guardians = user.get_all_linked_holoparasites() - if(length(guardians) && !allowmultiple) - to_chat(user, span_holoparasite("You already have a [mob_name]!") ) + if(length(guardians) && !allow_multiple) + balloon_alert(user, "already got one!") used = FALSE return - var/mob/living/simple_animal/hostile/guardian/summoned_guardian = new guardian_path(user, theme) + var/datum/guardian_fluff/guardian_theme = GLOB.guardian_themes[theme] + var/mob/living/basic/guardian/summoned_guardian = new guardian_path(user, guardian_theme) summoned_guardian.set_summoner(user, different_person = TRUE) summoned_guardian.key = candidate.key user.log_message("has summoned [key_name(summoned_guardian)], a [summoned_guardian.creator_name] holoparasite.", LOG_GAME) summoned_guardian.log_message("was summoned as a [summoned_guardian.creator_name] holoparasite.", LOG_GAME) - to_chat(user, summoned_guardian.used_fluff_string) + to_chat(user, guardian_theme.get_fluff_string(summoned_guardian.guardian_type)) to_chat(user, replacetext(success_message, "%GUARDIAN", mob_name)) summoned_guardian.client?.init_verbs() return summoned_guardian -/obj/item/guardiancreator/proc/check_menu(mob/living/user) +/// Checks to ensure we're still capable of using the radial selector +/obj/item/guardian_creator/proc/check_menu(mob/living/user) if(!istype(user)) return FALSE if(user.incapacitated() || !user.is_holding(src) || used) return FALSE return TRUE -/obj/item/guardiancreator/choose - random = FALSE - -/obj/item/guardiancreator/choose/all/Initialize(mapload) - . = ..() - possible_guardians = subtypesof(/mob/living/simple_animal/hostile/guardian) - -/obj/item/guardiancreator/choose/wizard - allowmultiple = TRUE - possible_guardians = list( //no support, but dextrous - /mob/living/simple_animal/hostile/guardian/assassin, - /mob/living/simple_animal/hostile/guardian/charger, - /mob/living/simple_animal/hostile/guardian/dextrous, - /mob/living/simple_animal/hostile/guardian/explosive, - /mob/living/simple_animal/hostile/guardian/gaseous, - /mob/living/simple_animal/hostile/guardian/gravitokinetic, - /mob/living/simple_animal/hostile/guardian/lightning, - /mob/living/simple_animal/hostile/guardian/protector, - /mob/living/simple_animal/hostile/guardian/ranged, - /mob/living/simple_animal/hostile/guardian/standard, +/// Guardian creator available in the wizard spellbook. All but support are available. +/obj/item/guardian_creator/wizard + allow_multiple = TRUE + possible_guardians = list( + /mob/living/basic/guardian/assassin, + /mob/living/basic/guardian/charger, + /mob/living/basic/guardian/dextrous, + /mob/living/basic/guardian/explosive, + /mob/living/basic/guardian/gaseous, + /mob/living/basic/guardian/gravitokinetic, + /mob/living/basic/guardian/lightning, + /mob/living/basic/guardian/protector, + /mob/living/basic/guardian/ranged, + /mob/living/basic/guardian/standard, ) -/obj/item/guardiancreator/choose/wizard/spawn_guardian(mob/living/user, mob/dead/candidate) - . = ..() - var/mob/guardian = . - if(!guardian) - return +/obj/item/guardian_creator/wizard/spawn_guardian(mob/living/user, mob/dead/candidate) + var/mob/guardian = ..() + if(isnull(guardian)) + return null + // Add the wizard team datum var/datum/antagonist/wizard/antag_datum = user.mind.has_antag_datum(/datum/antagonist/wizard) - if(antag_datum) - if(!antag_datum.wiz_team) - antag_datum.create_wiz_team() - guardian.mind.add_antag_datum(/datum/antagonist/wizard_minion, antag_datum.wiz_team) - -/obj/item/guardiancreator/tech + if(isnull(antag_datum)) + return guardian + if(!antag_datum.wiz_team) + antag_datum.create_wiz_team() + guardian.mind.add_antag_datum(/datum/antagonist/wizard_minion, antag_datum.wiz_team) + return guardian + +/// Guardian creator available in the traitor uplink. All but dextrous are available, you can pick which you want, and changelings cannot use it. +/obj/item/guardian_creator/tech name = "holoparasite injector" desc = "It contains an alien nanoswarm of unknown origin. Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, it requires an organic host as a home base and source of fuel." icon = 'icons/obj/medical/syringe.dmi' icon_state = "combat_hypo" theme = GUARDIAN_THEME_TECH - mob_name = "Holoparasite" + allow_changeling = FALSE use_message = span_holoparasite("You start to power on the injector...") used_message = span_holoparasite("The injector has already been used.") failure_message = span_boldholoparasite("...ERROR. BOOT SEQUENCE ABORTED. AI FAILED TO INTIALIZE. PLEASE CONTACT SUPPORT OR TRY AGAIN LATER.") ling_failure = span_boldholoparasite("The holoparasites recoil in horror. They want nothing to do with a creature like you.") success_message = span_holoparasite("%GUARDIAN is now online!") -/obj/item/guardiancreator/tech/choose - random = FALSE - -/obj/item/guardiancreator/tech/choose/all/Initialize(mapload) - . = ..() - possible_guardians = subtypesof(/mob/living/simple_animal/hostile/guardian) - -/obj/item/guardiancreator/tech/choose/traitor - allowling = FALSE - -/obj/item/guardiancreator/carp +/// Guardian creator only spawned by admins, which creates a holographic fish. You can have several of them. +/obj/item/guardian_creator/carp name = "holocarp fishsticks" desc = "Using the power of Carp'sie, you can catch a carp from byond the veil of Carpthulu, and bind it to your fleshy flesh form." icon = 'icons/obj/food/meat.dmi' icon_state = "fishfingers" theme = GUARDIAN_THEME_CARP - mob_name = "Holocarp" use_message = span_holoparasite("You put the fishsticks in your mouth...") used_message = span_holoparasite("Someone's already taken a bite out of these fishsticks! Ew.") failure_message = span_boldholoparasite("You couldn't catch any carp spirits from the seas of Lake Carp. Maybe there are none, maybe you fucked up.") ling_failure = span_boldholoparasite("Carp'sie seems to not have taken you as the chosen one. Maybe it's because of your horrifying origin.") success_message = span_holoparasite("%GUARDIAN has been caught!") - allowmultiple = TRUE + allow_multiple = TRUE -/obj/item/guardiancreator/carp/choose - random = FALSE - -/obj/item/guardiancreator/miner +/// Guardian creator available to miners from chests, very limited selection and randomly assigned. +/obj/item/guardian_creator/miner name = "dusty shard" desc = "Seems to be a very old rock, may have originated from a strange meteor." icon = 'icons/obj/mining_zones/artefacts.dmi' icon_state = "dustyshard" theme = GUARDIAN_THEME_MINER - mob_name = "Power Miner" use_message = span_holoparasite("You pierce your skin with the shard...") used_message = span_holoparasite("This shard seems to have lost all its power...") failure_message = span_boldholoparasite("The shard hasn't reacted at all. Maybe try again later...") ling_failure = span_boldholoparasite("The power of the shard seems to not react with your horrifying, mutated body.") success_message = span_holoparasite("%GUARDIAN has appeared!") - possible_guardians = list( //limited to ones useful on lavaland - /mob/living/simple_animal/hostile/guardian/charger, - /mob/living/simple_animal/hostile/guardian/protector, - /mob/living/simple_animal/hostile/guardian/ranged, - /mob/living/simple_animal/hostile/guardian/standard, - /mob/living/simple_animal/hostile/guardian/support, + random = TRUE + //limited to ones which are plausibly useful on lavaland + possible_guardians = list( + /mob/living/basic/guardian/charger, // A flying mount which can cross chasms + /mob/living/basic/guardian/protector, // Bodyblocks projectiles for you + /mob/living/basic/guardian/ranged, // Shoots the bad guys + /mob/living/basic/guardian/standard, // Can mine walls + /mob/living/basic/guardian/support, // Heals and teleports you ) - -/obj/item/guardiancreator/miner/choose - random = FALSE diff --git a/code/modules/mob/living/basic/guardian/guardian_fluff.dm b/code/modules/mob/living/basic/guardian/guardian_fluff.dm new file mode 100644 index 00000000000000..4ede238921ed30 --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_fluff.dm @@ -0,0 +1,124 @@ +/** + * Defines a theme used by guardian mobs for visuals and some text output + * The default is used for ones created by wizards + */ +/datum/guardian_fluff + /// What name do we apply before one has been selected? + var/name = "Guardian Spirit" + /// Mob description to apply + var/desc = "A mysterious being that stands by its charge, ever vigilant." + /// Are we magical or technological? Mostly just used to pick a surname + var/fluff_type = GUARDIAN_MAGIC + /// What speech bubble do we use? + var/bubble_icon = "guardian" + /// What is our base icon state? + var/icon_state = "magicbase" + /// What is the icon state for our coloured overlay? + var/overlay_state = "magic" + /// Emote used for speaking + var/list/speak_emote = list("hisses") + /// Verb shown to viewers when attacking + var/attack_verb_continuous = "punches" + /// Verb shown to attacker when attacking + var/attack_verb_simple = "punch" + /// Sound played when we attack + var/attack_sound = 'sound/weapons/punch1.ogg' + /// Visible effect when we attack + var/attack_vis_effect = ATTACK_EFFECT_PUNCH + /// An associative list of type of guardian to some kind of descriptive text to show on appearance. + var/guardian_fluff = list( + GUARDIAN_ASSASSIN = "...And draw the Space Ninja, a lethal and invisible assassin.", + GUARDIAN_CHARGER = "...And draw the Hunter, alien master of rapid assault.", + GUARDIAN_DEXTROUS = "...And draw the Monkey, ascendant beast who has learned to use tools.", + GUARDIAN_EXPLOSIVE = "...And draw the Scientist, herald of explosive death.", + GUARDIAN_GASEOUS = "...And draw the Atmospheric Technician, veiled in a purple haze.", + GUARDIAN_GRAVITOKINETIC = "...And draw the Singularity, a terrible, irresistible force..", + GUARDIAN_LIGHTNING = "...And draw the Supermatter, a shockingly lethal font of power.", + GUARDIAN_PROTECTOR = "...And draw the Corgi, a stalwart protector that never leaves the side of its charge.", + GUARDIAN_RANGED = "...And draw the Watcher, impaling its prey from afar.", + GUARDIAN_STANDARD = "...And draw the Assistant, faceless but never to be underestimated.", + GUARDIAN_SUPPORT = "...And draw the Paramedic, arbiter of life and death.", + ) + +/// Applies relevant visual properties to our guardian +/datum/guardian_fluff/proc/apply(mob/living/basic/guardian/guardian) + guardian.name = name + guardian.real_name = name + guardian.bubble_icon = bubble_icon + guardian.icon_living = icon_state + guardian.icon_state = icon_state + + guardian.speak_emote = speak_emote + guardian.attack_verb_continuous = attack_verb_continuous + guardian.attack_verb_simple = attack_verb_simple + guardian.attack_sound = attack_sound + guardian.attack_vis_effect = attack_vis_effect + + guardian.overlay = mutable_appearance(guardian.icon, overlay_state) + +/// Output an appropriate fluff string for our guardian when it is created +/datum/guardian_fluff/proc/get_fluff_string(guardian_type) + return span_holoparasite(guardian_fluff[guardian_type] || "You bring forth a glitching abomination, something which should not be! Please contact a coder about it.") + +/// Used by holoparasites in the Traitor uplink +/datum/guardian_fluff/tech + name = "Holoparasite" + fluff_type = GUARDIAN_TECH + bubble_icon = "holo" + icon_state = "techbase" + overlay_state = "tech" + guardian_fluff = list( + GUARDIAN_ASSASSIN = "Boot sequence complete. Stealth modules loaded. Holoparasite swarm online.", + GUARDIAN_CHARGER = "Boot sequence complete. Overclocking motive engines. Holoparasite swarm online.", + GUARDIAN_DEXTROUS = "Boot sequence complete. Armed combat routines loaded. Holoparasite swarm online.", + GUARDIAN_EXPLOSIVE = "Boot sequence complete. Payload generator online. Holoparasite swarm online.", + GUARDIAN_GASEOUS = "Boot sequence complete. Atmospheric projectors operational. Holoparasite swarm online.", + GUARDIAN_GRAVITOKINETIC = "Boot sequence complete. Gravitic engine spinning up. Holoparasite swarm online.", + GUARDIAN_LIGHTNING = "Boot sequence complete. Tesla projectors charged. Holoparasite swarm online.", + GUARDIAN_PROTECTOR = "Boot sequence complete. Bodyguard routines loaded. Holoparasite swarm online.", + GUARDIAN_RANGED = "Boot sequence complete. Flechette launchers operational. Holoparasite swarm online.", + GUARDIAN_STANDARD = "Boot sequence complete. CQC suite engaged. Holoparasite swarm online.", + GUARDIAN_SUPPORT = "Boot sequence complete. Medical suite active. Holoparasite swarm online.", + ) + +/// Used by powerminers found in necropolis chests +/datum/guardian_fluff/miner + name = "Power Miner" + icon_state = "minerbase" + overlay_state = "miner" + guardian_fluff = list( + GUARDIAN_ASSASSIN = "The shard reveals... Glass, a sharp but fragile ambusher.", + GUARDIAN_CHARGER = "The shard reveals... Titanium, a lightweight, agile fighter.", + GUARDIAN_DEXTROUS = "The shard reveals... Gold, a malleable hoarder of treasure.", + GUARDIAN_EXPLOSIVE = "The shard reveals... Gibtonite, volatile and surprising.", + GUARDIAN_GASEOUS = "The shard reveals... Plasma, the bringer of flame.", + GUARDIAN_GRAVITOKINETIC = "The shard reveals... Bananium, a manipulator of motive forces.", + GUARDIAN_LIGHTNING = "The shard reveals... Iron, a conductive font of lightning.", + GUARDIAN_PROTECTOR = "The shard reveals... Uranium, dense and resistant.", + GUARDIAN_RANGED = "The shard reveals... Diamond, projecting a million sharp edges.", + GUARDIAN_STANDARD = "The shard reveals... Plastitanium, a powerful fighter.", + GUARDIAN_SUPPORT = "The shard reveals... Bluespace, master of relocation.", + ) + +/// Used by holocarp spawned by admins +/datum/guardian_fluff/carp + name = "Holocarp" + fluff_type = GUARDIAN_TECH + desc = "A mysterious fish that swims by its charge, ever fingilant." + icon_state = null // Handled entirely by the overlay + bubble_icon = "holo" + overlay_state = "carp" + speak_emote = list("gnashes") + guardian_fluff = list( + GUARDIAN_ASSASSIN = "CARP CARP CARP! Caught one! It's an assassin carp! Just when you thought it was safe to go back to the water... which is unhelpful, because we're in space.", + GUARDIAN_CHARGER = "CARP CARP CARP! Caught one! It's a charger carp which likes running at people. But it doesn't have any legs...", + GUARDIAN_DEXTROUS = "CARP CARP CARP! You caught one! It's a dextrous carp ready to slap people with a fish, once it picks one up.", + GUARDIAN_EXPLOSIVE = "CARP CARP CARP! Caught one! It's an explosive carp! You two are going to have a blast.", + GUARDIAN_GASEOUS = "CARP CARP CARP! You caught one! It's a gaseous carp, but don't worry it actually smells pretty good!", + GUARDIAN_GRAVITOKINETIC = "CARP CARP CARP! Caught one! It's a gravitokinetic carp! Now do you understand the gravity of the situation?", + GUARDIAN_LIGHTNING = "CARP CARP CARP! Caught one! It's a lightning carp! What a shocking result!", + GUARDIAN_PROTECTOR = "CARP CARP CARP! You caught one! Wait, no... it caught you! The fisher has become the fishy...", + GUARDIAN_RANGED = "CARP CARP CARP! You caught one! It's a ranged carp! It has been collecting glass shards in preparation for this moment.", + GUARDIAN_STANDARD = "CARP CARP CARP! You caught one! This one is a little generic and disappointing... Better punch through some walls to ease the tension.", + GUARDIAN_SUPPORT = "CARP CARP CARP! You caught a support carp! Now it's here, now you're over there!", + ) diff --git a/code/modules/mob/living/basic/guardian/guardian_helpers.dm b/code/modules/mob/living/basic/guardian/guardian_helpers.dm new file mode 100644 index 00000000000000..df50a43e6a099e --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_helpers.dm @@ -0,0 +1,13 @@ +/// Returns a list of all holoparasites that has this mob as a summoner. +/mob/living/proc/get_all_linked_holoparasites() + RETURN_TYPE(/list) + var/list/all_parasites = list() + for(var/mob/living/basic/guardian/stand as anything in GLOB.parasites) + if (stand.summoner != src) + continue + all_parasites += stand + return all_parasites + +/// Returns true if this holoparasite has the same summoner as the passed holoparasite. +/mob/living/basic/guardian/proc/shares_summoner(mob/living/basic/guardian/other_guardian) + return istype(other_guardian) && other_guardian.summoner == summoner diff --git a/code/modules/mob/living/basic/guardian/guardian_types/assassin.dm b/code/modules/mob/living/basic/guardian/guardian_types/assassin.dm new file mode 100644 index 00000000000000..d62b9bcedea77d --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/assassin.dm @@ -0,0 +1,116 @@ +#define CAN_STEALTH_ALERT "can_stealth" + +/** + * Can enter stealth mode to become invisible and deal bonus damage on their next attack, an ambush predator. + */ +/mob/living/basic/guardian/assassin + guardian_type = GUARDIAN_ASSASSIN + melee_damage_lower = 15 + melee_damage_upper = 15 + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" + attack_sound = 'sound/weapons/bladeslice.ogg' + attack_vis_effect = ATTACK_EFFECT_SLASH + sharpness = SHARP_POINTY + damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) + playstyle_string = span_holoparasite("As an assassin type you do medium damage and have no damage resistance, but can enter stealth, massively increasing the damage of your next attack and causing it to ignore armor. Stealth is broken when you attack or take damage.") + creator_name = "Assassin" + creator_desc = "Does medium damage and takes full damage, but can enter stealth, causing its next attack to do massive damage and ignore armor. However, it becomes briefly unable to recall after attacking from stealth." + creator_icon = "assassin" + toggle_button_type = /atom/movable/screen/guardian/toggle_mode/assassin + /// How long to put stealth on cooldown if we are forced out? + var/stealth_cooldown_time = 16 SECONDS + /// Cooldown for the stealth toggle. + COOLDOWN_DECLARE(stealth_cooldown) + +/mob/living/basic/guardian/assassin/Initialize(mapload, datum/guardian_fluff/theme) + . = ..() + show_can_stealth() + RegisterSignal(src, COMSIG_GUARDIAN_ASSASSIN_REVEALED, PROC_REF(on_forced_unstealth)) + +// Toggle stealth +/mob/living/basic/guardian/assassin/toggle_modes() + var/stealthed = has_status_effect(/datum/status_effect/guardian_stealth) + if (stealthed) + to_chat(src, span_bolddanger("You exit stealth.")) + remove_status_effect(/datum/status_effect/guardian_stealth) + show_can_stealth() + return + if (COOLDOWN_FINISHED(src, stealth_cooldown)) + if (!is_deployed()) + to_chat(src, span_bolddanger("You have to be manifested to enter stealth!")) + return + apply_status_effect(/datum/status_effect/guardian_stealth) + clear_alert(CAN_STEALTH_ALERT) + return + to_chat(src, span_bolddanger("You cannot yet enter stealth, wait another [DisplayTimeText(COOLDOWN_TIMELEFT(src, stealth_cooldown))]!")) + +/mob/living/basic/guardian/assassin/get_status_tab_items() + . = ..() + if(!COOLDOWN_FINISHED(src, stealth_cooldown)) + . += "Stealth Cooldown Remaining: [DisplayTimeText(COOLDOWN_TIMELEFT(src, stealth_cooldown))]" + +/// Called when we are removed from stealth involuntarily +/mob/living/basic/guardian/assassin/proc/on_forced_unstealth(mob/living/source) + SIGNAL_HANDLER + visible_message(span_danger("\The [src] suddenly appears!")) + COOLDOWN_START(src, manifest_cooldown, 4 SECONDS) + COOLDOWN_START(src, stealth_cooldown, stealth_cooldown_time) + addtimer(CALLBACK(src, PROC_REF(show_can_stealth)), stealth_cooldown_time) + +/// Displays an alert letting us know that we can enter stealth +/mob/living/basic/guardian/assassin/proc/show_can_stealth() + if(!COOLDOWN_FINISHED(src, stealth_cooldown)) + return + throw_alert(CAN_STEALTH_ALERT, /atom/movable/screen/alert/canstealth) + +/// Status effect which makes us sneakier and do bonus damage +/datum/status_effect/guardian_stealth + id = "guardian_stealth" + alert_type = /atom/movable/screen/alert/status_effect/instealth + /// Damage added in stealth mode. + var/damage_bonus = 35 + /// Our wound bonus when in stealth mode. Allows you to actually cause wounds, unlike normal. + var/stealth_wound_bonus = -20 + +/datum/status_effect/guardian_stealth/on_apply() + new /obj/effect/temp_visual/guardian/phase/out(get_turf(owner)) + owner.melee_damage_lower += damage_bonus + owner.melee_damage_upper += damage_bonus + if (isbasicmob(owner)) + var/mob/living/basic/basic_owner = owner + basic_owner.armour_penetration = 100 + basic_owner.wound_bonus = stealth_wound_bonus + basic_owner.obj_damage = 0 + to_chat(owner, span_bolddanger("You enter stealth, empowering your next attack.")) + animate(owner, alpha = 15, time = 0.5 SECONDS) + + RegisterSignals(owner, list(COMSIG_GUARDIAN_RECALLED, COMSIG_HOSTILE_POST_ATTACKINGTARGET), PROC_REF(forced_exit)) + RegisterSignals(owner, COMSIG_LIVING_ADJUST_STANDARD_DAMAGE_TYPES, PROC_REF(on_health_changed)) + return TRUE + +/datum/status_effect/guardian_stealth/on_remove() + owner.melee_damage_lower -= damage_bonus + owner.melee_damage_upper -= damage_bonus + if (isbasicmob(owner)) + var/mob/living/basic/basic_owner = owner + basic_owner.armour_penetration = initial(basic_owner.armour_penetration) + basic_owner.wound_bonus = initial(basic_owner.wound_bonus) + basic_owner.obj_damage = initial(basic_owner.obj_damage) + animate(owner, alpha = initial(owner.alpha), time = 0.5 SECONDS) + UnregisterSignal(owner, list(COMSIG_GUARDIAN_RECALLED, COMSIG_HOSTILE_POST_ATTACKINGTARGET) + COMSIG_LIVING_ADJUST_STANDARD_DAMAGE_TYPES) + +/// If we take damage, exit the status effect +/datum/status_effect/guardian_stealth/proc/on_health_changed(mob/living/our_mob, type, amount, forced) + SIGNAL_HANDLER + if (amount <= 0) + return + forced_exit() + +/// Forcibly exit the status effect +/datum/status_effect/guardian_stealth/proc/forced_exit() + SIGNAL_HANDLER + SEND_SIGNAL(owner, COMSIG_GUARDIAN_ASSASSIN_REVEALED) + qdel(src) + +#undef CAN_STEALTH_ALERT diff --git a/code/modules/mob/living/basic/guardian/guardian_types/charger.dm b/code/modules/mob/living/basic/guardian/guardian_types/charger.dm new file mode 100644 index 00000000000000..02f839c6a415d8 --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/charger.dm @@ -0,0 +1,69 @@ +/** + * Very fast, has a charging attack, and most importantly can be ridden like a horse. + */ +/mob/living/basic/guardian/charger + guardian_type = GUARDIAN_CHARGER + melee_damage_lower = 15 + melee_damage_upper = 15 + speed = -0.5 + damage_coeff = list(BRUTE = 0.75, BURN = 0.75, TOX = 0.75, CLONE = 0.75, STAMINA = 0, OXY = 0.75) + playstyle_string = span_holoparasite("As a charger type you do medium damage, have light damage resistance, move very fast, can be ridden, and can charge at a location, damaging any target hit and forcing them to drop any items they are holding.") + creator_name = "Charger" + creator_desc = "Moves very fast, does medium damage on attack, can be ridden and can charge at targets, damaging the first target hit and forcing them to drop any items they are holding." + creator_icon = "charger" + +/mob/living/basic/guardian/charger/Initialize(mapload, datum/guardian_fluff/theme) + . = ..() + AddElement(/datum/element/ridable, /datum/component/riding/creature/guardian) + var/datum/action/cooldown/mob_cooldown/charge/basic_charge/guardian/charge = new(src) + charge.Grant(src) + charge.set_click_ability(src) + +/// Guardian charger's charging attack, it knocks items out of people's hands +/datum/action/cooldown/mob_cooldown/charge/basic_charge/guardian + name = "Charge!" + cooldown_time = 4 SECONDS + melee_cooldown_time = 0 SECONDS + button_icon = 'icons/effects/effects.dmi' + button_icon_state = "speed" + background_icon = 'icons/hud/guardian.dmi' + background_icon_state = "base" + charge_delay = 0 + recoil_duration = 0 + charge_damage = 20 + charge_distance = 10 + unset_after_click = FALSE + destroy_objects = FALSE + +/datum/action/cooldown/mob_cooldown/charge/basic_charge/guardian/PreActivate(atom/target) + if (!isguardian(owner)) + return ..() + var/mob/living/basic/guardian/guardian_owner = owner + if (guardian_owner.is_deployed()) + return ..() + return FALSE + +/datum/action/cooldown/mob_cooldown/charge/basic_charge/guardian/do_charge_indicator(atom/charger, atom/charge_target) + playsound(charger, 'sound/items/modsuit/loader_launch.ogg', 75, TRUE) + var/obj/effect/temp_visual/decoy/decoy_flash = new /obj/effect/temp_visual/decoy(charger.loc, charger) + animate(decoy_flash, alpha = 0, color = "#FF0000", transform = matrix() * 2, time = 3) + +/datum/action/cooldown/mob_cooldown/charge/basic_charge/guardian/can_hit_target(atom/movable/source, atom/target) + var/mob/living/living_target = target + if (!istype(living_target)) + return FALSE + var/mob/living/basic/guardian/guardian_owner = owner + if (!istype(guardian_owner)) + return TRUE + if (living_target == guardian_owner.summoner || guardian_owner.shares_summoner(target)) + return FALSE + return TRUE + +/datum/action/cooldown/mob_cooldown/charge/basic_charge/guardian/hit_target(atom/movable/source, mob/living/target, damage_dealt) + if(ishuman(target)) + var/mob/living/carbon/human/hit_human = target + if(hit_human.check_shields(src, charge_damage, name, attack_type = LEAP_ATTACK)) + return + . = ..() + var/mob/living/hit_mob = target + hit_mob.drop_all_held_items() diff --git a/code/modules/mob/living/basic/guardian/guardian_types/dextrous.dm b/code/modules/mob/living/basic/guardian/guardian_types/dextrous.dm new file mode 100644 index 00000000000000..ed54a23771d2a4 --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/dextrous.dm @@ -0,0 +1,100 @@ +/// Dextrous guardians have some of the most powerful abilities of all: hands and pockets +/mob/living/basic/guardian/dextrous + guardian_type = GUARDIAN_DEXTROUS + melee_damage_lower = 10 + melee_damage_upper = 10 + damage_coeff = list(BRUTE = 0.75, BURN = 0.75, TOX = 0.75, CLONE = 0.75, STAMINA = 0, OXY = 0.75) + playstyle_string = span_holoparasite("As a dextrous type you can hold items, store an item within yourself, and have medium damage resistance, but do low damage on attacks. Recalling and leashing will force you to drop unstored items!") + creator_name = "Dextrous" + creator_desc = "Does low damage on attack, but is capable of holding items and storing a single item within it. It will drop items held in its hands when it recalls, but it will retain the stored item." + creator_icon = "dextrous" + hud_type = /datum/hud/dextrous/guardian + held_items = list(null, null) + /// An internal pocket we can put stuff in + var/obj/item/internal_storage + +/mob/living/basic/guardian/dextrous/Initialize(mapload, datum/guardian_fluff/theme) + . = ..() + add_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP), ROUNDSTART_TRAIT) + AddElement(/datum/element/dextrous, hud_type = hud_type) + AddComponent(/datum/component/personal_crafting) + AddComponent(/datum/component/basic_inhands) + +/mob/living/basic/guardian/dextrous/death(gibbed) + dropItemToGround(internal_storage) + return ..() + +/mob/living/basic/guardian/dextrous/examine(mob/user) + . = ..() + if(isnull(internal_storage) || (internal_storage.item_flags & ABSTRACT)) + return + . += span_info("It is holding [internal_storage.get_examine_string(user)] in its internal storage.") + +/mob/living/basic/guardian/dextrous/recall_effects() + . = ..() + drop_all_held_items() + +// Bullshit related to having a fake pocket begins here + +/mob/living/basic/guardian/dextrous/doUnEquip(obj/item/equipped_item, force, newloc, no_move, invdrop = TRUE, silent = FALSE) + . = ..() + if (!.) + return FALSE + update_held_items() + if(equipped_item == internal_storage) + internal_storage = null + update_inv_internal_storage() + return TRUE + +/mob/living/basic/guardian/dextrous/can_equip(mob/living/M, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action = FALSE) + if(slot != ITEM_SLOT_DEX_STORAGE) + return FALSE + return isnull(internal_storage) + +/mob/living/basic/guardian/dextrous/get_item_by_slot(slot_id) + if(slot_id == ITEM_SLOT_DEX_STORAGE) + return internal_storage + return ..() + +/mob/living/basic/guardian/dextrous/get_slot_by_item(obj/item/looking_for) + if(internal_storage == looking_for) + return ITEM_SLOT_DEX_STORAGE + return ..() + +/mob/living/basic/guardian/dextrous/equip_to_slot(obj/item/equipping, slot, initial = FALSE, redraw_mob = FALSE, indirect_action = FALSE) + if (slot != ITEM_SLOT_DEX_STORAGE) + to_chat(src, span_danger("You are trying to equip this item to an unsupported inventory slot. Report this to a coder!")) + return FALSE + + var/index = get_held_index_of_item(equipping) + if(index) + held_items[index] = null + update_held_items() + + if(equipping.pulledby) + equipping.pulledby.stop_pulling() + + equipping.screen_loc = null // will get moved if inventory is visible + equipping.forceMove(src) + SET_PLANE_EXPLICIT(equipping, ABOVE_HUD_PLANE, src) + + internal_storage = equipping + update_inv_internal_storage() + + equipping.on_equipped(src, slot) + return TRUE + +/mob/living/basic/guardian/dextrous/getBackSlot() + return ITEM_SLOT_DEX_STORAGE + +/mob/living/basic/guardian/dextrous/getBeltSlot() + return ITEM_SLOT_DEX_STORAGE + +/mob/living/basic/guardian/dextrous/proc/update_inv_internal_storage() + if(isnull(internal_storage) || isnull(client) || !hud_used?.hud_shown) + return + internal_storage.screen_loc = ui_id + client.screen += internal_storage + +/mob/living/basic/guardian/dextrous/regenerate_icons() + update_inv_internal_storage() diff --git a/code/modules/mob/living/basic/guardian/guardian_types/explosive.dm b/code/modules/mob/living/basic/guardian/guardian_types/explosive.dm new file mode 100644 index 00000000000000..db59c3209d0f98 --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/explosive.dm @@ -0,0 +1,77 @@ +/// A durable guardian which can convert objects into hidden explosives. +/mob/living/basic/guardian/explosive + guardian_type = GUARDIAN_EXPLOSIVE + melee_damage_lower = 15 + melee_damage_upper = 15 + damage_coeff = list(BRUTE = 0.6, BURN = 0.6, TOX = 0.6, CLONE = 0.6, STAMINA = 0, OXY = 0.6) + range = 13 + playstyle_string = span_holoparasite("As an explosive type, you have moderate close combat abilities and are capable of converting nearby items and objects into disguised bombs via right-click.") + creator_name = "Explosive" + creator_desc = "High damage resist and medium power attack. Can turn any object, including objects too large to pick up, into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered or after a delay." + creator_icon = "explosive" + /// Ability which plants bombs + var/datum/action/cooldown/mob_cooldown/explosive_booby_trap/bomb + +/mob/living/basic/guardian/explosive/Initialize(mapload, datum/guardian_fluff/theme) + . = ..() + bomb = new(src) + bomb.Grant(src) + +/mob/living/basic/guardian/explosive/Destroy() + QDEL_NULL(bomb) + return ..() + +/mob/living/basic/guardian/explosive/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) + if(LAZYACCESS(modifiers, RIGHT_CLICK) && proximity_flag && isobj(attack_target)) + bomb.Trigger(target = attack_target) + return + return ..() + + +/// An ability which can turn an object into a bomb +/datum/action/cooldown/mob_cooldown/explosive_booby_trap + name = "Explosive Trap" + desc = "Convert an inanimate object into a deadly and mostly undetectable explosive, triggered on touch." + button_icon = 'icons/mob/actions/actions_spells.dmi' + button_icon_state = "smoke" + cooldown_time = 20 SECONDS + melee_cooldown_time = 0 SECONDS + background_icon = 'icons/hud/guardian.dmi' + background_icon_state = "base" + /// After this amount of time passses, bomb deactivates. + var/decay_time = 1 MINUTES + /// Static list of signals that activate the bomb. + var/static/list/boom_signals = list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_BUMPED, COMSIG_ATOM_ATTACK_HAND) + +/datum/action/cooldown/mob_cooldown/explosive_booby_trap/PreActivate(atom/target) + if (!isobj(target)) + return FALSE + if (!owner.Adjacent(target)) + return FALSE + return ..() + +/datum/action/cooldown/mob_cooldown/explosive_booby_trap/Activate(atom/target) + var/glow_colour = COLOR_RED + var/mob/living/basic/guardian/guardian_owner = owner + if (istype(guardian_owner)) + glow_colour = guardian_owner.guardian_colour + target.AddComponent(\ + /datum/component/direct_explosive_trap, \ + saboteur = owner, \ + expire_time = decay_time, \ + glow_colour = glow_colour,\ + explosive_checks = CALLBACK(src, PROC_REF(validate_target)), \ + triggering_signals = boom_signals, \ + ) + target.balloon_alert(owner, "bomb planted") + StartCooldown() + return TRUE + +/// Validate that we should blow up on this thing, preferably not on one of our allies +/datum/action/cooldown/mob_cooldown/explosive_booby_trap/proc/validate_target(mob/living/target) + if (target == owner) + return FALSE + var/mob/living/basic/guardian/guardian_owner = owner + if (!istype(guardian_owner)) + return TRUE + return target != guardian_owner.summoner && !guardian_owner.shares_summoner(target) diff --git a/code/modules/mob/living/basic/guardian/guardian_types/gaseous.dm b/code/modules/mob/living/basic/guardian/guardian_types/gaseous.dm new file mode 100644 index 00000000000000..6790916be07939 --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/gaseous.dm @@ -0,0 +1,159 @@ +/// Not particularly resistant, but versatile due to the selection of gases it can generate. +/mob/living/basic/guardian/gaseous + guardian_type = GUARDIAN_GASEOUS + melee_damage_lower = 10 + melee_damage_upper = 10 + damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 0) + range = 7 + playstyle_string = span_holoparasite("As a gaseous type, you have only light damage resistance, but you can expel gas in an area. In addition, your punches cause sparks, and you make your summoner inflammable.") + creator_name = "Gaseous" + creator_desc = "Creates sparks on touch and continuously expels a gas of its choice. Automatically extinguishes the user if they catch on fire." + creator_icon = "gaseous" + toggle_button_type = /atom/movable/screen/guardian/toggle_mode/gases + /// Ability we use to select gases + var/datum/action/cooldown/mob_cooldown/expel_gas/gas + /// Rate of temperature stabilization per second. + var/temp_stabilization_rate = 0.1 + +/mob/living/basic/guardian/gaseous/Initialize(mapload, theme) + . = ..() + RegisterSignal(src, COMSIG_ATOM_PRE_PRESSURE_PUSH, PROC_REF(pre_pressure_moved)) + gas = new(src) + gas.owner_has_control = FALSE // It's nicely integrated with the Guardian UI, no need to have two buttons + gas.Grant(src) + +/mob/living/basic/guardian/gaseous/Destroy() + QDEL_NULL(gas) + return ..() + +/mob/living/basic/guardian/gaseous/toggle_modes() + gas.Trigger() + +/mob/living/basic/guardian/gaseous/set_summoner(mob/living/to_who, different_person) + . = ..() + if (QDELETED(src)) + return + RegisterSignal(summoner, COMSIG_LIVING_IGNITED, PROC_REF(on_summoner_ignited)) + RegisterSignal(summoner, COMSIG_LIVING_LIFE, PROC_REF(on_summoner_life)) + +/mob/living/basic/guardian/gaseous/cut_summoner(different_person) + if (!isnull(summoner)) + UnregisterSignal(summoner, list(COMSIG_LIVING_IGNITED, COMSIG_LIVING_LIFE)) + return ..() + +/// Prevent our summoner from being on fire +/mob/living/basic/guardian/gaseous/proc/on_summoner_ignited(mob/living/source) + SIGNAL_HANDLER + source.extinguish_mob() + source.set_fire_stacks(0, remove_wet_stacks = FALSE) + +/// Maintain our summoner at a stable body temperature +/mob/living/basic/guardian/gaseous/proc/on_summoner_life(mob/living/source, seconds_per_tick, times_fired) + SIGNAL_HANDLER + source.adjust_bodytemperature(get_temp_change_amount((summoner.get_body_temp_normal() - summoner.bodytemperature), temp_stabilization_rate * seconds_per_tick)) + +/mob/living/basic/guardian/gaseous/melee_attack(atom/target, list/modifiers, ignore_cooldown) + . = ..() + if(!. || !isliving(target)) + return + do_sparks(1, TRUE, target) + +/mob/living/basic/guardian/gaseous/recall_effects() + . = ..() + if(!isnull(summoner)) + UnregisterSignal(summoner, COMSIG_ATOM_PRE_PRESSURE_PUSH) + +/mob/living/basic/guardian/gaseous/manifest_effects() + . = ..() + if (!isnull(summoner)) + RegisterSignal(summoner, COMSIG_ATOM_PRE_PRESSURE_PUSH, PROC_REF(pre_pressure_moved)) + +/// We stand firm in the face of gas +/mob/living/basic/guardian/gaseous/proc/pre_pressure_moved(datum/source) + SIGNAL_HANDLER + return COMSIG_ATOM_BLOCKS_PRESSURE + + +/// Expel a range of gases +/datum/action/cooldown/mob_cooldown/expel_gas + name = "Release Gas" + desc = "Start or stop expelling a selected gas into the environment." + button_icon = 'icons/mob/actions/actions_spells.dmi' + button_icon_state = "smoke" + cooldown_time = 0 SECONDS // We're here for the interface not the cooldown + melee_cooldown_time = 0 SECONDS + click_to_activate = FALSE + /// Gas being expelled. + var/active_gas = null + /// Associative list of types of gases to moles we create every life tick. + var/static/list/possible_gases = list( + /datum/gas/oxygen = 50, + /datum/gas/nitrogen = 750, //overpressurizing is hard!. + /datum/gas/water_vapor = 1, //you need incredibly little water vapor for the effects to kick in + /datum/gas/nitrous_oxide = 15, + /datum/gas/carbon_dioxide = 50, + /datum/gas/plasma = 3, + /datum/gas/bz = 10, + ) + +/datum/action/cooldown/mob_cooldown/expel_gas/Grant(mob/granted_to) + . = ..() + if (isnull(owner)) + return + RegisterSignal(owner, COMSIG_GUARDIAN_RECALLED, PROC_REF(stop_gas)) + +/datum/action/cooldown/mob_cooldown/expel_gas/Remove(mob/removed_from) + UnregisterSignal(owner, list(COMSIG_GUARDIAN_RECALLED, COMSIG_LIVING_LIFE)) + return ..() + +/datum/action/cooldown/mob_cooldown/expel_gas/Activate(atom/target) + StartCooldown(360 SECONDS) + // Regeneated each time just in case someone fucks with our list + var/list/gas_selection = list("None") + for(var/datum/gas/gas as anything in possible_gases) + gas_selection[initial(gas.name)] = gas + + var/picked_gas = tgui_input_list(owner, "Select a gas to emit.", "Gas Producer", gas_selection) + StartCooldown() + if(picked_gas == "None") + stop_gas() + return + + var/gas_type = gas_selection[picked_gas] + if(isnull(picked_gas) || isnull(gas_type)) + return + + to_chat(owner, span_bolddanger("You start releasing [picked_gas].")) + owner.investigate_log("set their gas type to [picked_gas].", INVESTIGATE_ATMOS) + var/had_gas = !isnull(active_gas) + active_gas = gas_type + if(isnull(owner.particles)) + owner.particles = new /particles/smoke/steam() + owner.particles.position = list(-1, 8, 0) + owner.particles.fadein = 5 + owner.particles.height = 200 + var/datum/gas/chosen_gas = active_gas // Casting it so that we can access gas vars in initial, it's still a typepath + owner.particles.color = initial(chosen_gas.primary_color) + if (!had_gas) + RegisterSignal(owner, COMSIG_LIVING_LIFE, PROC_REF(on_life)) + +/// Turns off the gas +/datum/action/cooldown/mob_cooldown/expel_gas/proc/stop_gas() + SIGNAL_HANDLER + if (!isnull(active_gas)) + to_chat(src, span_notice("You stop releasing gas.")) + active_gas = null + QDEL_NULL(owner.particles) + UnregisterSignal(owner, COMSIG_LIVING_LIFE) + +/// Release gas every life tick while active +/datum/action/cooldown/mob_cooldown/expel_gas/proc/on_life(datum/source, seconds_per_tick, times_fired) + SIGNAL_HANDLER + if (isnull(active_gas)) + return // We shouldn't even be registered at this point but just in case + var/datum/gas_mixture/mix_to_spawn = new() + mix_to_spawn.add_gas(active_gas) + mix_to_spawn.gases[active_gas][MOLES] = possible_gases[active_gas] * seconds_per_tick + mix_to_spawn.temperature = T20C + var/turf/open/our_turf = get_turf(owner) + our_turf.assume_air(mix_to_spawn) diff --git a/code/modules/mob/living/basic/guardian/guardian_types/gravitokinetic.dm b/code/modules/mob/living/basic/guardian/guardian_types/gravitokinetic.dm new file mode 100644 index 00000000000000..a0ad9c8c21b5f9 --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/gravitokinetic.dm @@ -0,0 +1,107 @@ +/// Somewhat durable guardian who can increase gravity in an area +/mob/living/basic/guardian/gravitokinetic + guardian_type = GUARDIAN_GRAVITOKINETIC + melee_damage_lower = 15 + melee_damage_upper = 15 + damage_coeff = list(BRUTE = 0.75, BURN = 0.75, TOX = 0.75, CLONE = 0.75, STAMINA = 0, OXY = 0.75) + playstyle_string = span_holoparasite("As a gravitokinetic type, you can right-click to make the gravity on the ground stronger, and punching applies this effect to a target.") + creator_name = "Gravitokinetic" + creator_desc = "Attacks will apply crushing gravity to the target. Can target the ground as well to slow targets advancing on you, but you are not immune to your own such effects." + creator_icon = "gravitokinetic" + /// Targets we have applied our gravity effects on. + var/list/gravity_targets = list() + /// Distance at which our ability works + var/gravity_power_range = 10 + /// Gravity added on punches. + var/punch_gravity = 5 + /// Gravity added to turfs. + var/turf_gravity = 3 + +/mob/living/basic/guardian/gravitokinetic/Initialize(mapload, datum/guardian_fluff/theme) + . = ..() + AddElement(/datum/element/forced_gravity, 1) + + var/static/list/container_connections = list( + COMSIG_MOVABLE_MOVED = PROC_REF(on_moved), + ) + AddComponent(/datum/component/connect_containers, src, container_connections) + RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + +/mob/living/basic/guardian/gravitokinetic/set_summoner(mob/living/to_who, different_person) + . = ..() + if (!QDELETED(src)) + return + to_who.AddElement(/datum/element/forced_gravity, 1) + +/mob/living/basic/guardian/gravitokinetic/cut_summoner(different_person) + summoner?.RemoveElement(/datum/element/forced_gravity, 1) + return ..() + +/mob/living/basic/guardian/gravitokinetic/death(gibbed) + . = ..() + clear_gravity() + +/mob/living/basic/guardian/gravitokinetic/recall_effects() + . = ..() + if (length(gravity_targets)) + to_chat(src, span_bolddanger("You have released your gravitokinetic powers!")) + clear_gravity() + +/mob/living/basic/guardian/gravitokinetic/melee_attack(atom/target, list/modifiers, ignore_cooldown) + . = ..() + if (!. || !isliving(target) || target == src || target == summoner || shares_summoner(target) || gravity_targets[target]) + return + to_chat(src, span_bolddanger("Your punch has applied heavy gravity to [target]!")) + add_gravity(target, punch_gravity) + to_chat(target, span_userdanger("Everything feels really heavy!")) + return TRUE + +/mob/living/basic/guardian/gravitokinetic/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) + if (LAZYACCESS(modifiers, RIGHT_CLICK) && proximity_flag && !gravity_targets[attack_target]) + slam_turf(attack_target) + return + return ..() + +/// Apply forced gravity to the floor +/mob/living/basic/guardian/gravitokinetic/proc/slam_turf(turf/open/slammed) + if (!isopenturf(slammed) || isgroundlessturf(slammed)) + return + visible_message(span_danger("[src] slams their fist into the [slammed]!"), span_notice("You amplify gravity around the [slammed].")) + do_attack_animation(slammed) + add_gravity(slammed, turf_gravity) + +/// Remove our forced gravity from all targets +/mob/living/basic/guardian/gravitokinetic/proc/clear_gravity() + for(var/gravity_target in gravity_targets) + remove_gravity(gravity_target) + +/// Make something heavier +/mob/living/basic/guardian/gravitokinetic/proc/add_gravity(atom/target, new_gravity = 3) + if (gravity_targets[target]) + return + target.AddElement(/datum/element/forced_gravity, new_gravity) + gravity_targets[target] = new_gravity + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_target_moved)) + playsound(src, 'sound/effects/gravhit.ogg', 100, TRUE) + +/// Stop making something heavier +/mob/living/basic/guardian/gravitokinetic/proc/remove_gravity(atom/target, too_far = FALSE) + if (isnull(gravity_targets[target])) + return + if (too_far) + to_chat(src, span_bolddanger("You are too far away from [target] to amplify gravity's hold on them!")) + UnregisterSignal(target, COMSIG_MOVABLE_MOVED) + target.RemoveElement(/datum/element/forced_gravity, gravity_targets[target]) + gravity_targets -= target + +/// When we or something we are inside move check if we are now too far away +/mob/living/basic/guardian/gravitokinetic/proc/on_moved() + for(var/gravity_target in gravity_targets) + if (get_dist(src, gravity_target) > gravity_power_range) + remove_gravity(gravity_target, too_far = TRUE) + +/// When something we put gravity on moves check if it's too far away +/mob/living/basic/guardian/gravitokinetic/proc/on_target_moved(atom/movable/moving_target, old_loc, dir, forced) + SIGNAL_HANDLER + if (get_dist(src, moving_target) > gravity_power_range) + remove_gravity(moving_target, too_far = TRUE) diff --git a/code/modules/mob/living/basic/guardian/guardian_types/lightning.dm b/code/modules/mob/living/basic/guardian/guardian_types/lightning.dm new file mode 100644 index 00000000000000..e25184372db77f --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/lightning.dm @@ -0,0 +1,95 @@ +/// A reasonably durable guardian linked to you by a chain of lightning, zapping people who get between you +/mob/living/basic/guardian/lightning + guardian_type = GUARDIAN_LIGHTNING + melee_damage_lower = 7 + melee_damage_upper = 7 + attack_verb_continuous = "shocks" + attack_verb_simple = "shock" + melee_damage_type = BURN + attack_sound = 'sound/machines/defib_zap.ogg' + damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7) + range = 7 + playstyle_string = span_holoparasite("As a lightning type, you will apply lightning chains to targets on attack and have a lightning chain to your summoner. Lightning chains will shock anyone near them.") + creator_name = "Lightning" + creator_desc = "Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage." + creator_icon = "lightning" + /// Link between us and our summoner + var/datum/component/summoner_chain + /// Associative list of chained enemies to their chains + var/list/enemy_chains + +/mob/living/basic/guardian/lightning/death(gibbed) + . = ..() + clear_chains() + +/mob/living/basic/guardian/lightning/Destroy() + clear_chains() + return ..() + +/mob/living/basic/guardian/lightning/manifest_effects() + . = ..() + if (isnull(summoner)) + return + summoner_chain = chain_to(summoner, max_range = INFINITY) // Functionally it's actually our leash range but admins might fuck with it + +/mob/living/basic/guardian/lightning/recall_effects() + . = ..() + clear_chains() + +/// Remove all of our chains +/mob/living/basic/guardian/lightning/proc/clear_chains() + QDEL_NULL(summoner_chain) + QDEL_LIST_ASSOC_VAL(enemy_chains) + +/mob/living/basic/guardian/lightning/melee_attack(atom/target, list/modifiers, ignore_cooldown) + . = ..() + if (!. || !validate_target(target) || (target in enemy_chains)) + return + if (length(enemy_chains) == 2) + var/old_target = enemy_chains[1] + var/datum/old_chain = enemy_chains[old_target] + qdel(old_chain) + var/datum/new_chain = chain_to(target) + RegisterSignal(new_chain, COMSIG_QDELETING, PROC_REF(on_chain_deleted)) + LAZYADDASSOC(enemy_chains, target, new_chain) + +/// Create a damaging lightning chain between ourselves and a target +/mob/living/basic/guardian/lightning/proc/chain_to(atom/target, max_range = 7) + var/datum/component/chain = AddComponent(\ + /datum/component/damage_chain, \ + linked_to = target, \ + max_distance = max_range, \ + beam_state = "lightning[rand(1,12)]", \ + beam_type = /obj/effect/ebeam/chain, \ + validate_target = CALLBACK(src, PROC_REF(validate_target)), \ + chain_damage_feedback = CALLBACK(src, PROC_REF(on_chain_zap)), \ + ) + return chain + +/// Handle losing our reference when we delete a chain +/mob/living/basic/guardian/lightning/proc/on_chain_deleted(datum/source) + SIGNAL_HANDLER + for (var/target in enemy_chains) + if (enemy_chains[target] != source) + continue + enemy_chains -= target + return + +/// Confirm whether something is valid to zap with lightning +/mob/living/basic/guardian/lightning/proc/validate_target(atom/target) + return isliving(target) && target != src && target != summoner && !shares_summoner(target) + +/// Called every few zaps by a chain +/mob/living/basic/guardian/lightning/proc/on_chain_zap(mob/living/target) + target.electrocute_act(shock_damage = 0, source = "lightning chain") + target.visible_message( + span_danger("[target] was shocked by the lightning chain!"), + span_userdanger("You are shocked by the lightning chain!"), + span_hear("You hear a heavy electrical crack."), + ) + +/// Beam definition for our lightning chain +/obj/effect/ebeam/chain + name = "lightning chain" + layer = LYING_MOB_LAYER + plane = GAME_PLANE_FOV_HIDDEN diff --git a/code/modules/mob/living/basic/guardian/guardian_types/protector.dm b/code/modules/mob/living/basic/guardian/guardian_types/protector.dm new file mode 100644 index 00000000000000..a0aa34ad17f140 --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/protector.dm @@ -0,0 +1,122 @@ +/// Very durable, and reverses the usual leash dynamic. Can slow down to become extremely durable. +/mob/living/basic/guardian/protector + guardian_type = GUARDIAN_PROTECTOR + melee_damage_lower = 15 + melee_damage_upper = 15 + range = 5 // You want this to be low so you can drag them around + damage_coeff = list(BRUTE = 0.4, BURN = 0.4, TOX = 0.4, CLONE = 0.4, STAMINA = 0, OXY = 0.4) + playstyle_string = span_holoparasite("As a protector type you cause your summoner to leash to you instead of you leashing to them and have two modes; Combat Mode, where you do and take medium damage, and Protection Mode, where you do and take almost no damage, but move slightly slower.") + creator_name = "Protector" + creator_desc = "Causes you to teleport to it when out of range, unlike other parasites. Has two modes; Combat, where it does and takes medium damage, and Protection, where it does and takes almost no damage but moves slightly slower." + creator_icon = "protector" + toggle_button_type = /atom/movable/screen/guardian/toggle_mode + /// Action which toggles our shield + var/datum/action/cooldown/mob_cooldown/protector_shield/shield + +/mob/living/basic/guardian/protector/Initialize(mapload, datum/guardian_fluff/theme) + . = ..() + shield = new(src) + shield.owner_has_control = FALSE // Hide it from the user, it's integrated with guardian UI + shield.Grant(src) + +/mob/living/basic/guardian/protector/Destroy() + QDEL_NULL(shield) + return ..() + +// Invert the order +/mob/living/basic/guardian/protector/leash_to(atom/movable/leashed, atom/movable/leashed_to) + return ..(leashed_to, leashed) + +/mob/living/basic/guardian/protector/unleash() + qdel(summoner?.GetComponent(/datum/component/leash)) + +/mob/living/basic/guardian/protector/toggle_modes() + shield.Trigger() + +/mob/living/basic/guardian/protector/ex_act(severity) + if(severity >= EXPLODE_DEVASTATE) + adjustBruteLoss(400) //if in protector mode, will do 20 damage and not actually necessarily kill the summoner + return TRUE + return ..() + +/// Toggle a status effect which makes you slow but defensive +/datum/action/cooldown/mob_cooldown/protector_shield + name = "Protection Mode" + desc = "Enter a defensive stance which slows you down and reduces your damage, but makes you almost invincible." + button_icon = 'icons/effects/effects.dmi' + button_icon_state = "shield-old" + background_icon = 'icons/hud/guardian.dmi' + background_icon_state = "base" + cooldown_time = 1 SECONDS + click_to_activate = FALSE + +/datum/action/cooldown/mob_cooldown/protector_shield/Activate(mob/living/target) + if (!isliving(target)) + return FALSE + if (target.has_status_effect(/datum/status_effect/protector_shield)) + target.remove_status_effect(/datum/status_effect/protector_shield) + return + target.apply_status_effect(/datum/status_effect/protector_shield) + StartCooldown() + return TRUE + +/// Makes the guardian even more durable, but slower +/datum/status_effect/protector_shield + id = "guardian_shield" + alert_type = null + /// Damage removed in protecting mode. + var/damage_penalty = 13 + /// Colour for our various overlays. + var/overlay_colour = COLOR_TEAL + /// Overlay for our protection shield. + var/mutable_appearance/shield_overlay + /// Damage coefficients when shielded + var/list/shielded_damage = list(BRUTE = 0.05, BURN = 0.05, TOX = 0.05, CLONE = 0.05, STAMINA = 0, OXY = 0.05) + +/datum/status_effect/protector_shield/on_apply() + if (isguardian(owner)) + var/mob/living/basic/guardian/guardian_owner = owner + overlay_colour = guardian_owner.guardian_colour + shield_overlay = mutable_appearance('icons/effects/effects.dmi', "shield-grey") + shield_overlay.color = overlay_colour + + owner.melee_damage_lower -= damage_penalty + owner.melee_damage_upper -= damage_penalty + owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/guardian_shield) + + if (isbasicmob(owner)) // Better hope you are or this status is doing basically nothing useful for you + var/mob/living/basic/basic_owner = owner + basic_owner.damage_coeff = shielded_damage + + to_chat(owner, span_bolddanger("You enter protection mode.")) + RegisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays)) + RegisterSignals(owner, COMSIG_LIVING_ADJUST_STANDARD_DAMAGE_TYPES, PROC_REF(on_health_changed)) + owner.update_appearance(UPDATE_ICON) + return TRUE + +/datum/status_effect/protector_shield/on_remove() + owner.melee_damage_lower += damage_penalty + owner.melee_damage_upper += damage_penalty + owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/guardian_shield) + + if (isbasicmob(owner)) + var/mob/living/basic/basic_owner = owner + basic_owner.damage_coeff = initial(basic_owner.damage_coeff) + + to_chat(owner, span_bolddanger("You return to your normal mode.")) + UnregisterSignal(owner, list(COMSIG_ATOM_UPDATE_OVERLAYS) + COMSIG_LIVING_ADJUST_STANDARD_DAMAGE_TYPES) + owner.update_appearance(UPDATE_ICON) + +/// Show an extra overlay when we're in shield mode +/datum/status_effect/protector_shield/proc/on_update_overlays(atom/source, list/overlays) + SIGNAL_HANDLER + overlays += shield_overlay + +/// Flash an animation when someone tries to hurt us +/datum/status_effect/protector_shield/proc/on_health_changed(mob/living/our_mob, type, amount, forced) + SIGNAL_HANDLER + if (amount <= 0 && !QDELETED(our_mob)) + return + var/image/flash_overlay = new('icons/effects/effects.dmi', owner, "shield-flash", dir = pick(GLOB.cardinals)) + flash_overlay.color = overlay_colour + owner.flick_overlay_view(flash_overlay, 0.5 SECONDS) diff --git a/code/modules/mob/living/basic/guardian/guardian_types/ranged.dm b/code/modules/mob/living/basic/guardian/guardian_types/ranged.dm new file mode 100644 index 00000000000000..293dbfc2320d7c --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/ranged.dm @@ -0,0 +1,205 @@ +/// A ranged guardian can fling shards of glass at people very very quickly. It can also enter a long-range scouting mode. +/mob/living/basic/guardian/ranged + guardian_type = GUARDIAN_RANGED + combat_mode = FALSE + friendly_verb_continuous = "quietly assesses" + friendly_verb_simple = "quietly assess" + melee_damage_lower = 10 + melee_damage_upper = 10 + damage_coeff = list(BRUTE = 0.9, BURN = 0.9, TOX = 0.9, CLONE = 0.9, STAMINA = 0, OXY = 0.9) + range = 13 + playstyle_string = span_holoparasite("As a ranged type, you have only light damage resistance, but are capable of spraying shards of crystal at incredibly high speed. You can also deploy surveillance snares to monitor enemy movement. Finally, you can switch to scout mode, in which you can't attack, but can move without limit.") + creator_name = "Ranged" + creator_desc = "Has two modes. Ranged; which fires a constant stream of weak, armor-ignoring projectiles. Scout; where it cannot attack, but can move through walls and is quite hard to see. Can lay surveillance snares, which alert it when crossed, in either mode." + creator_icon = "ranged" + see_invisible = SEE_INVISIBLE_LIVING + toggle_button_type = /atom/movable/screen/guardian/toggle_mode + +/mob/living/basic/guardian/ranged/Initialize(mapload, datum/guardian_fluff/theme) + . = ..() + AddComponent(\ + /datum/component/ranged_attacks,\ + projectile_type = /obj/projectile/guardian,\ + projectile_sound = 'sound/effects/hit_on_shattered_glass.ogg',\ + cooldown_time = 0.1 SECONDS, \ + ) + AddComponent(/datum/component/ranged_mob_full_auto, autofire_shot_delay = 0.1 SECONDS) + var/datum/action/cooldown/mob_cooldown/guardian_alarm_snare/snare = new (src) + snare.Grant(src) + +/mob/living/basic/guardian/ranged/toggle_modes() + if(is_deployed() && !isnull(summoner)) + balloon_alert(src, "must not be manifested!") + return + if (has_status_effect(/datum/status_effect/guardian_scout_mode)) + remove_status_effect(/datum/status_effect/guardian_scout_mode) + return + apply_status_effect(/datum/status_effect/guardian_scout_mode) + +/mob/living/basic/guardian/ranged/toggle_light() + var/msg + switch(lighting_cutoff) + if (LIGHTING_CUTOFF_VISIBLE) + lighting_cutoff_red = 10 + lighting_cutoff_green = 10 + lighting_cutoff_blue = 15 + msg = "You activate your night vision." + if (LIGHTING_CUTOFF_MEDIUM) + lighting_cutoff_red = 25 + lighting_cutoff_green = 25 + lighting_cutoff_blue = 35 + msg = "You increase your night vision." + if (LIGHTING_CUTOFF_HIGH) + lighting_cutoff_red = 35 + lighting_cutoff_green = 35 + lighting_cutoff_blue = 50 + msg = "You maximize your night vision." + else + lighting_cutoff_red = 0 + lighting_cutoff_green = 0 + lighting_cutoff_blue = 0 + msg = "You deactivate your night vision." + sync_lighting_plane_cutoff() + to_chat(src, span_notice(msg)) + +/// Become an incorporeal scout +/datum/status_effect/guardian_scout_mode + id = "guardian_scout" + alert_type = null + +/datum/status_effect/guardian_scout_mode/on_apply() + animate(owner, alpha = 45, time = 0.5 SECONDS) + RegisterSignal(owner, COMSIG_GUARDIAN_MANIFESTED, PROC_REF(on_manifest)) + RegisterSignal(owner, COMSIG_GUARDIAN_RECALLED, PROC_REF(on_recall)) + RegisterSignal(owner, COMSIG_MOB_CLICKON, PROC_REF(on_click)) + + var/mob/living/basic/guardian/guardian_mob = owner + guardian_mob.unleash() + to_chat(owner, span_bolddanger("You enter scouting mode.")) + return TRUE + +/datum/status_effect/guardian_scout_mode/on_remove() + animate(owner, alpha = initial(owner.alpha), time = 0.5 SECONDS) + UnregisterSignal(owner, list(COMSIG_GUARDIAN_MANIFESTED, COMSIG_GUARDIAN_RECALLED, COMSIG_MOB_CLICKON)) + to_chat(owner, span_bolddanger("You return to your normal mode.")) + var/mob/living/basic/guardian/guardian_mob = owner + guardian_mob.leash_to(owner, guardian_mob.summoner) + +/// Restore incorporeal move when we become corporeal, yes I know that suonds silly +/datum/status_effect/guardian_scout_mode/proc/on_manifest() + SIGNAL_HANDLER + owner.incorporeal_move = INCORPOREAL_MOVE_BASIC + +/// Stop having incorporeal move when we recall so that we can't move +/datum/status_effect/guardian_scout_mode/proc/on_recall() + SIGNAL_HANDLER + owner.incorporeal_move = FALSE + +/// While this is active we can't click anything +/datum/status_effect/guardian_scout_mode/proc/on_click() + SIGNAL_HANDLER + return COMSIG_MOB_CANCEL_CLICKON + + +/// Place an invisible trap which alerts the guardian when it is crossed +/datum/action/cooldown/mob_cooldown/guardian_alarm_snare + name = "Surveillance Snare" + desc = "Place an invisible snare which will alert you when it is crossed." + button_icon = 'icons/mob/actions/actions_ecult.dmi' + button_icon_state = "eye" + background_icon = 'icons/hud/guardian.dmi' + background_icon_state = "base" + cooldown_time = 2 SECONDS + melee_cooldown_time = 0 + click_to_activate = FALSE + /// How many snares can we have? + var/maximum_snares = 5 + /// What snares have we already placed? + var/list/placed_snares = list() + +/datum/action/cooldown/mob_cooldown/guardian_alarm_snare/Activate(atom/target) + StartCooldown(360 SECONDS) + + if (length(placed_snares) >= maximum_snares) + var/picked_snare = tgui_input_list(owner, "Choose a snare to replace.", "Remove Snare", sort_names(placed_snares)) + if(isnull(picked_snare)) + return FALSE + qdel(picked_snare) + if (length(placed_snares) >= maximum_snares) + StartCooldown(0) + return FALSE + + owner.balloon_alert(owner, "snare deployed") // We need feedback because they are invisible + var/turf/snare_loc = get_turf(owner) + var/obj/effect/abstract/surveillance_snare/new_snare = new(snare_loc, owner) + new_snare.assign_owner(owner) + RegisterSignal(new_snare, COMSIG_QDELETING, PROC_REF(on_snare_deleted)) + placed_snares += new_snare + + StartCooldown() + return TRUE + +/// When a snare is deleted remove it from tracking +/datum/action/cooldown/mob_cooldown/guardian_alarm_snare/proc/on_snare_deleted(atom/snare) + SIGNAL_HANDLER + placed_snares -= snare + + +/// An invisible marker placed by a ranged guardian, alerts the owner when crossed +/obj/effect/abstract/surveillance_snare + name = "surveillance snare" + desc = "This thing is invisible, how are you examining it?" + invisibility = INVISIBILITY_ABSTRACT + /// Who do we notify when someone steps on us? + var/mob/living/owner + +/obj/effect/abstract/surveillance_snare/Initialize(mapload, spawning_guardian) + . = ..() + name = "[get_area(src)] snare ([rand(1, 1000)])" + var/static/list/loc_connections = list(COMSIG_ATOM_ENTERED = PROC_REF(on_entered)) + AddElement(/datum/element/connect_loc, loc_connections) + +/// Set up crossed notification +/obj/effect/abstract/surveillance_snare/proc/assign_owner(mob/living/new_owner) + if (isnull(new_owner)) + qdel(src) + return + owner = new_owner + RegisterSignal(owner, COMSIG_QDELETING, PROC_REF(owner_destroyed)) + +/// When crossed notify our owner +/obj/effect/abstract/surveillance_snare/proc/on_entered(atom/source, crossed_object) + SIGNAL_HANDLER + if (isnull(owner)) + qdel(src) + return + if (!isliving(crossed_object) || crossed_object == owner) + return + var/mob/living/basic/guardian/guardian_owner = owner + if (isguardian(owner) && crossed_object == guardian_owner.summoner || guardian_owner.shares_summoner(crossed_object)) + return + + var/send_message = span_bolddanger("[crossed_object] has crossed [name].") + if (!isguardian(owner) || isnull(guardian_owner.summoner)) + to_chat(owner, send_message) + return + + to_chat(guardian_owner.summoner, send_message) + var/list/guardians = guardian_owner.summoner.get_all_linked_holoparasites() + for(var/guardian in guardians) + to_chat(guardian, send_message) + +/// If the person who placed us doesn't exist we might as well die +/obj/effect/abstract/surveillance_snare/proc/owner_destroyed() + SIGNAL_HANDLER + owner = null + qdel(src) + + +/// The glass shards we throw as a guardian. They have low damage because you can fire them very very quickly. +/obj/projectile/guardian + name = "crystal spray" + icon_state = "guardian" + damage = 5 + damage_type = BRUTE + armour_penetration = 100 diff --git a/code/modules/mob/living/basic/guardian/guardian_types/standard.dm b/code/modules/mob/living/basic/guardian/guardian_types/standard.dm new file mode 100644 index 00000000000000..2ca006b385c785 --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/standard.dm @@ -0,0 +1,63 @@ +/// Plain, but durable and strong. Can destroy walls. +/mob/living/basic/guardian/standard + guardian_type = GUARDIAN_STANDARD + damage_coeff = list(BRUTE = 0.5, BURN = 0.5, TOX = 0.5, CLONE = 0.5, STAMINA = 0, OXY = 0.5) + melee_damage_lower = 20 + melee_damage_upper = 20 + melee_attack_cooldown = 0.6 SECONDS + wound_bonus = -5 //you can wound! + obj_damage = 80 + environment_smash = ENVIRONMENT_SMASH_WALLS + playstyle_string = span_holoparasite("As a standard type you have no special abilities, but have a high damage resistance and a powerful attack capable of smashing through walls.") + creator_name = "Standard" + creator_desc = "Devastating close combat attacks and high damage resistance. Can smash through weak walls." + creator_icon = "standard" + /// The text we shout when attacking. + var/battlecry = "AT" + +/mob/living/basic/guardian/standard/Initialize(mapload, datum/guardian_fluff/theme) + . = ..() + AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE, tear_time = 1.5 SECONDS) + var/datum/action/select_guardian_battlecry/cry = new(src) + cry.Grant(src) + +/mob/living/basic/guardian/standard/do_attack_animation(atom/attacked_atom, visual_effect_icon, used_item, no_effect) + . = ..() + if (!isliving(attacked_atom) || !isclosedturf(attacked_atom)) + return + var/msg = "" + for(var/i in 1 to 9) + msg += battlecry + say("[msg]!!", ignore_spam = TRUE) + for(var/sounds in 1 to 4) + addtimer(CALLBACK(src, PROC_REF(do_attack_sound), attacked_atom.loc), sounds DECISECONDS, TIMER_DELETE_ME) + +/// Echo our punching sounds +/mob/living/basic/guardian/standard/proc/do_attack_sound(atom/playing_from) + playsound(playing_from, attack_sound, 50, TRUE, TRUE) + +/// Action to change our battlecry +/datum/action/select_guardian_battlecry + name = "Select Battlecry" + desc = "Update the really cool thing you shout whenever you attack." + button_icon = 'icons/obj/clothing/gloves.dmi' + button_icon_state = "boxing" + background_icon = 'icons/hud/guardian.dmi' + background_icon_state = "base" + /// How long can it be? Shouldn't be too long because we repeat this a shitload of times + var/max_length = 6 + +/datum/action/select_guardian_battlecry/IsAvailable(feedback) + if (!istype(owner, /mob/living/basic/guardian/standard)) + return FALSE + return ..() + +/datum/action/select_guardian_battlecry/Trigger(trigger_flags) + . = ..() + if (!.) + return + var/mob/living/basic/guardian/standard/stand = owner + var/input = tgui_input_text(owner, "What do you want your battlecry to be?", "Battle Cry", max_length = max_length) + if(!input) + return + stand.battlecry = input diff --git a/code/modules/mob/living/basic/guardian/guardian_types/support.dm b/code/modules/mob/living/basic/guardian/guardian_types/support.dm new file mode 100644 index 00000000000000..e22762bcada70f --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_types/support.dm @@ -0,0 +1,164 @@ +/// Quick-moving mob which can teleport things to a beacon and heal its allies +/mob/living/basic/guardian/support + guardian_type = GUARDIAN_SUPPORT + speed = 0 + damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7) + melee_damage_lower = 15 + melee_damage_upper = 15 + playstyle_string = span_holoparasite("As a support type, you may right-click to heal targets. In addition, alt-clicking on an adjacent object or mob will warp them to your bluespace beacon after a short delay.") + creator_name = "Support" + creator_desc = "Does medium damage, but can heal its targets and create beacons to teleport people and things to." + creator_icon = "support" + /// Amount of each damage type to heal per hit + var/healing_amount = 5 + +/mob/living/basic/guardian/support/Initialize(mapload, datum/guardian_fluff/theme) + . = ..() + AddComponent(\ + /datum/component/healing_touch,\ + heal_brute = healing_amount,\ + heal_burn = healing_amount,\ + heal_tox = healing_amount,\ + heal_oxy = healing_amount,\ + heal_time = 0,\ + action_text = "",\ + complete_text = "",\ + required_modifier = RIGHT_CLICK,\ + after_healed = CALLBACK(src, PROC_REF(after_healed)),\ + ) + + var/datum/atom_hud/medsensor = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] + medsensor.show_to(src) + + var/datum/action/cooldown/mob_cooldown/guardian_bluespace_beacon/teleport = new(src) + teleport.Grant(src) + +/mob/living/basic/guardian/support/set_guardian_colour(colour) + . = ..() + AddComponent(/datum/component/healing_touch, heal_color = guardian_colour) + +/// Called after we heal someone, show some visuals +/mob/living/basic/guardian/support/proc/after_healed(mob/living/healed) + do_attack_animation(healed, ATTACK_EFFECT_PUNCH) + healed.visible_message( + message = span_notice("[src] heals [healed]!"), + self_message = span_userdanger("[src] heals you!"), + vision_distance = COMBAT_MESSAGE_RANGE, + ignored_mobs = src, + ) + to_chat(src, span_notice("You heal [healed]!")) + playsound(healed, attack_sound, 50, TRUE, TRUE, frequency = -1) // play punch sound in REVERSE + + +/// Place a beacon and then listen for clicks to teleport people to it +/datum/action/cooldown/mob_cooldown/guardian_bluespace_beacon + name = "Place Bluespace Beacon" + desc = "Mark the ground under your feet as a teleportation point. Alt-click things to teleport them to your beacon." + button_icon = 'icons/effects/effects.dmi' + button_icon_state = "the_freezer" + background_icon = 'icons/hud/guardian.dmi' + background_icon_state = "base" + cooldown_time = 5 MINUTES + melee_cooldown_time = 0 + cooldown_rounding = 1 + click_to_activate = FALSE + /// Our teleportation beacon. + var/obj/structure/guardian_beacon/beacon + /// Time it takes to teleport something. + var/teleport_time = 6 SECONDS + +/datum/action/cooldown/mob_cooldown/guardian_bluespace_beacon/Grant(mob/granted_to) + . = ..() + RegisterSignal(owner, COMSIG_MOB_ALTCLICKON, PROC_REF(try_teleporting)) + +/datum/action/cooldown/mob_cooldown/guardian_bluespace_beacon/Remove(mob/removed_from) + UnregisterSignal(owner, COMSIG_MOB_ALTCLICKON) + return ..() + +/datum/action/cooldown/mob_cooldown/guardian_bluespace_beacon/Activate(atom/movable/target) + var/turf/beacon_loc = owner.loc + if(!isfloorturf(beacon_loc)) + owner.balloon_alert(owner, "no room!") + return FALSE + + if (!isnull(beacon)) + beacon.visible_message("[beacon] vanishes!") + new /obj/effect/temp_visual/guardian/phase/out(beacon.loc) + qdel(beacon) + + beacon = new(beacon_loc, src) + if (isguardian(owner)) + var/mob/living/basic/guardian/guardian_owner = owner + beacon.add_atom_colour(guardian_owner.guardian_colour, FIXED_COLOUR_PRIORITY) + RegisterSignal(beacon, COMSIG_QDELETING, PROC_REF(on_beacon_deleted)) + to_chat(src, span_bolddanger("Beacon placed! You may now warp targets and objects to it, including your user, via Alt+Click.")) + StartCooldown() + return TRUE + +/// Don't hold a reference to a deleted beacon +/datum/action/cooldown/mob_cooldown/guardian_bluespace_beacon/proc/on_beacon_deleted() + SIGNAL_HANDLER + beacon = null + +/// Try and teleport something to our beacon +/datum/action/cooldown/mob_cooldown/guardian_bluespace_beacon/proc/try_teleporting(mob/living/source, atom/target) + SIGNAL_HANDLER + if (!can_teleport(source, target)) + return + INVOKE_ASYNC(src, PROC_REF(perform_teleport), source, target) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/// Validate whether we can teleport this object +/datum/action/cooldown/mob_cooldown/guardian_bluespace_beacon/proc/can_teleport(mob/living/source, atom/movable/target) + if (isnull(beacon)) + source.balloon_alert(source, "no beacon!") + return FALSE + if (isguardian(source)) + var/mob/living/basic/guardian/guardian_mob = source + if (!guardian_mob.is_deployed()) + source.balloon_alert(source, "manifest yourself!") + return FALSE + if (!source.Adjacent(target)) + target.balloon_alert(source, "too far!") + return FALSE + if (target.anchored) + target.balloon_alert(source, "it won't budge!") + return FALSE + if(beacon.z != target.z) + target.balloon_alert(source, "too far from beacon!") + return FALSE + return TRUE + +/// Start teleporting +/datum/action/cooldown/mob_cooldown/guardian_bluespace_beacon/proc/perform_teleport(mob/living/source, atom/target) + source.do_attack_animation(target) + playsound(target, 'sound/weapons/punch1.ogg', 50, TRUE, TRUE, frequency = -1) + source.balloon_alert(source, "teleporting...") + target.visible_message( + span_danger("[target] starts to glow faintly!"), \ + span_userdanger("You start to faintly glow, and you feel strangely weightless!")) + if(!do_after(source, teleport_time, target)) + return + new /obj/effect/temp_visual/guardian/phase/out(target.loc) + if(isliving(target)) + var/mob/living/living_target = target + living_target.flash_act() + target.visible_message( + span_danger("[target] disappears in a flash of light!"), \ + span_userdanger("Your vision is obscured by a flash of light!"), \ + ) + do_teleport(target, beacon, precision = 0, channel = TELEPORT_CHANNEL_BLUESPACE) + new /obj/effect/temp_visual/guardian/phase(get_turf(target)) + + +/// Structure which acts as the landing point for a support guardian's teleportation effects +/obj/structure/guardian_beacon + name = "guardian beacon" + icon = 'icons/turf/floors.dmi' + desc = "A glowing zone which acts as a beacon for teleportation." + icon_state = "light_on-8" + light_range = MINIMUM_USEFUL_LIGHT_RANGE + density = FALSE + anchored = TRUE + plane = FLOOR_PLANE + layer = ABOVE_OPEN_TURF_LAYER diff --git a/code/modules/mob/living/basic/guardian/guardian_verbs.dm b/code/modules/mob/living/basic/guardian/guardian_verbs.dm new file mode 100644 index 00000000000000..02d1fd1ed3ab23 --- /dev/null +++ b/code/modules/mob/living/basic/guardian/guardian_verbs.dm @@ -0,0 +1,187 @@ +/// Pop out into the realm of the living. +/mob/living/basic/guardian/proc/manifest(forced) + if (is_deployed() || isnull(summoner) || isnull(summoner.loc) || istype(summoner.loc, /obj/effect) || (!COOLDOWN_FINISHED(src, manifest_cooldown) && !forced) || locked) + return FALSE + forceMove(summoner.loc) + new /obj/effect/temp_visual/guardian/phase(loc) + COOLDOWN_START(src, manifest_cooldown, 1 SECONDS) + reset_perspective() + manifest_effects() + return TRUE + +/// Go and hide inside your boss. +/mob/living/basic/guardian/proc/recall(forced) + if (!is_deployed() || isnull(summoner) || (!COOLDOWN_FINISHED(src, manifest_cooldown) && !forced) || locked) + return FALSE + new /obj/effect/temp_visual/guardian/phase/out(loc) + recall_effects() + forceMove(summoner) + COOLDOWN_START(src, manifest_cooldown, 1 SECONDS) + return TRUE + +/// Do something when we appear. +/mob/living/basic/guardian/proc/manifest_effects() + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_GUARDIAN_MANIFESTED) + +/// Do something when we vanish. +/mob/living/basic/guardian/proc/recall_effects() + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_GUARDIAN_RECALLED) + +/// Swap to a different mode... if we have one +/mob/living/basic/guardian/proc/toggle_modes() + to_chat(src, span_bolddanger("You don't have another mode!")) + + +/// Turn an internal light on or off. +/mob/living/basic/guardian/proc/toggle_light() + if (!light_on) + to_chat(src, span_notice("You activate your light.")) + set_light_on(TRUE) + else + to_chat(src, span_notice("You deactivate your light.")) + set_light_on(FALSE) + + +/// Prints what type of guardian we are and what we can do. +/mob/living/basic/guardian/verb/check_type() + set name = "Check Guardian Type" + set category = "Guardian" + set desc = "Check what type you are." + to_chat(src, playstyle_string) + + +/// Speak with our boss at a distance +/mob/living/basic/guardian/proc/communicate() + if (isnull(summoner)) + return + var/sender_key = key + var/input = tgui_input_text(src, "Enter a message to tell your summoner", "Guardian") + if (sender_key != key || !input) //guardian got reset, or did not enter anything + return + + var/preliminary_message = span_boldholoparasite("[input]") //apply basic color/bolding + var/my_message = "[span_bolditalic(src.name)]: [preliminary_message]" //add source, color source with the guardian's color + + to_chat(summoner, "[my_message]") + var/list/guardians = summoner.get_all_linked_holoparasites() + for(var/guardian in guardians) + to_chat(guardian, "[my_message]") + for(var/dead_mob in GLOB.dead_mob_list) + var/link = FOLLOW_LINK(dead_mob, src) + to_chat(dead_mob, "[link] [my_message]") + + src.log_talk(input, LOG_SAY, tag="guardian") + + +/// Speak with your guardian(s) at a distance. +/datum/action/cooldown/mob_cooldown/guardian_comms + name = "Guardian Communication" + desc = "Communicate telepathically with your guardian." + button_icon = 'icons/hud/guardian.dmi' + button_icon_state = "communicate" + background_icon = 'icons/hud/guardian.dmi' + background_icon_state = "base" + click_to_activate = FALSE + cooldown_time = 0 SECONDS + melee_cooldown_time = 0 + shared_cooldown = NONE + +/datum/action/cooldown/mob_cooldown/guardian_comms/Activate(atom/target) + StartCooldown(360 SECONDS) + var/input = tgui_input_text(owner, "Enter a message to tell your guardian", "Message") + StartCooldown() + if (!input) + return FALSE + + var/preliminary_message = span_boldholoparasite("[input]") //apply basic color/bolding + var/my_message = span_boldholoparasite("[owner]: [preliminary_message]") //add source, color source with default grey... + + to_chat(owner, "[my_message]") + var/mob/living/living_owner = owner + var/list/guardians = living_owner.get_all_linked_holoparasites() + for(var/mob/living/basic/guardian/guardian as anything in guardians) + to_chat(guardian, "[span_bolditalic(owner.real_name)]: [preliminary_message]" ) + for(var/dead_mob in GLOB.dead_mob_list) + var/link = FOLLOW_LINK(dead_mob, owner) + to_chat(dead_mob, "[link] [my_message]") + owner.log_talk(input, LOG_SAY, tag="guardian") + + return TRUE + + +/// Tell your slacking or distracted guardian to come home. +/datum/action/cooldown/mob_cooldown/recall_guardian + name = "Recall Guardian" + desc = "Forcibly recall your guardian." + button_icon = 'icons/hud/guardian.dmi' + button_icon_state = "recall" + background_icon = 'icons/hud/guardian.dmi' + background_icon_state = "base" + click_to_activate = FALSE + cooldown_time = 0 SECONDS + melee_cooldown_time = 0 + shared_cooldown = NONE + +/datum/action/cooldown/mob_cooldown/recall_guardian/Activate(atom/target) + var/mob/living/living_owner = owner + var/list/guardians = living_owner.get_all_linked_holoparasites() + for(var/mob/living/basic/guardian/guardian in guardians) + guardian.recall() + StartCooldown() + return TRUE + +/// Replace an annoying griefer you were paired up to with a different but probably no less annoying player. +/datum/action/cooldown/mob_cooldown/replace_guardian + name = "Reset Guardian Consciousness" + desc = "Replaces the mind of your guardian with that of a different ghost." + button_icon = 'icons/mob/simple/mob.dmi' + button_icon_state = "ghost" + background_icon = 'icons/hud/guardian.dmi' + background_icon_state = "base" + click_to_activate = FALSE + cooldown_time = 5 SECONDS + melee_cooldown_time = 0 + shared_cooldown = NONE + +/datum/action/cooldown/mob_cooldown/replace_guardian/Activate(atom/target) + StartCooldown(5 MINUTES) + + var/mob/living/living_owner = owner + var/list/guardians = living_owner.get_all_linked_holoparasites() + for(var/mob/living/basic/guardian/resetting_guardian as anything in guardians) + if (!COOLDOWN_FINISHED(resetting_guardian, resetting_cooldown)) + guardians -= resetting_guardian //clear out guardians that are already reset + + if (!length(guardians)) + to_chat(owner, span_holoparasite("You cannot reset [length(guardians) > 1 ? "any of your guardians":"your guardian"] yet.")) + StartCooldown() + return FALSE + + var/mob/living/basic/guardian/chosen_guardian = tgui_input_list(owner, "Pick the guardian you wish to reset", "Guardian Reset", sort_names(guardians)) + if (isnull(chosen_guardian)) + to_chat(owner, span_holoparasite("You decide not to reset [length(guardians) > 1 ? "any of your guardians":"your guardian"].")) + StartCooldown() + return FALSE + + to_chat(owner, span_holoparasite("You attempt to reset [span_bold(chosen_guardian.real_name)]'s personality...")) + var/list/mob/dead/observer/ghost_candidates = poll_ghost_candidates("Do you want to play as [owner.real_name]'s [chosen_guardian.theme.name]?", ROLE_PAI, FALSE, 100) + if (!LAZYLEN(ghost_candidates)) + to_chat(owner, span_holoparasite("Your attempt to reset the personality of \ + [span_bold(chosen_guardian.real_name)] appears to have failed... \ + Looks like you're stuck with it for now.")) + StartCooldown() + return FALSE + + var/mob/dead/observer/candidate = pick(ghost_candidates) + to_chat(chosen_guardian, span_holoparasite("Your user reset you, and your body was taken over by a ghost. Looks like they weren't happy with your performance.")) + to_chat(owner, span_boldholoparasite("The personality of [chosen_guardian.theme.name] has been successfully reset.")) + message_admins("[key_name_admin(candidate)] has taken control of ([ADMIN_LOOKUPFLW(chosen_guardian)])") + chosen_guardian.ghostize(FALSE) + chosen_guardian.key = candidate.key + COOLDOWN_START(chosen_guardian, resetting_cooldown, 5 MINUTES) + chosen_guardian.guardian_rename() //give it a new color and name, to show it's a new person + chosen_guardian.guardian_recolour() + StartCooldown() + return TRUE diff --git a/code/modules/mob/living/basic/health_adjustment.dm b/code/modules/mob/living/basic/health_adjustment.dm index 9644a1a6299057..43352c689c4714 100644 --- a/code/modules/mob/living/basic/health_adjustment.dm +++ b/code/modules/mob/living/basic/health_adjustment.dm @@ -17,6 +17,12 @@ updatehealth() return . - bruteloss +/mob/living/basic/get_damage_mod(damage_type) + var/modifier = ..() + if (damage_type in damage_coeff) + return modifier * damage_coeff[damage_type] + return modifier + /mob/living/basic/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype) if(!can_adjust_brute_loss(amount, forced, required_bodytype)) return 0 diff --git a/code/modules/mob/living/basic/heretic/heretic_summon.dm b/code/modules/mob/living/basic/heretic/_heretic_summon.dm similarity index 100% rename from code/modules/mob/living/basic/heretic/heretic_summon.dm rename to code/modules/mob/living/basic/heretic/_heretic_summon.dm diff --git a/code/modules/mob/living/basic/heretic/ash_spirit.dm b/code/modules/mob/living/basic/heretic/ash_spirit.dm index d12ad5eb8d12fd..fed64db8adcb80 100644 --- a/code/modules/mob/living/basic/heretic/ash_spirit.dm +++ b/code/modules/mob/living/basic/heretic/ash_spirit.dm @@ -20,6 +20,4 @@ /datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash, /datum/action/cooldown/spell/pointed/cleave, ) - for (var/action in actions_to_add) - var/datum/action/cooldown/new_action = new action(src) - new_action.Grant(src) + grant_actions_by_list(actions_to_add) diff --git a/code/modules/mob/living/basic/heretic/flesh_stalker.dm b/code/modules/mob/living/basic/heretic/flesh_stalker.dm index 00fecd2f60804d..c8a3342141ff55 100644 --- a/code/modules/mob/living/basic/heretic/flesh_stalker.dm +++ b/code/modules/mob/living/basic/heretic/flesh_stalker.dm @@ -11,7 +11,7 @@ melee_damage_upper = 20 sight = SEE_MOBS ai_controller = /datum/ai_controller/basic_controller/stalker - /// Associative list of action types we would like to have, and what blackboard key (if any) to put it in + /// Actions to grant on spawn var/static/list/actions_to_add = list( /datum/action/cooldown/spell/emp/eldritch = BB_GENERIC_ACTION, /datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash = null, @@ -21,18 +21,13 @@ /mob/living/basic/heretic_summon/stalker/Initialize(mapload) . = ..() AddComponent(/datum/component/ai_target_timer) - for (var/action_type in actions_to_add) - var/datum/action/new_action = new action_type(src) - new_action.Grant(src) - var/blackboard_key = actions_to_add[action_type] - if (!isnull(blackboard_key)) - ai_controller?.set_blackboard_key(blackboard_key, new_action) + grant_actions_by_list(actions_to_add) /// Changes shape and lies in wait when it has no target, uses EMP and attacks once it does /datum/ai_controller/basic_controller/stalker ai_traits = CAN_ACT_IN_STASIS blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/heretic/maid_in_the_mirror.dm b/code/modules/mob/living/basic/heretic/maid_in_the_mirror.dm index 26eaa9d7ebe86e..b83c4f253f3624 100644 --- a/code/modules/mob/living/basic/heretic/maid_in_the_mirror.dm +++ b/code/modules/mob/living/basic/heretic/maid_in_the_mirror.dm @@ -32,8 +32,7 @@ /obj/item/shard, ) AddElement(/datum/element/death_drops, loot) - var/datum/action/cooldown/spell/jaunt/mirror_walk/jaunt = new (src) - jaunt.Grant(src) + GRANT_ACTION(/datum/action/cooldown/spell/jaunt/mirror_walk) /mob/living/basic/heretic_summon/maid_in_the_mirror/death(gibbed) var/turf/death_turf = get_turf(src) diff --git a/code/modules/mob/living/basic/heretic/raw_prophet.dm b/code/modules/mob/living/basic/heretic/raw_prophet.dm index 1b7015960954a2..f4ed7229a005e5 100644 --- a/code/modules/mob/living/basic/heretic/raw_prophet.dm +++ b/code/modules/mob/living/basic/heretic/raw_prophet.dm @@ -15,8 +15,12 @@ maxHealth = 65 health = 65 sight = SEE_MOBS|SEE_OBJS|SEE_TURFS - /// Some ability we use to make people go blind - var/blind_action_type = /datum/action/cooldown/spell/pointed/blind/eldritch + /// List of innate abilities we have to add. + var/static/list/innate_abilities = list( + /datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash/long = null, + /datum/action/cooldown/spell/list_target/telepathy/eldritch = null, + /datum/action/innate/expand_sight = null, + ) /mob/living/basic/heretic_summon/raw_prophet/Initialize(mapload) . = ..() @@ -39,19 +43,13 @@ unlink_message = on_unlink_message, \ ) - // We don't use these for AI so we can just repeat the same adding process - var/static/list/add_abilities = list( - /datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash/long, - /datum/action/cooldown/spell/list_target/telepathy/eldritch, - /datum/action/innate/expand_sight, - ) - for (var/ability_type in add_abilities) - var/datum/action/new_action = new ability_type(src) - new_action.Grant(src) + grant_actions_by_list(get_innate_abilities()) - var/datum/action/cooldown/blind = new blind_action_type(src) - blind.Grant(src) - ai_controller?.set_blackboard_key(BB_TARGETTED_ACTION, blind) +/// Returns a list of abilities that we should add. +/mob/living/basic/heretic_summon/raw_prophet/proc/get_innate_abilities() + var/list/returnable_list = innate_abilities.Copy() + returnable_list += list(/datum/action/cooldown/spell/pointed/blind/eldritch = BB_TARGETED_ACTION) + return returnable_list /* * Callback for the mind_linker component. @@ -78,12 +76,16 @@ /// NPC variant with a less bullshit ability /mob/living/basic/heretic_summon/raw_prophet/ruins ai_controller = /datum/ai_controller/basic_controller/raw_prophet - blind_action_type = /datum/action/cooldown/mob_cooldown/watcher_gaze + +/mob/living/basic/heretic_summon/raw_prophet/ruins/get_innate_abilities() + var/list/returnable_list = innate_abilities.Copy() + returnable_list += list(/datum/action/cooldown/mob_cooldown/watcher_gaze = BB_TARGETED_ACTION) + return returnable_list /// Walk and attack people, blind them when we can /datum/ai_controller/basic_controller/raw_prophet blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/heretic/rust_walker.dm b/code/modules/mob/living/basic/heretic/rust_walker.dm index 0031ce2388d264..ff56c311f7346d 100644 --- a/code/modules/mob/living/basic/heretic/rust_walker.dm +++ b/code/modules/mob/living/basic/heretic/rust_walker.dm @@ -17,13 +17,12 @@ /mob/living/basic/heretic_summon/rust_walker/Initialize(mapload) . = ..() AddElement(/datum/element/footstep, FOOTSTEP_MOB_RUST) - var/datum/action/cooldown/spell/aoe/rust_conversion/small/conversion = new(src) - conversion.Grant(src) - ai_controller?.set_blackboard_key(BB_GENERIC_ACTION, conversion) - var/datum/action/cooldown/spell/basic_projectile/rust_wave/short/wave = new(src) - wave.Grant(src) - ai_controller?.set_blackboard_key(BB_TARGETTED_ACTION, wave) + var/static/list/grantable_spells = list( + /datum/action/cooldown/spell/aoe/rust_conversion/small = BB_GENERIC_ACTION, + /datum/action/cooldown/spell/basic_projectile/rust_wave/short = BB_TARGETED_ACTION, + ) + grant_actions_by_list(grantable_spells) /mob/living/basic/heretic_summon/rust_walker/setDir(newdir) . = ..() @@ -51,7 +50,7 @@ /// Converts unconverted terrain, sprays pocket sand around /datum/ai_controller/basic_controller/rust_walker blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/heretic/star_gazer.dm b/code/modules/mob/living/basic/heretic/star_gazer.dm index a8af89a7f7177f..f7ab925440d57e 100644 --- a/code/modules/mob/living/basic/heretic/star_gazer.dm +++ b/code/modules/mob/living/basic/heretic/star_gazer.dm @@ -66,7 +66,7 @@ target.apply_status_effect(/datum/status_effect/star_mark) target.apply_damage(damage = 5, damagetype = CLONE) - var/datum/targetting_datum/target_confirmer = ai_controller.blackboard[BB_TARGETTING_DATUM] + var/datum/targeting_strategy/target_confirmer = GET_TARGETING_STRATEGY(ai_controller.blackboard[BB_TARGETING_STRATEGY]) for(var/mob/living/nearby_mob in range(1, src)) if(target == nearby_mob || !target_confirmer?.can_attack(src, nearby_mob)) continue @@ -78,9 +78,9 @@ /datum/ai_controller/basic_controller/star_gazer blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = HARD_CRIT, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends/attack_closed_turfs, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends/attack_closed_turfs, ) ai_movement = /datum/ai_movement/basic_avoidance @@ -104,7 +104,7 @@ can_attack_turfs = TRUE can_attack_dense_objects = TRUE -/datum/pet_command/point_targetting/attack/star_gazer +/datum/pet_command/point_targeting/attack/star_gazer speech_commands = list("attack", "sic", "kill", "slash them") command_feedback = "stares!" pointed_reaction = "stares intensely!" diff --git a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm index 960f875365bfa4..a83953ae1c94d0 100644 --- a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm +++ b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm @@ -28,15 +28,13 @@ /mob/living/basic/mining/ice_demon/Initialize(mapload) . = ..() - var/datum/action/cooldown/mob_cooldown/slippery_ice_floors/ice_floor = new(src) - ice_floor.Grant(src) - ai_controller.set_blackboard_key(BB_DEMON_SLIP_ABILITY, ice_floor) - var/datum/action/cooldown/mob_cooldown/ice_demon_teleport/demon_teleport = new(src) - demon_teleport.Grant(src) - ai_controller.set_blackboard_key(BB_DEMON_TELEPORT_ABILITY, demon_teleport) - var/datum/action/cooldown/spell/conjure/create_afterimages/afterimage = new(src) - afterimage.Grant(src) - ai_controller.set_blackboard_key(BB_DEMON_CLONE_ABILITY, afterimage) + var/static/list/innate_actions = list( + /datum/action/cooldown/mob_cooldown/slippery_ice_floors = BB_DEMON_SLIP_ABILITY, + /datum/action/cooldown/mob_cooldown/ice_demon_teleport = BB_DEMON_TELEPORT_ABILITY, + /datum/action/cooldown/spell/conjure/limit_summons/create_afterimages = BB_DEMON_CLONE_ABILITY, + ) + grant_actions_by_list(innate_actions) + AddComponent(\ /datum/component/ranged_attacks,\ projectile_type = /obj/projectile/temp/ice_demon,\ diff --git a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_abilities.dm b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_abilities.dm index 79c9ee9bd583eb..b143f471138f4b 100644 --- a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_abilities.dm +++ b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_abilities.dm @@ -82,7 +82,7 @@ /obj/effect/temp_visual/slippery_ice/proc/add_slippery_component() AddComponent(/datum/component/slippery, 2 SECONDS) -/datum/action/cooldown/spell/conjure/create_afterimages +/datum/action/cooldown/spell/conjure/limit_summons/create_afterimages name = "Create After Images" button_icon = 'icons/mob/simple/icemoon/icemoon_monsters.dmi' button_icon_state = "ice_demon" @@ -91,27 +91,8 @@ summon_type = list(/mob/living/basic/mining/demon_afterimage) summon_radius = 1 summon_amount = 2 - ///max number of after images - var/max_afterimages = 2 - ///How many clones do we have summoned - var/number_of_afterimages = 0 + max_summons = 2 -/datum/action/cooldown/spell/conjure/create_afterimages/can_cast_spell(feedback = TRUE) +/datum/action/cooldown/spell/conjure/limit_summons/create_afterimages/post_summon(atom/summoned_object, atom/cast_on) . = ..() - if(!.) - return FALSE - if(number_of_afterimages >= max_afterimages) - return FALSE - return TRUE - -/datum/action/cooldown/spell/conjure/create_afterimages/post_summon(atom/summoned_object, atom/cast_on) - var/mob/living/basic/created_copy = summoned_object - created_copy.AddComponent(/datum/component/joint_damage, overlord_mob = owner) - RegisterSignals(created_copy, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH), PROC_REF(delete_copy)) - number_of_afterimages++ - -/datum/action/cooldown/spell/conjure/create_afterimages/proc/delete_copy(mob/source) - SIGNAL_HANDLER - - UnregisterSignal(source, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH)) - number_of_afterimages-- + summoned_object.AddComponent(/datum/component/joint_damage, overlord_mob = owner) diff --git a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_ai.dm b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_ai.dm index 28ddd38324ac61..20bcd8a69a130e 100644 --- a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_ai.dm +++ b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_ai.dm @@ -1,11 +1,10 @@ /datum/ai_controller/basic_controller/ice_demon blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_LIST_SCARY_ITEMS = list( /obj/item/weldingtool, /obj/item/flashlight/flare, ), - BB_MINIMUM_DISTANCE_RANGE = 3, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm index 8fb02ec83df915..768375cfce8a69 100644 --- a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm +++ b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm @@ -40,17 +40,20 @@ /mob/living/basic/mining/ice_whelp/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_NO_GLIDE, INNATE_TRAIT) + AddElement(/datum/element/footstep, FOOTSTEP_MOB_HEAVY) AddComponent(/datum/component/basic_mob_ability_telegraph) AddComponent(/datum/component/basic_mob_attack_telegraph, telegraph_duration = 0.6 SECONDS) - var/datum/action/cooldown/mob_cooldown/fire_breath/ice/flamethrower = new(src) - flamethrower.Grant(src) - ai_controller.set_blackboard_key(BB_WHELP_STRAIGHTLINE_FIRE, flamethrower) - var/datum/action/cooldown/mob_cooldown/fire_breath/ice/cross/wide_flames = new(src) - wide_flames.Grant(src) - ai_controller.set_blackboard_key(BB_WHELP_WIDESPREAD_FIRE, wide_flames) + RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) + var/static/list/innate_actions = list( + /datum/action/cooldown/mob_cooldown/fire_breath/ice = BB_WHELP_STRAIGHTLINE_FIRE, + /datum/action/cooldown/mob_cooldown/fire_breath/ice/cross = BB_WHELP_WIDESPREAD_FIRE, + ) + + grant_actions_by_list(innate_actions) + /mob/living/basic/mining/ice_whelp/proc/pre_attack(mob/living/sculptor, atom/target) SIGNAL_HANDLER diff --git a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm index 2d9715caf37527..725dcc09b5ec98 100644 --- a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm +++ b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm @@ -1,7 +1,7 @@ #define ENRAGE_ADDITION 25 /datum/ai_controller/basic_controller/ice_whelp blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, BB_TARGET_MINIMUM_STAT = HARD_CRIT, BB_WHELP_ENRAGED = 0, ) diff --git a/code/modules/mob/living/basic/jungle/leaper/leaper.dm b/code/modules/mob/living/basic/jungle/leaper/leaper.dm new file mode 100644 index 00000000000000..f3213897f9bdb8 --- /dev/null +++ b/code/modules/mob/living/basic/jungle/leaper/leaper.dm @@ -0,0 +1,100 @@ +/mob/living/basic/leaper + name = "leaper" + desc = "Commonly referred to as 'leapers', the Geron Toad is a massive beast that spits out highly pressurized bubbles containing a unique toxin, knocking down its prey and then crushing it with its girth." + icon = 'icons/mob/simple/jungle/leaper.dmi' + icon_state = "leaper" + icon_living = "leaper" + icon_dead = "leaper_dead" + mob_biotypes = MOB_ORGANIC|MOB_BEAST + + melee_damage_lower = 15 + melee_damage_upper = 20 + maxHealth = 350 + health = 350 + speed = 10 + + pixel_x = -16 + base_pixel_x = -16 + + faction = list(FACTION_JUNGLE) + obj_damage = 30 + + unsuitable_atmos_damage = 0 + minimum_survivable_temperature = 0 + maximum_survivable_temperature = INFINITY + + attack_sound = 'sound/weapons/bladeslice.ogg' + attack_vis_effect = ATTACK_EFFECT_SLASH + status_flags = NONE + lighting_cutoff_red = 5 + lighting_cutoff_green = 20 + lighting_cutoff_blue = 25 + mob_size = MOB_SIZE_LARGE + ai_controller = /datum/ai_controller/basic_controller/leaper + move_resist = MOVE_FORCE_VERY_STRONG + pull_force = MOVE_FORCE_VERY_STRONG + ///appearance when we dead + var/mutable_appearance/dead_overlay + ///appearance when we are alive + var/mutable_appearance/living_overlay + ///list of pet commands we can issue + var/list/pet_commands = list( + /datum/pet_command/idle, + /datum/pet_command/free, + /datum/pet_command/follow, + /datum/pet_command/untargeted_ability/blood_rain, + /datum/pet_command/untargeted_ability/summon_toad, + /datum/pet_command/point_targeting/attack, + /datum/pet_command/point_targeting/use_ability/flop, + /datum/pet_command/point_targeting/use_ability/bubble, + ) + +/mob/living/basic/leaper/Initialize(mapload) + . = ..() + AddElement(\ + /datum/element/change_force_on_death,\ + move_resist = MOVE_RESIST_DEFAULT,\ + pull_force = PULL_FORCE_DEFAULT,\ + ) + AddComponent(/datum/component/obeys_commands, pet_commands) + AddComponent(/datum/component/seethrough_mob) + AddElement(/datum/element/wall_smasher) + AddElement(/datum/element/ridable, component_type = /datum/component/riding/creature/leaper) + AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_HEAVY) + var/datum/action/cooldown/mob_cooldown/blood_rain/volley = new(src) + volley.Grant(src) + ai_controller.set_blackboard_key(BB_LEAPER_VOLLEY, volley) + var/datum/action/cooldown/mob_cooldown/belly_flop/flop = new(src) + flop.Grant(src) + ai_controller.set_blackboard_key(BB_LEAPER_FLOP, flop) + var/datum/action/cooldown/mob_cooldown/projectile_attack/leaper_bubble/bubble = new(src) + bubble.Grant(src) + ai_controller.set_blackboard_key(BB_LEAPER_BUBBLE, bubble) + var/datum/action/cooldown/spell/conjure/limit_summons/create_suicide_toads/toads = new(src) + toads.Grant(src) + ai_controller.set_blackboard_key(BB_LEAPER_SUMMON, toads) + +/mob/living/basic/leaper/proc/set_color_overlay(toad_color) + dead_overlay = mutable_appearance(icon, "[icon_state]_dead_overlay") + dead_overlay.color = toad_color + + living_overlay = mutable_appearance(icon, "[icon_state]_overlay") + living_overlay.color = toad_color + update_appearance(UPDATE_OVERLAYS) + +/mob/living/basic/leaper/update_overlays() + . = ..() + if(stat == DEAD && dead_overlay) + . += dead_overlay + return + + if(living_overlay) + . += living_overlay + +/mob/living/basic/leaper/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE, quickstart = TRUE) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, LEAPING_TRAIT) + return ..() + +/mob/living/basic/leaper/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + . = ..() + REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LEAPING_TRAIT) diff --git a/code/modules/mob/living/basic/jungle/leaper/leaper_abilities.dm b/code/modules/mob/living/basic/jungle/leaper/leaper_abilities.dm new file mode 100644 index 00000000000000..8ff9edd1476042 --- /dev/null +++ b/code/modules/mob/living/basic/jungle/leaper/leaper_abilities.dm @@ -0,0 +1,256 @@ +// fire leaper bubble ability +/datum/action/cooldown/mob_cooldown/projectile_attack/leaper_bubble + name = "Fire Leaper Bubble" + button_icon = 'icons/obj/weapons/guns/projectiles.dmi' + button_icon_state = "leaper" + desc = "Fires a poisonous leaper bubble towards the victim!" + background_icon_state = "bg_revenant" + overlay_icon_state = "bg_revenant_border" + cooldown_time = 7 SECONDS + projectile_type = /obj/projectile/leaper + projectile_sound = 'sound/effects/snap.ogg' + shared_cooldown = NONE + melee_cooldown_time = 0 SECONDS + +// bubble ability objects and effects +/obj/projectile/leaper + name = "leaper bubble" + icon_state = "leaper" + paralyze = 5 SECONDS + damage = 0 + range = 7 + hitsound = 'sound/effects/snap.ogg' + nondirectional_sprite = TRUE + impact_effect_type = /obj/effect/temp_visual/leaper_projectile_impact + +/obj/projectile/leaper/on_hit(atom/target, blocked = 0, pierce_hit) + . = ..() + if (!isliving(target)) + return + var/mob/living/bubbled = target + if(iscarbon(target)) + bubbled.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5) + return + bubbled.apply_damage(30) + +/obj/projectile/leaper/on_range() + new /obj/structure/leaper_bubble(get_turf(src)) + return ..() + +/obj/effect/temp_visual/leaper_projectile_impact + name = "leaper bubble" + icon = 'icons/obj/weapons/guns/projectiles.dmi' + icon_state = "leaper_bubble_pop" + layer = ABOVE_ALL_MOB_LAYER + plane = GAME_PLANE_UPPER_FOV_HIDDEN + duration = 3 SECONDS + +/obj/effect/temp_visual/leaper_projectile_impact/Initialize(mapload) + . = ..() + new /obj/effect/decal/cleanable/leaper_sludge(get_turf(src)) + +/obj/effect/decal/cleanable/leaper_sludge + name = "leaper sludge" + desc = "A small pool of sludge, containing trace amounts of leaper venom." + icon = 'icons/effects/tomatodecal.dmi' + icon_state = "tomato_floor1" + +// bubble ability reagent +/datum/reagent/toxin/leaper_venom + name = "Leaper venom" + description = "A toxin spat out by leapers that, while harmless in small doses, quickly creates a toxic reaction if too much is in the body." + color = "#801E28" // rgb: 128, 30, 40 + toxpwr = 0 + taste_description = "french cuisine" + taste_mult = 1.3 + +/datum/reagent/toxin/leaper_venom/on_mob_life(mob/living/carbon/poisoned_mob, seconds_per_tick, times_fired) + . = ..() + if(volume <= 5) + return + if(poisoned_mob.adjustToxLoss(2.5 * REM * seconds_per_tick, updating_health = FALSE)) + return UPDATE_MOB_HEALTH + +// bubble ability structure +/obj/structure/leaper_bubble + name = "leaper bubble" + desc = "A floating bubble containing leaper venom. The contents are under a surprising amount of pressure." + icon = 'icons/obj/weapons/guns/projectiles.dmi' + icon_state = "leaper" + max_integrity = 10 + density = FALSE + +/obj/structure/leaper_bubble/Initialize(mapload) + . = ..() + AddElement(/datum/element/movetype_handler) + ADD_TRAIT(src, TRAIT_MOVE_FLOATING, LEAPER_BUBBLE_TRAIT) + QDEL_IN(src, 10 SECONDS) + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + +/obj/structure/leaper_bubble/Destroy() + new /obj/effect/temp_visual/leaper_projectile_impact(get_turf(src)) + playsound(src,'sound/effects/snap.ogg', 50, TRUE) + return ..() + +/obj/structure/leaper_bubble/proc/on_entered(datum/source, atom/movable/bubbled) + SIGNAL_HANDLER + if(!isliving(bubbled) || istype(bubbled, /mob/living/basic/leaper)) + return + var/mob/living/bubbled_mob = bubbled + + playsound(src, 'sound/effects/snap.ogg',50, TRUE) + bubbled_mob.Paralyze(5 SECONDS) + if(iscarbon(bubbled_mob)) + bubbled_mob.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5) + else + bubbled_mob.apply_damage(30) + qdel(src) + +// blood rain ability +/datum/action/cooldown/mob_cooldown/blood_rain + name = "Blood Rain" + button_icon = 'icons/effects/effects.dmi' + button_icon_state = "blood_effect_falling" + background_icon_state = "bg_revenant" + overlay_icon_state = "bg_revenant_border" + desc = "Rain down poisonous dropplets of blood!" + cooldown_time = 10 SECONDS + click_to_activate = FALSE + shared_cooldown = NONE + melee_cooldown_time = 0 SECONDS + /// how many droplets we will fire + var/volley_count = 8 + /// time between each droplet launched + var/fire_interval = 0.1 SECONDS + +/datum/action/cooldown/mob_cooldown/blood_rain/Activate(mob/living/firer, atom/target) + var/list/possible_turfs = list() + for(var/turf/possible_turf in oview(5, owner)) + if(possible_turf.is_blocked_turf() || isopenspaceturf(possible_turf) || isspaceturf(possible_turf)) + continue + if(locate(/obj/structure/leaper_bubble) in possible_turf) + continue + possible_turfs += possible_turf + + if(!length(possible_turfs)) + return FALSE + + playsound(owner, 'sound/magic/fireball.ogg', 70, TRUE) + new /obj/effect/temp_visual/blood_drop_rising(get_turf(owner)) + addtimer(CALLBACK(src, PROC_REF(fire_droplets), possible_turfs), 1.5 SECONDS) + StartCooldown() + return TRUE + +/datum/action/cooldown/mob_cooldown/blood_rain/proc/fire_droplets(list/possible_turfs) + var/fire_count = min(volley_count, possible_turfs.len) + for(var/i in 1 to fire_count) + addtimer(CALLBACK(src, PROC_REF(fall_effect), pick_n_take(possible_turfs)), i * fire_interval) + +/datum/action/cooldown/mob_cooldown/blood_rain/proc/fall_effect(turf/selected_turf) + new /obj/effect/temp_visual/blood_drop_falling(selected_turf) + var/obj/effect/temp_visual/falling_shadow = new /obj/effect/temp_visual/shadow_telegraph(selected_turf) + animate(falling_shadow, transform = matrix().Scale(0.1, 0.1), time = falling_shadow.duration) + +// blood rain effects +/obj/effect/temp_visual/blood_drop_rising + name = "leaper bubble" + icon = 'icons/obj/weapons/guns/projectiles.dmi' + icon_state = "leaper" + layer = ABOVE_ALL_MOB_LAYER + plane = GAME_PLANE_UPPER_FOV_HIDDEN + duration = 1 SECONDS + +/obj/effect/temp_visual/blood_drop_rising/Initialize(mapload) + . = ..() + animate(src, pixel_y = base_pixel_y + 150, time = duration) + +/obj/effect/temp_visual/blood_drop_falling + name = "leaper bubble" + icon = 'icons/effects/effects.dmi' + icon_state = "blood_effect_falling" + layer = ABOVE_ALL_MOB_LAYER + plane = GAME_PLANE_UPPER_FOV_HIDDEN + duration = 0.7 SECONDS + pixel_y = 60 + +/obj/effect/temp_visual/blood_drop_falling/Initialize(mapload) + . = ..() + addtimer(CALLBACK(src, PROC_REF(create_blood_structure)), duration) + animate(src, pixel_y = 0, time = duration) + +/obj/effect/temp_visual/blood_drop_falling/proc/create_blood_structure() + playsound(src, 'sound/effects/snap.ogg', 50, TRUE) + new /obj/structure/leaper_bubble(get_turf(src)) + +/obj/effect/temp_visual/shadow_telegraph + name = "shadow" + icon = 'icons/effects/effects.dmi' + icon_state = "shadow_telegraph" + duration = 1.5 SECONDS + + +// flop ability +/datum/action/cooldown/mob_cooldown/belly_flop + name = "Belly Flop" + desc = "Belly flop your enemy!" + cooldown_time = 14 SECONDS + background_icon_state = "bg_revenant" + overlay_icon_state = "bg_revenant_border" + shared_cooldown = NONE + melee_cooldown_time = 0 SECONDS + +/datum/action/cooldown/mob_cooldown/belly_flop/Activate(atom/target) + var/turf/target_turf = get_turf(target) + if(isclosedturf(target_turf) || isspaceturf(target_turf)) + owner.balloon_alert(owner, "base not suitable!") + return FALSE + new /obj/effect/temp_visual/leaper_crush(target_turf) + owner.throw_at(target = target_turf, range = 7, speed = 1, spin = FALSE, callback = CALLBACK(src, PROC_REF(flop_on_turf), target_turf)) + StartCooldown() + return TRUE + +/datum/action/cooldown/mob_cooldown/belly_flop/proc/flop_on_turf(turf/target, original_pixel_y) + playsound(get_turf(owner), 'sound/effects/meteorimpact.ogg', 200, TRUE) + for(var/mob/living/victim in oview(1, owner)) + if(victim in owner.buckled_mobs) + continue + victim.apply_damage(35) + if(QDELETED(victim)) // Some mobs are deleted on death + continue + var/throw_dir = victim.loc == owner.loc ? get_dir(owner, victim) : pick(GLOB.alldirs) + var/throwtarget = get_edge_target_turf(victim, throw_dir) + victim.throw_at(target = throwtarget, range = 3, speed = 1) + victim.visible_message(span_warning("[victim] is thrown clear of [owner]!")) + +// flop ability effects +/obj/effect/temp_visual/leaper_crush + name = "grim tidings" + desc = "Incoming leaper!" + icon = 'icons/effects/96x96.dmi' + icon_state = "lily_pad" + layer = BELOW_MOB_LAYER + plane = GAME_PLANE + SET_BASE_PIXEL(-32, -32) + duration = 3 SECONDS + +// summon toads ability +/datum/action/cooldown/spell/conjure/limit_summons/create_suicide_toads + name = "Summon Suicide Toads" + button_icon = 'icons/mob/simple/animal.dmi' + button_icon_state = "frog_trash" + background_icon_state = "bg_revenant" + overlay_icon_state = "bg_revenant_border" + spell_requirements = NONE + cooldown_time = 30 SECONDS + summon_type = list(/mob/living/basic/frog/frog_suicide) + summon_radius = 2 + summon_amount = 2 + max_summons = 2 + +/datum/action/cooldown/spell/conjure/limit_summons/create_suicide_toads/post_summon(atom/summoned_object, atom/cast_on) + . = ..() + var/mob/living/summoned_toad = summoned_object + summoned_toad.faction = owner.faction ///so they dont attack the leaper or the wizard master diff --git a/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm b/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm new file mode 100644 index 00000000000000..e776117a3a5961 --- /dev/null +++ b/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm @@ -0,0 +1,73 @@ +/datum/ai_controller/basic_controller/leaper + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk/less_walking + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/pet_planning, + /datum/ai_planning_subtree/targeted_mob_ability/pointed_bubble, + /datum/ai_planning_subtree/targeted_mob_ability/flop, + /datum/ai_planning_subtree/targeted_mob_ability/volley, + /datum/ai_planning_subtree/targeted_mob_ability/summon, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/go_for_swim, + ) + +/datum/ai_planning_subtree/targeted_mob_ability/pointed_bubble + ability_key = BB_LEAPER_BUBBLE + finish_planning = FALSE + +/datum/ai_planning_subtree/targeted_mob_ability/flop + ability_key = BB_LEAPER_FLOP + finish_planning = FALSE + +/datum/ai_planning_subtree/targeted_mob_ability/flop/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/atom/current_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + if(isclosedturf(current_target) || isspaceturf(current_target)) + return + return ..() + +/datum/ai_planning_subtree/targeted_mob_ability/volley + ability_key = BB_LEAPER_VOLLEY + finish_planning = FALSE + +/datum/ai_planning_subtree/targeted_mob_ability/summon + ability_key = BB_LEAPER_SUMMON + finish_planning = FALSE + +/datum/pet_command/point_targeting/use_ability/flop + command_name = "Flop" + command_desc = "Command your pet to belly flop your target!" + radial_icon = 'icons/mob/actions/actions_items.dmi' + radial_icon_state = "sniper_zoom" + speech_commands = list("flop", "crush") + pet_ability_key = BB_LEAPER_FLOP + +/datum/pet_command/point_targeting/use_ability/bubble + command_name = "Poison Bubble" + command_desc = "Launch poisonous bubbles at your target!" + radial_icon = 'icons/obj/weapons/guns/projectiles.dmi' + radial_icon_state = "leaper" + speech_commands = list("bubble", "shoot") + pet_ability_key = BB_LEAPER_BUBBLE + +/datum/pet_command/untargeted_ability/blood_rain + command_name = "Blood Rain" + command_desc = "Let it rain poisonous blood!" + radial_icon = 'icons/effects/effects.dmi' + radial_icon_state = "blood_effect_falling" + speech_commands = list("blood", "rain", "volley") + ability_key = BB_LEAPER_VOLLEY + + +/datum/pet_command/untargeted_ability/summon_toad + command_name = "Summon Toads" + command_desc = "Summon crazy suicide frogs!" + radial_icon = 'icons/mob/simple/animal.dmi' + radial_icon_state = "frog_trash" + speech_commands = list("frogs", "bombers") + ability_key = BB_LEAPER_SUMMON diff --git a/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid.dm b/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid.dm index bb109fdde61a8c..3a6ed50db10866 100644 --- a/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid.dm +++ b/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid.dm @@ -36,16 +36,16 @@ /mob/living/basic/mega_arachnid/Initialize(mapload) . = ..() - AddComponent(/datum/component/seethrough_mob) - var/datum/action/cooldown/spell/pointed/projectile/flesh_restraints/restrain = new(src) - var/datum/action/cooldown/mob_cooldown/secrete_acid/acid_spray = new(src) - acid_spray.Grant(src) - restrain.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/mob_cooldown/secrete_acid = BB_ARACHNID_SLIP, + /datum/action/cooldown/spell/pointed/projectile/flesh_restraints = BB_ARACHNID_RESTRAIN, + ) + grant_actions_by_list(innate_actions) + AddElement(/datum/element/swabable, CELL_LINE_TABLE_MEGA_ARACHNID, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) + AddComponent(/datum/component/seethrough_mob) AddComponent(/datum/component/appearance_on_aggro, alpha_on_aggro = 255, alpha_on_deaggro = alpha) AddComponent(/datum/component/tree_climber, climbing_distance = 15) - ai_controller.set_blackboard_key(BB_ARACHNID_RESTRAIN, restrain) - ai_controller.set_blackboard_key(BB_ARACHNID_SLIP, acid_spray) /mob/living/basic/mega_arachnid/Login() . = ..() diff --git a/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid_ai.dm b/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid_ai.dm index 8964ebf837ec18..fa2a86787d861b 100644 --- a/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid_ai.dm +++ b/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid_ai.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/mega_arachnid blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_BASIC_MOB_FLEE_DISTANCE = 5, ) diff --git a/code/modules/mob/living/basic/jungle/seedling/seedling.dm b/code/modules/mob/living/basic/jungle/seedling/seedling.dm index 998f693d6da178..5a958d3ca7c184 100644 --- a/code/modules/mob/living/basic/jungle/seedling/seedling.dm +++ b/code/modules/mob/living/basic/jungle/seedling/seedling.dm @@ -56,12 +56,12 @@ /mob/living/basic/seedling/Initialize(mapload) . = ..() - var/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/seedling/seed_attack = new(src) - seed_attack.Grant(src) - ai_controller.set_blackboard_key(BB_RAPIDSEEDS_ABILITY, seed_attack) - var/datum/action/cooldown/mob_cooldown/solarbeam/beam_attack = new(src) - beam_attack.Grant(src) - ai_controller.set_blackboard_key(BB_SOLARBEAM_ABILITY, beam_attack) + var/static/list/innate_actions = list( + /datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/seedling = BB_RAPIDSEEDS_ABILITY, + /datum/action/cooldown/mob_cooldown/solarbeam = BB_SOLARBEAM_ABILITY, + ) + + grant_actions_by_list(innate_actions) var/petal_color = pick(possible_colors) @@ -77,7 +77,7 @@ petal_dead = mutable_appearance(icon, "[icon_state]_dead_overlay") petal_dead.color = petal_color - AddElement(/datum/element/wall_smasher) + AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE) AddComponent(/datum/component/obeys_commands, seedling_commands) RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) RegisterSignal(src, COMSIG_KB_MOB_DROPITEM_DOWN, PROC_REF(drop_can)) @@ -212,9 +212,9 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targetting/attack, - /datum/pet_command/point_targetting/use_ability/solarbeam, - /datum/pet_command/point_targetting/use_ability/rapidseeds, + /datum/pet_command/point_targeting/attack, + /datum/pet_command/point_targeting/use_ability/solarbeam, + /datum/pet_command/point_targeting/use_ability/rapidseeds, ) //abilities diff --git a/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm b/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm index e3f9fe083a63ad..2ed4811e46f255 100644 --- a/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm +++ b/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm @@ -1,7 +1,7 @@ /datum/ai_controller/basic_controller/seedling blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, BB_WEEDLEVEL_THRESHOLD = 3, BB_WATERLEVEL_THRESHOLD = 90, ) @@ -141,8 +141,8 @@ /datum/ai_controller/basic_controller/seedling/meanie blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, ) planning_subtrees = list( /datum/ai_planning_subtree/pet_planning, @@ -161,7 +161,7 @@ finish_planning = FALSE ///pet commands -/datum/pet_command/point_targetting/use_ability/solarbeam +/datum/pet_command/point_targeting/use_ability/solarbeam command_name = "Launch solarbeam" command_desc = "Command your pet to launch a solarbeam at your target!" radial_icon = 'icons/effects/beam.dmi' @@ -169,7 +169,7 @@ speech_commands = list("beam", "solar") pet_ability_key = BB_SOLARBEAM_ABILITY -/datum/pet_command/point_targetting/use_ability/rapidseeds +/datum/pet_command/point_targeting/use_ability/rapidseeds command_name = "Rapid seeds" command_desc = "Command your pet to launch a volley of seeds at your target!" radial_icon = 'icons/obj/weapons/guns/projectiles.dmi' diff --git a/code/modules/mob/living/basic/jungle/venus_human_trap.dm b/code/modules/mob/living/basic/jungle/venus_human_trap.dm index ac4e5c9db24bc9..b59ec233bd0689 100644 --- a/code/modules/mob/living/basic/jungle/venus_human_trap.dm +++ b/code/modules/mob/living/basic/jungle/venus_human_trap.dm @@ -165,7 +165,7 @@ melee_attack_cooldown = 1.2 SECONDS ai_controller = /datum/ai_controller/basic_controller/human_trap ///how much damage we take out of weeds - var/no_weed_damage = 20 + var/no_weed_damage = 12.5 ///how much do we heal in weeds var/weed_heal = 10 ///if the balloon alert was shown atleast once, reset after healing in weeds @@ -174,14 +174,15 @@ /mob/living/basic/venus_human_trap/Initialize(mapload) . = ..() AddElement(/datum/element/lifesteal, 5) - var/datum/action/cooldown/vine_tangle/tangle = new(src) - tangle.Grant(src) - ai_controller.set_blackboard_key(BB_TARGETTED_ACTION, tangle) + var/static/list/innate_actions = list( + /datum/action/cooldown/vine_tangle = BB_TARGETED_ACTION, + ) + grant_actions_by_list(innate_actions) /mob/living/basic/venus_human_trap/RangedAttack(atom/victim) if(!combat_mode) return - var/datum/action/cooldown/mob_cooldown/tangle_ability = ai_controller.blackboard[BB_TARGETTED_ACTION] + var/datum/action/cooldown/mob_cooldown/tangle_ability = ai_controller.blackboard[BB_TARGETED_ACTION] if(!istype(tangle_ability)) return tangle_ability.Trigger(target = victim) @@ -198,7 +199,7 @@ else if(vines_in_range) alert_shown = FALSE - apply_damage(vines_in_range ? -weed_heal : no_weed_damage, BRUTE) //every life tick take 20 brute if not near vines or heal 10 if near vines, 5 times out of weeds = u ded + adjustBruteLoss(vines_in_range ? -weed_heal : no_weed_damage) //every life tick take 20 damage if not near vines or heal 10 if near vines, 5 times out of weeds = u ded /datum/action/cooldown/vine_tangle name = "Tangle" @@ -254,7 +255,7 @@ /datum/ai_controller/basic_controller/human_trap blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/lavaland/basilisk/basilisk.dm b/code/modules/mob/living/basic/lavaland/basilisk/basilisk.dm index d4fef239bf84f4..90b99a533f9f91 100644 --- a/code/modules/mob/living/basic/lavaland/basilisk/basilisk.dm +++ b/code/modules/mob/living/basic/lavaland/basilisk/basilisk.dm @@ -77,7 +77,7 @@ /datum/ai_controller/basic_controller/basilisk blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_AGGRO_RANGE = 5, ) diff --git a/code/modules/mob/living/basic/lavaland/bileworm/_bileworm.dm b/code/modules/mob/living/basic/lavaland/bileworm/_bileworm.dm index 3d6bc299ccd815..d2e04b60d26a7e 100644 --- a/code/modules/mob/living/basic/lavaland/bileworm/_bileworm.dm +++ b/code/modules/mob/living/basic/lavaland/bileworm/_bileworm.dm @@ -37,8 +37,6 @@ /mob/living/basic/mining/bileworm/Initialize(mapload) . = ..() - //traits and elements - ADD_TRAIT(src, TRAIT_IMMOBILIZED, INNATE_TRAIT) if(ispath(evolve_path)) @@ -47,16 +45,14 @@ //setup mob abilities - var/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/bileworm/spew_bile = new attack_action_path(src) - spew_bile.Grant(src) //well, one of them has to start on infinite cooldown + var/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/bileworm/spew_bile = new(src) + spew_bile.Grant(src) spew_bile.StartCooldownSelf(INFINITY) - var/datum/action/cooldown/mob_cooldown/resurface/resurface = new(src) - resurface.Grant(src) - var/datum/action/cooldown/mob_cooldown/devour/devour = new(src) - devour.Grant(src) - var/datum/action/adjust_vision/bileworm/adjust_vision = new(src) - adjust_vision.Grant(src) - ai_controller.set_blackboard_key(BB_BILEWORM_SPEW_BILE, spew_bile) - ai_controller.set_blackboard_key(BB_BILEWORM_RESURFACE, resurface) - ai_controller.set_blackboard_key(BB_BILEWORM_DEVOUR, devour) + ai_controller?.set_blackboard_key(BB_BILEWORM_SPEW_BILE, spew_bile) + + var/static/list/other_innate_actions = list( + /datum/action/adjust_vision/bileworm = null, + /datum/action/cooldown/mob_cooldown/devour = BB_BILEWORM_DEVOUR, + /datum/action/cooldown/mob_cooldown/resurface = BB_BILEWORM_RESURFACE, + ) diff --git a/code/modules/mob/living/basic/lavaland/bileworm/bileworm_ai.dm b/code/modules/mob/living/basic/lavaland/bileworm/bileworm_ai.dm index 0093e69220c172..ea979febff3e34 100644 --- a/code/modules/mob/living/basic/lavaland/bileworm/bileworm_ai.dm +++ b/code/modules/mob/living/basic/lavaland/bileworm/bileworm_ai.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/bileworm blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/bileworm(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/bileworm, ) planning_subtrees = list( @@ -9,7 +9,7 @@ /datum/ai_planning_subtree/bileworm_execute, ) -/datum/targetting_datum/basic/bileworm +/datum/targeting_strategy/basic/bileworm ignore_sight = TRUE /datum/ai_planning_subtree/bileworm_attack diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon.dm index 2c22977d9c6372..9a88c636cf511c 100644 --- a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon.dm +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon.dm @@ -41,11 +41,7 @@ AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) beam = new(src) beam.Grant(src) - ai_controller.set_blackboard_key(BB_TARGETTED_ACTION, beam) - -/mob/living/basic/mining/brimdemon/Destroy() - QDEL_NULL(beam) - return ..() + ai_controller.set_blackboard_key(BB_TARGETED_ACTION, beam) /mob/living/basic/mining/brimdemon/RangedAttack(atom/target, modifiers) beam.Trigger(target = target) diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm index 18f614359c066b..fe209387e008b0 100644 --- a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm @@ -3,7 +3,7 @@ */ /datum/ai_controller/basic_controller/brimdemon blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = HARD_CRIT, ) @@ -28,7 +28,7 @@ if (!succeeded) return var/mob/living/target = controller.blackboard[target_key] - var/datum/action/cooldown/ability = controller.blackboard[BB_TARGETTED_ACTION] + var/datum/action/cooldown/ability = controller.blackboard[BB_TARGETED_ACTION] if(!ability?.IsAvailable()) return ability.InterceptClickOn(caller = controller.pawn, target = target) diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm index fe1cc00110134f..79bfc160804d9e 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm @@ -36,7 +36,7 @@ /datum/pet_command/free, /datum/pet_command/grub_spit, /datum/pet_command/follow, - /datum/pet_command/point_targetting/fetch, + /datum/pet_command/point_targeting/fetch, ) /mob/living/basic/mining/goldgrub/Initialize(mapload) @@ -47,13 +47,11 @@ else can_lay_eggs = FALSE - var/datum/action/cooldown/mob_cooldown/spit_ore/spit = new(src) - var/datum/action/cooldown/mob_cooldown/burrow/burrow = new(src) - spit.Grant(src) - burrow.Grant(src) - ai_controller.set_blackboard_key(BB_SPIT_ABILITY, spit) - ai_controller.set_blackboard_key(BB_BURROW_ABILITY, burrow) - AddElement(/datum/element/wall_smasher) + var/static/list/innate_actions = list( + /datum/action/cooldown/mob_cooldown/spit_ore = BB_SPIT_ABILITY, + /datum/action/cooldown/mob_cooldown/burrow = BB_BURROW_ABILITY, + ) + grant_actions_by_list(innate_actions) AddComponent(/datum/component/ai_listen_to_weather) AddComponent(\ /datum/component/appearance_on_aggro,\ diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm index 7e7a72ec412063..53054052e58af3 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm @@ -1,7 +1,7 @@ /datum/ai_controller/basic_controller/goldgrub blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, BB_ORE_IGNORE_TYPES = list(/obj/item/stack/ore/iron, /obj/item/stack/ore/glass), BB_STORM_APPROACHING = FALSE, ) @@ -20,7 +20,7 @@ /datum/ai_controller/basic_controller/babygrub blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_ORE_IGNORE_TYPES = list(/obj/item/stack/ore/glass), BB_FIND_MOM_TYPES = list(/mob/living/basic/mining/goldgrub), BB_IGNORE_MOM_TYPES = list(/mob/living/basic/mining/goldgrub/baby), diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath.dm index 6f57e1dec67ddb..f8064c32569ddf 100644 --- a/code/modules/mob/living/basic/lavaland/goliath/goliath.dm +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath.dm @@ -44,6 +44,8 @@ COOLDOWN_DECLARE(ability_animation_cooldown) /// Our base tentacles ability var/datum/action/cooldown/mob_cooldown/goliath_tentacles/tentacles + /// Our melee tentacles ability + var/datum/action/cooldown/mob_cooldown/tentacle_burst/melee_tentacles /// Our long-ranged tentacles ability var/datum/action/cooldown/mob_cooldown/tentacle_grasp/tentacle_line /// Things we want to eat off the floor (or a plate, we're not picky) @@ -76,24 +78,18 @@ tentacles = new (src) tentacles.Grant(src) - var/datum/action/cooldown/mob_cooldown/tentacle_burst/melee_tentacles = new (src) + melee_tentacles = new(src) melee_tentacles.Grant(src) - AddComponent(/datum/component/revenge_ability, melee_tentacles, targetting = ai_controller.blackboard[BB_TARGETTING_DATUM], max_range = 1, target_self = TRUE) + AddComponent(/datum/component/revenge_ability, melee_tentacles, targeting = GET_TARGETING_STRATEGY(ai_controller.blackboard[BB_TARGETING_STRATEGY]), max_range = 1, target_self = TRUE) tentacle_line = new (src) tentacle_line.Grant(src) - AddComponent(/datum/component/revenge_ability, tentacle_line, targetting = ai_controller.blackboard[BB_TARGETTING_DATUM], min_range = 2, max_range = 9) + AddComponent(/datum/component/revenge_ability, tentacle_line, targeting = GET_TARGETING_STRATEGY(ai_controller.blackboard[BB_TARGETING_STRATEGY]), min_range = 2, max_range = 9) tentacles_ready() RegisterSignal(src, COMSIG_MOB_ABILITY_FINISHED, PROC_REF(used_ability)) ai_controller.set_blackboard_key(BB_BASIC_FOODS, goliath_foods) ai_controller.set_blackboard_key(BB_GOLIATH_TENTACLES, tentacles) - -/mob/living/basic/mining/goliath/Destroy() - QDEL_NULL(tentacles) - QDEL_NULL(tentacle_line) - return ..() - /mob/living/basic/mining/goliath/examine(mob/user) . = ..() if (saddled) diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath_actions.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath_actions.dm index b484afa0cea360..31eecc03629067 100644 --- a/code/modules/mob/living/basic/lavaland/goliath/goliath_actions.dm +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath_actions.dm @@ -1,7 +1,7 @@ /// Place some grappling tentacles underfoot /datum/action/cooldown/mob_cooldown/goliath_tentacles name = "Unleash Tentacles" - desc = "Unleash burrowed tentacles at a targetted location, grappling targets after a delay." + desc = "Unleash burrowed tentacles at a targeted location, grappling targets after a delay." button_icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' button_icon_state = "goliath_tentacle_wiggle" background_icon_state = "bg_demon" @@ -59,7 +59,7 @@ /// Summon a line of tentacles towards the target /datum/action/cooldown/mob_cooldown/tentacle_grasp name = "Tentacle Grasp" - desc = "Unleash burrowed tentacles in a line towards a targetted location, grappling targets after a delay." + desc = "Unleash burrowed tentacles in a line towards a targeted location, grappling targets after a delay." button_icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' button_icon_state = "goliath_tentacle_wiggle" background_icon_state = "bg_demon" diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm index 48f0e213e73fbf..76c230520df349 100644 --- a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm @@ -3,7 +3,7 @@ /datum/ai_controller/basic_controller/goliath blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, BB_TARGET_MINIMUM_STAT = HARD_CRIT, ) @@ -27,7 +27,7 @@ /// Go for the tentacles if they're available /datum/ai_behavior/basic_melee_attack/goliath -/datum/ai_behavior/basic_melee_attack/goliath/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, health_ratio_key) +/datum/ai_behavior/basic_melee_attack/goliath/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key, health_ratio_key) var/time_on_target = controller.blackboard[BB_BASIC_MOB_HAS_TARGET_TIME] || 0 if (time_on_target < MIN_TIME_TO_TENTACLE) return ..() diff --git a/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm b/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm index 11043e58d11ead..7b1e461991ce78 100644 --- a/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm +++ b/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm @@ -36,7 +36,7 @@ AddComponent(/datum/component/appearance_on_aggro, aggro_state = "hivelord_alert") spawn_brood = new(src) spawn_brood.Grant(src) - ai_controller.set_blackboard_key(BB_TARGETTED_ACTION, spawn_brood) + ai_controller.set_blackboard_key(BB_TARGETED_ACTION, spawn_brood) /mob/living/basic/mining/hivelord/Destroy() QDEL_NULL(spawn_brood) diff --git a/code/modules/mob/living/basic/lavaland/hivelord/hivelord_ai.dm b/code/modules/mob/living/basic/lavaland/hivelord/hivelord_ai.dm index fd7983de3977c1..1fb05cd7a012b9 100644 --- a/code/modules/mob/living/basic/lavaland/hivelord/hivelord_ai.dm +++ b/code/modules/mob/living/basic/lavaland/hivelord/hivelord_ai.dm @@ -1,7 +1,7 @@ /// Basically just keep away and shit out worms /datum/ai_controller/basic_controller/hivelord blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_AGGRO_RANGE = 5, // Only get mad at people nearby ) diff --git a/code/modules/mob/living/basic/lavaland/hivelord/spawn_hivelord_brood.dm b/code/modules/mob/living/basic/lavaland/hivelord/spawn_hivelord_brood.dm index 63a66d4c4e3261..7d50806e63a0cf 100644 --- a/code/modules/mob/living/basic/lavaland/hivelord/spawn_hivelord_brood.dm +++ b/code/modules/mob/living/basic/lavaland/hivelord/spawn_hivelord_brood.dm @@ -10,7 +10,7 @@ cooldown_time = 2 SECONDS melee_cooldown_time = 0 shared_cooldown = NONE - /// If a mob is not clicked directly, inherit targetting data from this blackboard key and setting it upon this target key + /// If a mob is not clicked directly, inherit targeting data from this blackboard key and setting it upon this target key var/ai_target_key = BB_BASIC_MOB_CURRENT_TARGET /// What are we actually spawning? var/spawn_type = /mob/living/basic/hivelord_brood diff --git a/code/modules/mob/living/basic/lavaland/legion/legion.dm b/code/modules/mob/living/basic/lavaland/legion/legion.dm index 7c6bd0fd170a74..b64c3b257a01e3 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion.dm @@ -41,7 +41,7 @@ var/datum/action/cooldown/mob_cooldown/skull_launcher/skull_launcher = new(src) skull_launcher.Grant(src) skull_launcher.spawn_type = brood_type - ai_controller.blackboard[BB_TARGETTED_ACTION] = skull_launcher + ai_controller.set_blackboard_key(BB_TARGETED_ACTION, skull_launcher) /// Create what we want to drop on death, in proc form so we can always return a static list /mob/living/basic/mining/legion/proc/get_loot_list() diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_ai.dm b/code/modules/mob/living/basic/lavaland/legion/legion_ai.dm index 9167846b6853e8..1bae1b30353793 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion_ai.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion_ai.dm @@ -1,7 +1,7 @@ /// Keep away and launch skulls at every opportunity, prioritising injured allies /datum/ai_controller/basic_controller/legion blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/legion, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/legion, BB_TARGET_MINIMUM_STAT = HARD_CRIT, BB_AGGRO_RANGE = 5, // Unobservant BB_BASIC_MOB_FLEE_DISTANCE = 6, @@ -16,10 +16,10 @@ /datum/ai_planning_subtree/flee_target/legion, ) -/// Chase and attack whatever we are targetting, if it's friendly we will heal them +/// Chase and attack whatever we are targeting, if it's friendly we will heal them /datum/ai_controller/basic_controller/legion_brood blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/legion, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/legion, BB_TARGET_MINIMUM_STAT = HARD_CRIT, ) @@ -31,9 +31,9 @@ ) /// Target nearby friendlies if they are hurt (and are not themselves Legions) -/datum/targetting_datum/basic/legion +/datum/targeting_strategy/basic/legion -/datum/targetting_datum/basic/legion/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) +/datum/targeting_strategy/basic/legion/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) if (!living_mob.faction_check_atom(the_target, exact_match = check_factions_exactly)) return FALSE if (istype(the_target, living_mob.type)) diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm index 7ce568d5760892..797426058a1ace 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm @@ -57,7 +57,7 @@ return return ..() -/// Turn the targetted mob into one of us +/// Turn the targeted mob into one of us /mob/living/basic/legion_brood/proc/infest(mob/living/target) visible_message(span_warning("[name] burrows into the flesh of [target]!")) var/spawn_type = get_legion_type(target) diff --git a/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm b/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm index f68c5f7fafe03f..bd9b2c2aff99f5 100644 --- a/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm +++ b/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm @@ -10,7 +10,7 @@ cooldown_time = 2 SECONDS melee_cooldown_time = 0 shared_cooldown = NONE - /// If a mob is not clicked directly, inherit targetting data from this blackboard key and setting it upon this target key + /// If a mob is not clicked directly, inherit targeting data from this blackboard key and setting it upon this target key var/ai_target_key = BB_BASIC_MOB_CURRENT_TARGET /// What are we actually spawning? var/spawn_type = /mob/living/basic/legion_brood diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index a048fe77ab146a..ef6d846970d20f 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm @@ -44,7 +44,7 @@ ) charge = new(src) charge.Grant(src) - ai_controller.set_blackboard_key(BB_TARGETTED_ACTION, charge) + ai_controller.set_blackboard_key(BB_TARGETED_ACTION, charge) /mob/living/basic/mining/lobstrosity/Destroy() QDEL_NULL(charge) @@ -69,7 +69,7 @@ /datum/action/cooldown/mob_cooldown/charge/basic_charge/lobster/hit_target(atom/movable/source, atom/target, damage_dealt) . = ..() - if(!isliving(target) || !isbasicmob(source)) + if(!isbasicmob(source)) return var/mob/living/basic/basic_source = source var/mob/living/living_target = target diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm index c89cc3b9c07b76..b80d5d6b9f79a6 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/lobstrosity blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = HARD_CRIT, BB_LOBSTROSITY_EXPLOIT_TRAITS = list(TRAIT_INCAPACITATED, TRAIT_FLOORED, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT), BB_LOBSTROSITY_FINGER_LUST = 0 @@ -34,7 +34,7 @@ /datum/ai_behavior/basic_melee_attack/lobster -/datum/ai_behavior/basic_melee_attack/lobster/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/basic_melee_attack/lobster/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) var/mob/living/target = controller.blackboard[target_key] if (isnull(target)) return ..() @@ -55,7 +55,7 @@ flee_behaviour = /datum/ai_behavior/run_away_from_target/lobster /datum/ai_planning_subtree/flee_target/lobster/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/datum/action/cooldown/using_action = controller.blackboard[BB_TARGETTED_ACTION] + var/datum/action/cooldown/using_action = controller.blackboard[BB_TARGETED_ACTION] if (using_action?.IsAvailable()) return return ..() diff --git a/code/modules/mob/living/basic/lavaland/mook/mook.dm b/code/modules/mob/living/basic/lavaland/mook/mook.dm index d36973cff033af..93e2806932105d 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook.dm @@ -41,8 +41,8 @@ var/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, - /datum/pet_command/point_targetting/attack, - /datum/pet_command/point_targetting/fetch, + /datum/pet_command/point_targeting/attack, + /datum/pet_command/point_targeting/fetch, ) /mob/living/basic/mining/mook/Initialize(mapload) @@ -52,14 +52,12 @@ move_resist = MOVE_RESIST_DEFAULT,\ ) AddComponent(/datum/component/ai_retaliate_advanced, CALLBACK(src, PROC_REF(attack_intruder))) - var/datum/action/cooldown/mob_cooldown/mook_ability/mook_jump/jump = new(src) - jump.Grant(src) - ai_controller.set_blackboard_key(BB_MOOK_JUMP_ABILITY, jump) + grant_actions_by_list(get_innate_abilities()) ore_overlay = mutable_appearance(icon, "mook_ore_overlay") AddComponent(/datum/component/ai_listen_to_weather) - AddElement(/datum/element/wall_smasher) + AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE) RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) RegisterSignal(src, COMSIG_KB_MOB_DROPITEM_DOWN, PROC_REF(drop_ore)) @@ -68,6 +66,13 @@ AddComponent(/datum/component/obeys_commands, pet_commands) +/// Returns a list of actions and blackboard keys to pass into `grant_actions_by_list`. +/mob/living/basic/mining/mook/proc/get_innate_abilities() + var/static/list/innate_abilities = list( + /datum/action/cooldown/mob_cooldown/mook_ability/mook_jump = BB_MOOK_JUMP_ABILITY, + ) + return innate_abilities + /mob/living/basic/mining/mook/proc/grant_healer_abilities() AddComponent(\ /datum/component/healing_touch,\ @@ -198,9 +203,18 @@ neutral_stance = mutable_appearance(icon, "mook_axe_overlay") attack_stance = mutable_appearance(icon, "axe_strike_overlay") update_appearance() - var/datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/leap = new(src) - leap.Grant(src) - ai_controller.set_blackboard_key(BB_MOOK_LEAP_ABILITY, leap) + +/mob/living/basic/mining/mook/worker/get_innate_abilities() + var/static/list/worker_innate_abilites = null + + if(isnull(worker_innate_abilites)) + worker_innate_abilites = list() + worker_innate_abilites += ..() + worker_innate_abilites += list( + /datum/action/cooldown/mob_cooldown/mook_ability/mook_leap = BB_MOOK_LEAP_ABILITY, + ) + + return worker_innate_abilites /mob/living/basic/mining/mook/worker/attack_sequence(atom/target) . = ..() diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm index 0fc2873531e073..b3bd9e1c4d5405 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm @@ -1,12 +1,12 @@ ///commands the chief can pick from GLOBAL_LIST_INIT(mook_commands, list( - new /datum/pet_command/point_targetting/attack, - new /datum/pet_command/point_targetting/fetch, + new /datum/pet_command/point_targeting/attack, + new /datum/pet_command/point_targeting/fetch, )) /datum/ai_controller/basic_controller/mook blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/mook, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/mook, BB_BLACKLIST_MINERAL_TURFS = list(/turf/closed/mineral/gibtonite, /turf/closed/mineral/strong), BB_MAXIMUM_DISTANCE_TO_VILLAGE = 7, BB_STORM_APPROACHING = FALSE, @@ -28,7 +28,7 @@ GLOBAL_LIST_INIT(mook_commands, list( ) ///check for faction if not a ash walker, otherwise just attack -/datum/targetting_datum/basic/mook/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) +/datum/targeting_strategy/basic/mook/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) if(FACTION_ASHWALKER in living_mob.faction) return FALSE @@ -212,7 +212,7 @@ GLOBAL_LIST_INIT(mook_commands, list( ///bard mook plays nice music for the village /datum/ai_controller/basic_controller/mook/bard blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/mook, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/mook, BB_MAXIMUM_DISTANCE_TO_VILLAGE = 10, BB_STORM_APPROACHING = FALSE, BB_SONG_LINES = MOOK_SONG, @@ -264,10 +264,10 @@ GLOBAL_LIST_INIT(mook_commands, list( ///healer mooks guard the village from intruders and heal the miner mooks when they come home /datum/ai_controller/basic_controller/mook/support blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/mook, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/mook, BB_MAXIMUM_DISTANCE_TO_VILLAGE = 10, BB_STORM_APPROACHING = FALSE, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, ) idle_behavior = /datum/idle_behavior/walk_near_target/mook_village planning_subtrees = list( @@ -324,7 +324,7 @@ GLOBAL_LIST_INIT(mook_commands, list( ///the chief would rather command his mooks to attack people than attack them himself /datum/ai_controller/basic_controller/mook/tribal_chief blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/mook, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/mook, BB_STORM_APPROACHING = FALSE, ) idle_behavior = /datum/idle_behavior/walk_near_target/mook_village @@ -349,7 +349,7 @@ GLOBAL_LIST_INIT(mook_commands, list( if(!locate(/mob/living/basic/mining/mook) in oview(command_distance, controller.pawn)) return if(controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) - controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_BASIC_MOB_CURRENT_TARGET, /datum/pet_command/point_targetting/attack) + controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_BASIC_MOB_CURRENT_TARGET, /datum/pet_command/point_targeting/attack) return var/atom/ore_target = controller.blackboard[BB_ORE_TARGET] @@ -359,7 +359,7 @@ GLOBAL_LIST_INIT(mook_commands, list( if(get_dist(ore_target, living_pawn) <= 1) return - controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_ORE_TARGET, /datum/pet_command/point_targetting/fetch) + controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_ORE_TARGET, /datum/pet_command/point_targeting/fetch) /datum/ai_behavior/issue_commands action_cooldown = 5 SECONDS diff --git a/code/modules/mob/living/basic/lavaland/watcher/watcher.dm b/code/modules/mob/living/basic/lavaland/watcher/watcher.dm index 28ed712d06127a..c3c30526dff745 100644 --- a/code/modules/mob/living/basic/lavaland/watcher/watcher.dm +++ b/code/modules/mob/living/basic/lavaland/watcher/watcher.dm @@ -62,7 +62,7 @@ var/datum/action/cooldown/mob_cooldown/watcher_gaze/gaze = new gaze_attack(src) gaze.Grant(src) ai_controller.set_blackboard_key(BB_GENERIC_ACTION, gaze) - AddComponent(/datum/component/revenge_ability, gaze, targetting = ai_controller.blackboard[BB_TARGETTING_DATUM]) + AddComponent(/datum/component/revenge_ability, gaze, targeting = GET_TARGETING_STRATEGY(ai_controller.blackboard[BB_TARGETING_STRATEGY])) /mob/living/basic/mining/watcher/update_overlays() . = ..() diff --git a/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm b/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm index 348bbcfcaa7d00..c962ca50c12a45 100644 --- a/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm +++ b/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/watcher blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = PAUSE_DURING_DO_AFTER diff --git a/code/modules/mob/living/basic/minebots/minebot.dm b/code/modules/mob/living/basic/minebots/minebot.dm index 061c9a624f719d..6bc0202aed58b2 100644 --- a/code/modules/mob/living/basic/minebots/minebot.dm +++ b/code/modules/mob/living/basic/minebots/minebot.dm @@ -40,7 +40,7 @@ /datum/pet_command/automate_mining, /datum/pet_command/free/minebot, /datum/pet_command/follow, - /datum/pet_command/point_targetting/attack/minebot, + /datum/pet_command/point_targeting/attack/minebot, ) /mob/living/basic/mining_drone/Initialize(mapload) @@ -58,14 +58,13 @@ after_tame = CALLBACK(src, PROC_REF(activate_bot)),\ ) - var/datum/action/cooldown/mob_cooldown/minedrone/toggle_light/toggle_light_action = new(src) - var/datum/action/cooldown/mob_cooldown/minedrone/toggle_meson_vision/toggle_meson_vision_action = new(src) - var/datum/action/cooldown/mob_cooldown/minedrone/dump_ore/dump_ore_action = new(src) - toggle_light_action.Grant(src) - toggle_meson_vision_action.Grant(src) - dump_ore_action.Grant(src) - ai_controller.set_blackboard_key(BB_MINEBOT_LIGHT_ABILITY, toggle_light_action) - ai_controller.set_blackboard_key(BB_MINEBOT_DUMP_ABILITY, dump_ore_action) + var/static/list/innate_actions = list( + /datum/action/cooldown/mob_cooldown/minedrone/toggle_light = BB_MINEBOT_LIGHT_ABILITY, + /datum/action/cooldown/mob_cooldown/minedrone/toggle_meson_vision = null, + /datum/action/cooldown/mob_cooldown/minedrone/dump_ore = BB_MINEBOT_DUMP_ABILITY, + ) + + grant_actions_by_list(innate_actions) stored_gun = new(src) var/obj/item/implant/radio/mining/comms = new(src) diff --git a/code/modules/mob/living/basic/minebots/minebot_ai.dm b/code/modules/mob/living/basic/minebots/minebot_ai.dm index f4a2adda9e1fdd..4aba93c426501a 100644 --- a/code/modules/mob/living/basic/minebots/minebot_ai.dm +++ b/code/modules/mob/living/basic/minebots/minebot_ai.dm @@ -1,7 +1,7 @@ /datum/ai_controller/basic_controller/minebot blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, BB_BLACKLIST_MINERAL_TURFS = list(/turf/closed/mineral/gibtonite), BB_AUTOMATED_MINING = FALSE, ) @@ -201,10 +201,10 @@ radial_icon_state = "mech_eject" ability_key = BB_MINEBOT_DUMP_ABILITY -/datum/pet_command/point_targetting/attack/minebot +/datum/pet_command/point_targeting/attack/minebot attack_behaviour = /datum/ai_behavior/basic_ranged_attack/minebot -/datum/pet_command/point_targetting/attack/minebot/execute_action(datum/ai_controller/controller) +/datum/pet_command/point_targeting/attack/minebot/execute_action(datum/ai_controller/controller) controller.set_blackboard_key(BB_AUTOMATED_MINING, FALSE) var/mob/living/living_pawn = controller.pawn if(!living_pawn.combat_mode) diff --git a/code/modules/mob/living/basic/pets/dog/_dog.dm b/code/modules/mob/living/basic/pets/dog/_dog.dm index dd3b3b3a4634c6..f835d7c5e17584 100644 --- a/code/modules/mob/living/basic/pets/dog/_dog.dm +++ b/code/modules/mob/living/basic/pets/dog/_dog.dm @@ -7,10 +7,10 @@ speech_commands = list("good dog") // Set correct attack behaviour -/datum/pet_command/point_targetting/attack/dog +/datum/pet_command/point_targeting/attack/dog attack_behaviour = /datum/ai_behavior/basic_melee_attack/dog -/datum/pet_command/point_targetting/attack/dog/set_command_active(mob/living/parent, mob/living/commander) +/datum/pet_command/point_targeting/attack/dog/set_command_active(mob/living/parent, mob/living/commander) . = ..() parent.ai_controller.set_blackboard_key(BB_DOG_HARASS_HARM, TRUE) @@ -40,8 +40,8 @@ /datum/pet_command/free, /datum/pet_command/good_boy/dog, /datum/pet_command/follow/dog, - /datum/pet_command/point_targetting/attack/dog, - /datum/pet_command/point_targetting/fetch, + /datum/pet_command/point_targeting/attack/dog, + /datum/pet_command/point_targeting/fetch, /datum/pet_command/play_dead, ) diff --git a/code/modules/mob/living/basic/pets/fox.dm b/code/modules/mob/living/basic/pets/fox.dm index 150abdc676bc76..7d74a6a36e410a 100644 --- a/code/modules/mob/living/basic/pets/fox.dm +++ b/code/modules/mob/living/basic/pets/fox.dm @@ -39,8 +39,8 @@ /datum/ai_controller/basic_controller/fox blackboard = list( BB_ALWAYS_IGNORE_FACTION = TRUE, - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/of_size/ours_or_smaller, - BB_FLEE_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/of_size/ours_or_smaller, + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/pets/penguin.dm b/code/modules/mob/living/basic/pets/penguin.dm index 35abc784e3792e..671c2cf30c130f 100644 --- a/code/modules/mob/living/basic/pets/penguin.dm +++ b/code/modules/mob/living/basic/pets/penguin.dm @@ -84,7 +84,7 @@ /datum/ai_controller/basic_controller/penguin blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED @@ -178,7 +178,7 @@ /datum/ai_controller/basic_controller/penguin/baby blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_FIND_MOM_TYPES = list(/mob/living/basic/pet/penguin), BB_IGNORE_MOM_TYPES = list(/mob/living/basic/pet/penguin/baby), ) diff --git a/code/modules/mob/living/basic/pets/sloth.dm b/code/modules/mob/living/basic/pets/sloth.dm index aaeeb218b2c0cc..0b1546ccf93dd8 100644 --- a/code/modules/mob/living/basic/pets/sloth.dm +++ b/code/modules/mob/living/basic/pets/sloth.dm @@ -75,8 +75,8 @@ GLOBAL_DATUM(cargo_sloth, /mob/living/basic/sloth) /// They're really passive in game, so they just wanna get away if you start smacking them. No trees in space from them to use for clawing your eyes out, but they will try if desperate. /datum/ai_controller/basic_controller/sloth blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_FLEE_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED diff --git a/code/modules/mob/living/basic/ruin_defender/flesh.dm b/code/modules/mob/living/basic/ruin_defender/flesh.dm new file mode 100644 index 00000000000000..85f48a8f672666 --- /dev/null +++ b/code/modules/mob/living/basic/ruin_defender/flesh.dm @@ -0,0 +1,168 @@ +/datum/ai_controller/basic_controller/living_limb_flesh + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGET_MINIMUM_STAT = HARD_CRIT, + ) + + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree + ) + +/mob/living/basic/living_limb_flesh + name = "living flesh" + desc = "A vaguely leg or arm shaped flesh abomination. It pulses, like a heart." + icon = 'icons/mob/simple/animal.dmi' + icon_state = "limb" + icon_living = "limb" + mob_size = MOB_SIZE_SMALL + basic_mob_flags = DEL_ON_DEATH + faction = list(FACTION_HOSTILE) + melee_damage_lower = 10 + melee_damage_upper = 10 + health = 20 + maxHealth = 20 + attack_sound = 'sound/weapons/bite.ogg' + attack_vis_effect = ATTACK_EFFECT_BITE + attack_verb_continuous = "tries desperately to attach to" + attack_verb_simple = "try to attach to" + mob_biotypes = MOB_ORGANIC | MOB_SPECIAL + ai_controller = /datum/ai_controller/basic_controller/living_limb_flesh + /// the meat bodypart we are currently inside, used to like drain nutrition and dismember and shit + var/obj/item/bodypart/current_bodypart + +/mob/living/basic/living_limb_flesh/Initialize(mapload, obj/item/bodypart/limb) + . = ..() + AddComponent(/datum/component/swarming, max_x = 8, max_y = 8) + AddElement(/datum/element/death_drops, string_list(list(/obj/effect/gibspawner/generic))) + if(!isnull(limb)) + register_to_limb(limb) + +/mob/living/basic/living_limb_flesh/Destroy(force) + . = ..() + QDEL_NULL(current_bodypart) + +/mob/living/basic/living_limb_flesh/Life(seconds_per_tick = SSMOBS_DT, times_fired) + . = ..() + if(stat == DEAD) + return + if(isnull(current_bodypart) || isnull(current_bodypart.owner)) + return + var/mob/living/carbon/human/victim = current_bodypart.owner + if(prob(SPT_PROB(3, SSMOBS_DT))) + to_chat(victim, span_warning("The thing posing as your limb makes you feel funny...")) //warn em + //firstly as a sideeffect we drain nutrition from our host + victim.adjust_nutrition(-1.5) + + if(!prob(SPT_PROB(1.5, SSMOBS_DT))) + return + + if(istype(current_bodypart, /obj/item/bodypart/arm)) + var/list/candidates = list() + for(var/atom/movable/movable in orange(victim, 1)) + if(movable.anchored) + continue + if(movable == victim) + continue + if(!victim.CanReach(movable)) + continue + candidates += movable + var/atom/movable/candidate = pick(candidates) + if(isnull(candidate)) + return + victim.start_pulling(candidate, supress_message = TRUE) + victim.visible_message(span_warning("[victim][victim.p_s()] [current_bodypart] instinctually starts feeling [candidate]!")) + return + + if(HAS_TRAIT(victim, TRAIT_IMMOBILIZED)) + return + step(victim, pick(GLOB.cardinals)) + to_chat(victim, span_warning("Your [current_bodypart] moves on its own!")) + + +/mob/living/basic/living_limb_flesh/melee_attack(mob/living/carbon/human/target, list/modifiers, ignore_cooldown) + . = ..() + if (!ishuman(target) || target.stat == DEAD || HAS_TRAIT(target, TRAIT_NODISMEMBER)) + return + + var/list/zone_candidates = target.get_missing_limbs() + for(var/obj/item/bodypart/bodypart in target.bodyparts) + if(bodypart.body_zone == BODY_ZONE_HEAD || bodypart.body_zone == BODY_ZONE_CHEST) + continue + if(HAS_TRAIT(bodypart, TRAIT_IGNORED_BY_LIVING_FLESH)) + continue + if(bodypart.bodypart_flags & BODYPART_UNREMOVABLE) + continue + if(bodypart.brute_dam < 20) + continue + zone_candidates += bodypart.body_zone + + if(!length(zone_candidates)) + return + + var/target_zone = pick(zone_candidates) + var/obj/item/bodypart/target_part = target.get_bodypart(target_zone) + if(isnull(target_part)) + target.emote("scream") // dismember already makes them scream so only do this if we aren't doing that + else + target_part.dismember() + + var/part_type + switch(target_zone) + if(BODY_ZONE_L_ARM) + part_type = /obj/item/bodypart/arm/left/flesh + if(BODY_ZONE_R_ARM) + part_type = /obj/item/bodypart/arm/right/flesh + if(BODY_ZONE_L_LEG) + part_type = /obj/item/bodypart/leg/left/flesh + if(BODY_ZONE_R_LEG) + part_type = /obj/item/bodypart/leg/right/flesh + + target.visible_message(span_danger("[src] [target_part ? "tears off and attaches itself" : "attaches itself"] to where [target][target.p_s()] limb used to be!")) + current_bodypart = new part_type(TRUE) //dont_spawn_flesh, we cant use named arguments here + current_bodypart.replace_limb(target, TRUE) + forceMove(current_bodypart) + register_to_limb(current_bodypart) + +/mob/living/basic/living_limb_flesh/proc/register_to_limb(obj/item/bodypart/part) + ai_controller.set_ai_status(AI_STATUS_OFF) + RegisterSignal(part, COMSIG_BODYPART_REMOVED, PROC_REF(on_limb_lost)) + RegisterSignal(part.owner, COMSIG_LIVING_DEATH, PROC_REF(owner_died)) + RegisterSignal(part.owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(owner_shocked)) //detach if we are shocked, not beneficial for the host but hey its a sideeffect + +/mob/living/basic/living_limb_flesh/proc/owner_shocked(datum/source, shock_damage, source, siemens_coeff, flags) + SIGNAL_HANDLER + if(shock_damage < 10) + return + var/mob/living/carbon/human/part_owner = current_bodypart.owner + if(!detach_self()) + return + var/turf/our_location = get_turf(src) + our_location.visible_message(span_warning("[part_owner][part_owner.p_s()] [current_bodypart] begins to convulse wildly!")) + +/mob/living/basic/living_limb_flesh/proc/owner_died(datum/source, gibbed) + SIGNAL_HANDLER + if(gibbed) + return + addtimer(CALLBACK(src, PROC_REF(detach_self)), 1 SECONDS) //we need new hosts, dead people suck! + +/mob/living/basic/living_limb_flesh/proc/detach_self() + if(isnull(current_bodypart)) + return FALSE + current_bodypart.dismember() + return TRUE//on_limb_lost should be called after that + +/mob/living/basic/living_limb_flesh/proc/on_limb_lost(atom/movable/source, mob/living/carbon/old_owner, dismembered) + SIGNAL_HANDLER + UnregisterSignal(source, COMSIG_BODYPART_REMOVED) + UnregisterSignal(old_owner, COMSIG_LIVING_ELECTROCUTE_ACT) + UnregisterSignal(old_owner, COMSIG_LIVING_DEATH) + addtimer(CALLBACK(src, PROC_REF(wake_up), source), 2 SECONDS) + +/mob/living/basic/living_limb_flesh/proc/wake_up(atom/limb) + ai_controller.set_ai_status(AI_STATUS_ON) + forceMove(limb.drop_location()) + current_bodypart = null + qdel(limb) + visible_message(span_warning("[src] begins flailing around!")) + Shake(6, 6, 0.5 SECONDS) diff --git a/code/modules/mob/living/basic/ruin_defender/living_floor.dm b/code/modules/mob/living/basic/ruin_defender/living_floor.dm new file mode 100644 index 00000000000000..851a0873657a01 --- /dev/null +++ b/code/modules/mob/living/basic/ruin_defender/living_floor.dm @@ -0,0 +1,96 @@ +/datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic/on_top/SelectBehaviors(datum/ai_controller/controller, delta_time) + var/mob/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + if(!target || QDELETED(target)) + return + if(target.loc != controller.pawn.loc) + return + return ..() + +/datum/ai_controller/basic_controller/living_floor + max_target_distance = 2 + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGET_MINIMUM_STAT = HARD_CRIT, + ) + + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic/on_top + ) + +/mob/living/basic/living_floor + name = "floor" + desc = "The floor you walk on. It looks near-impervious to damage." + icon = 'icons/turf/floors.dmi' + icon_state = "floor" + icon_living = "floor" + mob_size = MOB_SIZE_HUGE + mob_biotypes = MOB_SPECIAL + status_flags = GODMODE //nothing but crowbars may kill us + death_message = "" + unsuitable_atmos_damage = 0 + minimum_survivable_temperature = 0 + maximum_survivable_temperature = INFINITY + basic_mob_flags = DEL_ON_DEATH + move_resist = INFINITY + density = FALSE + combat_mode = TRUE + layer = TURF_LAYER + plane = FLOOR_PLANE + faction = list(FACTION_HOSTILE) + melee_damage_lower = 20 + melee_damage_upper = 40 //pranked..... + attack_sound = 'sound/weapons/bite.ogg' + attack_vis_effect = ATTACK_EFFECT_BITE + attack_verb_continuous = "bites" + attack_verb_simple = "bite" + ai_controller = /datum/ai_controller/basic_controller/living_floor + melee_attack_cooldown = 0.5 SECONDS // get real + + var/icon_aggro = "floor-hostile" + var/desc_aggro = "This flooring is alive and filled with teeth, better not step on that. Being covered in plating, it is immune to damage. Seems vulnerable to prying though." + +/mob/living/basic/living_floor/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_IMMOBILIZED, INNATE_TRAIT) + var/static/list/connections = list(COMSIG_ATOM_ENTERED = PROC_REF(look_aggro), COMSIG_ATOM_EXITED = PROC_REF(look_deaggro)) + AddComponent(/datum/component/connect_range, tracked = src, connections = connections, range = 1, works_in_containers = FALSE) + +/mob/living/basic/living_floor/proc/look_aggro(datum/source, mob/living/victim) + SIGNAL_HANDLER + if(!istype(victim) || istype(victim, /mob/living/basic/living_floor) || victim.stat == DEAD) + return + if(victim.loc == loc) //guaranteed bite + var/datum/targeting_strategy/basic/targeting = GET_TARGETING_STRATEGY(ai_controller.blackboard[BB_TARGETING_STRATEGY]) + if(targeting.can_attack(src, victim)) + melee_attack(victim) + icon_state = icon_aggro + desc = desc_aggro + +/mob/living/basic/living_floor/proc/look_deaggro(datum/source, mob/living/victim) + SIGNAL_HANDLER + if(!istype(victim) && !istype(victim, /mob/living/basic/living_floor)) + return + icon_state = initial(icon_state) + desc = initial(desc_aggro) + +/mob/living/basic/living_floor/med_hud_set_health() + return + +/mob/living/basic/living_floor/med_hud_set_status() + return + +/mob/living/basic/living_floor/attackby(obj/item/weapon, mob/user, params) + if(weapon.tool_behaviour != TOOL_CROWBAR) + return ..() + balloon_alert(user, "prying...") + playsound(src, 'sound/items/crowbar.ogg', 45, TRUE) + if(!do_after(user, 5 SECONDS, src)) + return + new /obj/effect/gibspawner/generic(loc) + qdel(src) + +/mob/living/basic/living_floor/white + icon_state = "white" + icon_living = "white" + icon_aggro = "whitefloor-hostile" diff --git a/code/modules/mob/living/basic/ruin_defender/skeleton.dm b/code/modules/mob/living/basic/ruin_defender/skeleton.dm index 125787319b0949..3ca9211451edad 100644 --- a/code/modules/mob/living/basic/ruin_defender/skeleton.dm +++ b/code/modules/mob/living/basic/ruin_defender/skeleton.dm @@ -161,7 +161,7 @@ /// Skeletons mostly just beat people to death, but they'll also find and drink milk. /datum/ai_controller/basic_controller/skeleton blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, BB_TARGET_MINIMUM_STAT = HARD_CRIT, BB_EMOTE_KEY = "rattles", BB_EMOTE_CHANCE = 20, diff --git a/code/modules/mob/living/basic/ruin_defender/stickman.dm b/code/modules/mob/living/basic/ruin_defender/stickman.dm index 107973135c78c1..588a75c6346436 100644 --- a/code/modules/mob/living/basic/ruin_defender/stickman.dm +++ b/code/modules/mob/living/basic/ruin_defender/stickman.dm @@ -33,7 +33,7 @@ /datum/ai_controller/basic_controller/stickman blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic() + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/ruin_defender/wizard/wizard.dm b/code/modules/mob/living/basic/ruin_defender/wizard/wizard.dm new file mode 100644 index 00000000000000..7c35184af3717b --- /dev/null +++ b/code/modules/mob/living/basic/ruin_defender/wizard/wizard.dm @@ -0,0 +1,90 @@ +/mob/living/basic/wizard + name = "Space Wizard" + desc = "A wizard is never early. Nor is he late. He arrives exactly at the worst possible moment." + icon = 'icons/mob/simple/simple_human.dmi' + icon_state = "wizard" + icon_living = "wizard" + icon_dead = "wizard_dead" + mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + sentience_type = SENTIENCE_HUMANOID + speed = 0 + maxHealth = 100 + health = 100 + melee_damage_lower = 5 + melee_damage_upper = 5 + attack_verb_continuous = "punches" + attack_verb_simple = "punch" + attack_sound = 'sound/weapons/punch1.ogg' + combat_mode = TRUE + habitable_atmos = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) + unsuitable_atmos_damage = 7.5 + faction = list(ROLE_WIZARD) + basic_mob_flags = DEL_ON_DEATH + ai_controller = /datum/ai_controller/basic_controller/wizard + + /// A list of possible wizard corpses, and therefore wizard outfits, to select from + var/static/list/wizard_outfits = list( + /obj/effect/mob_spawn/corpse/human/wizard = 5, + /obj/effect/mob_spawn/corpse/human/wizard/red = 3, + /obj/effect/mob_spawn/corpse/human/wizard/yellow = 3, + /obj/effect/mob_spawn/corpse/human/wizard/black = 3, + /obj/effect/mob_spawn/corpse/human/wizard/marisa = 1, + //The tape wizard should go here, but its hat doesn't render correctly for some reason. + ) + /// A specified wizard corpse spawner to use. If null, picks from the list above instead. + var/selected_outfit + + /// Typepath for the wizard's targeted spell. If null, selects randomly. + var/targeted_spell_path + /// List of possible targeted spells to pick from + var/static/list/targeted_spell_list = list( + /datum/action/cooldown/spell/pointed/projectile/fireball/lesser, + /datum/action/cooldown/spell/pointed/projectile/lightningbolt, + ) + + /// Typepath for the wizard's secondary spell. If null, selects randomly. + var/secondary_spell_path + /// List of possible secondary spells to pick from + var/static/list/secondary_spell_list = list( + /datum/action/cooldown/spell/aoe/magic_missile, + /datum/action/cooldown/spell/charged/beam/tesla, + /datum/action/cooldown/spell/aoe/repulse, + /datum/action/cooldown/spell/conjure/the_traps, + ) + +/mob/living/basic/wizard/Initialize(mapload) + . = ..() + if(!selected_outfit) + selected_outfit = pick_weight(wizard_outfits) + apply_dynamic_human_appearance(src, mob_spawn_path = selected_outfit, r_hand = /obj/item/staff) + var/list/remains = string_list(list( + selected_outfit, + /obj/item/staff + )) + AddElement(/datum/element/death_drops, remains) + AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_SHOE) + + if(isnull(targeted_spell_path)) + targeted_spell_path = pick(targeted_spell_list) + if(isnull(secondary_spell_path)) + secondary_spell_path = pick(secondary_spell_list) + + var/datum/action/cooldown/spell/targeted_spell = new targeted_spell_path(src) + targeted_spell.spell_requirements &= ~(SPELL_REQUIRES_HUMAN|SPELL_REQUIRES_WIZARD_GARB|SPELL_REQUIRES_MIND) + targeted_spell.Grant(src) + ai_controller.set_blackboard_key(BB_WIZARD_TARGETED_SPELL, targeted_spell) + + var/datum/action/cooldown/spell/secondary_spell = new secondary_spell_path(src) + secondary_spell.spell_requirements &= ~(SPELL_REQUIRES_HUMAN|SPELL_REQUIRES_WIZARD_GARB|SPELL_REQUIRES_MIND) + secondary_spell.Grant(src) + ai_controller.set_blackboard_key(BB_WIZARD_SECONDARY_SPELL, secondary_spell) + + var/datum/action/cooldown/spell/teleport/radius_turf/blink/lesser/blink_spell = new(src) + blink_spell.Grant(src) + ai_controller.set_blackboard_key(BB_WIZARD_BLINK_SPELL, blink_spell) + +/// Uses the colors and loadout of the original wizard simplemob +/mob/living/basic/wizard/classic + selected_outfit = /obj/effect/mob_spawn/corpse/human/wizard + targeted_spell_path = /datum/action/cooldown/spell/pointed/projectile/fireball/lesser + secondary_spell_path = /datum/action/cooldown/spell/aoe/magic_missile diff --git a/code/modules/mob/living/basic/ruin_defender/wizard/wizard_ai.dm b/code/modules/mob/living/basic/ruin_defender/wizard/wizard_ai.dm new file mode 100644 index 00000000000000..4430b1339a74e2 --- /dev/null +++ b/code/modules/mob/living/basic/ruin_defender/wizard/wizard_ai.dm @@ -0,0 +1,53 @@ +#define WIZARD_SPELL_COOLDOWN (1 SECONDS) + +/** + * Wizards run away from their targets while flinging spells at them and blinking constantly. + */ +/datum/ai_controller/basic_controller/wizard + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGET_MINIMUM_STAT = HARD_CRIT, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/maintain_distance/cover_minimum_distance, + /datum/ai_planning_subtree/targeted_mob_ability/wizard_spell/primary, + /datum/ai_planning_subtree/targeted_mob_ability/wizard_spell/secondary, + /datum/ai_planning_subtree/targeted_mob_ability/wizard_spell/blink, + ) + +/** + * Cast a wizard spell. There is a minimum cooldown between spellcasts to prevent overwhelming spam. + * + * Though only the primary spell is actually targeted, all spells use targeted behavior so that they + * only get used in combat. + */ +/datum/ai_planning_subtree/targeted_mob_ability/wizard_spell + use_ability_behaviour = /datum/ai_behavior/targeted_mob_ability/wizard_spell + +/datum/ai_planning_subtree/targeted_mob_ability/wizard_spell/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if (controller.blackboard[BB_WIZARD_SPELL_COOLDOWN] > world.time) + return + return ..() + +/datum/ai_behavior/targeted_mob_ability/wizard_spell/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key) + . = ..() + controller.set_blackboard_key(BB_WIZARD_SPELL_COOLDOWN, world.time + WIZARD_SPELL_COOLDOWN) + +/datum/ai_planning_subtree/targeted_mob_ability/wizard_spell/primary + ability_key = BB_WIZARD_TARGETED_SPELL + +/datum/ai_planning_subtree/targeted_mob_ability/wizard_spell/secondary + ability_key = BB_WIZARD_SECONDARY_SPELL + +/datum/ai_planning_subtree/targeted_mob_ability/wizard_spell/blink + ability_key = BB_WIZARD_BLINK_SPELL + +/datum/ai_behavior/use_mob_ability/wizard_spell/perform(seconds_per_tick, datum/ai_controller/controller, ability_key) + . = ..() + controller.set_blackboard_key(BB_WIZARD_SPELL_COOLDOWN, world.time + WIZARD_SPELL_COOLDOWN) + +#undef WIZARD_SPELL_COOLDOWN diff --git a/code/modules/mob/living/basic/ruin_defender/wizard/wizard_spells.dm b/code/modules/mob/living/basic/ruin_defender/wizard/wizard_spells.dm new file mode 100644 index 00000000000000..c49d87c730a55c --- /dev/null +++ b/code/modules/mob/living/basic/ruin_defender/wizard/wizard_spells.dm @@ -0,0 +1,17 @@ +// Lesser versions of wizard spells to be used by AI wizards + +/// Lesser fireball, which is slightly less "instant death" than the normal one +/datum/action/cooldown/spell/pointed/projectile/fireball/lesser + name = "Lesser Fireball" + projectile_type = /obj/projectile/magic/fireball/lesser + cooldown_time = 10 SECONDS + +/obj/projectile/magic/fireball/lesser + damage = 0 + exp_light = 1 + +/// Lesser Blink, shorter range than the normal blink spell +/datum/action/cooldown/spell/teleport/radius_turf/blink/lesser + name = "Lesser Blink" + outer_tele_radius = 3 + spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC diff --git a/code/modules/mob/living/basic/space_fauna/ant.dm b/code/modules/mob/living/basic/space_fauna/ant.dm index 7748d9120d76d7..26a904340b7c5e 100644 --- a/code/modules/mob/living/basic/space_fauna/ant.dm +++ b/code/modules/mob/living/basic/space_fauna/ant.dm @@ -45,7 +45,7 @@ /datum/ai_controller/basic_controller/ant blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm b/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm index 851c0bb80290b2..335e7257e504e0 100644 --- a/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm +++ b/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/bear blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index 27b28400b3904b..53199375359d5f 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -58,7 +58,7 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targetting/attack + /datum/pet_command/point_targeting/attack ) /// Carp want to eat raw meat var/static/list/desired_food = list(/obj/item/food/meat/slab, /obj/item/food/meat/rawcutlet) @@ -103,12 +103,7 @@ teleport = new(src) teleport.Grant(src) ai_controller.set_blackboard_key(BB_CARP_RIFT, teleport) - ai_controller.set_blackboard_key(BB_OBSTACLE_TARGETTING_WHITELIST, allowed_obstacle_targets) - - -/mob/living/basic/carp/Destroy() - QDEL_NULL(teleport) - return ..() + ai_controller.set_blackboard_key(BB_OBSTACLE_TARGETING_WHITELIST, allowed_obstacle_targets) /// Tell the elements and the blackboard what food we want to eat /mob/living/basic/carp/proc/setup_eating() @@ -252,6 +247,7 @@ /mob/living/basic/carp/advanced health = 40 + maxHealth = 40 obj_damage = 15 #undef RARE_CAYENNE_CHANCE diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm index b1343a7aeedbfb..9e767bab3af1f8 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm @@ -1,6 +1,6 @@ #define MAGICARP_SPELL_TARGET_SEEK_RANGE 4 -/datum/pet_command/point_targetting/use_ability/magicarp +/datum/pet_command/point_targeting/use_ability/magicarp pet_ability_key = BB_MAGICARP_SPELL /datum/ai_planning_subtree/attack_obstacle_in_path/carp @@ -16,18 +16,18 @@ /// Interrupt your attack chain if: you have a spell, it's not on cooldown, and it has a target /datum/ai_behavior/basic_melee_attack/magicarp -/datum/ai_behavior/basic_melee_attack/magicarp/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, health_ratio_key) +/datum/ai_behavior/basic_melee_attack/magicarp/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key, health_ratio_key) var/datum/action/cooldown/using_action = controller.blackboard[BB_MAGICARP_SPELL] if (QDELETED(using_action)) return ..() - if (!controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETTING] && using_action.IsAvailable()) + if (!controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETING] && using_action.IsAvailable()) finish_action(controller, succeeded = FALSE) return return ..() /** * Find a target for the magicarp's spell - * This gets weird because different spells want different targetting + * This gets weird because different spells want different targeting * but I didn't want a new ai controller for every different spell */ /datum/ai_planning_subtree/find_nearest_magicarp_spell_target @@ -37,12 +37,12 @@ if (!using_action?.IsAvailable()) return - var/spell_targetting = controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETTING] - if (!spell_targetting) - controller.queue_behavior(/datum/ai_behavior/find_potential_targets/nearest/magicarp, BB_MAGICARP_SPELL_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + var/spell_targeting = controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETING] + if (!spell_targeting) + controller.queue_behavior(/datum/ai_behavior/find_potential_targets/nearest/magicarp, BB_MAGICARP_SPELL_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) return - switch(spell_targetting) + switch(spell_targeting) if (MAGICARP_SPELL_CORPSES) controller.queue_behavior(/datum/ai_behavior/find_and_set/friendly_corpses, BB_MAGICARP_SPELL_TARGET, MAGICARP_SPELL_TARGET_SEEK_RANGE) return diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm index 5bf664d1687844..0befb20987c01b 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm @@ -10,8 +10,8 @@ /datum/ai_controller/basic_controller/carp blackboard = list( BB_BASIC_MOB_STOP_FLEEING = TRUE, - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, ) ai_movement = /datum/ai_movement/basic_avoidance @@ -37,8 +37,8 @@ /datum/ai_controller/basic_controller/carp/pet blackboard = list( BB_BASIC_MOB_STOP_FLEEING = TRUE, - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, ) ai_traits = STOP_MOVING_WHEN_PULLED planning_subtrees = list( @@ -81,8 +81,8 @@ /datum/ai_controller/basic_controller/carp/passive blackboard = list( BB_BASIC_MOB_STOP_FLEEING = TRUE, - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, ) ai_traits = STOP_MOVING_WHEN_PULLED planning_subtrees = list( diff --git a/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm b/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm index 32f02b880dba40..65d16cfb490ddc 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm @@ -56,8 +56,8 @@ GLOBAL_LIST_INIT(magicarp_spell_colours, list( /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targetting/attack, - /datum/pet_command/point_targetting/use_ability/magicarp, + /datum/pet_command/point_targeting/attack, + /datum/pet_command/point_targeting/use_ability/magicarp, ) /// List of all projectiles we can fire. /// Non-static, because subtypes can have their own lists. @@ -91,15 +91,15 @@ GLOBAL_LIST_INIT(magicarp_spell_colours, list( ai_controller.set_blackboard_key(BB_MAGICARP_SPELL, spell) assign_spell_ai(spell_type) -/// If you have certain spells, use a different targetting datum +/// If you have certain spells, use a different targeting strategy /mob/living/basic/carp/magic/proc/assign_spell_ai(spell_type) - var/static/list/spell_special_targetting = list( + var/static/list/spell_special_targeting = list( /obj/projectile/magic/animate = MAGICARP_SPELL_OBJECTS, /obj/projectile/magic/door = MAGICARP_SPELL_WALLS, /obj/projectile/magic/resurrection = MAGICARP_SPELL_CORPSES, ) - ai_controller.set_blackboard_key(BB_MAGICARP_SPELL_SPECIAL_TARGETTING, spell_special_targetting[spell_type]) + ai_controller.set_blackboard_key(BB_MAGICARP_SPELL_SPECIAL_TARGETING, spell_special_targeting[spell_type]) /// Shoot when you click away from you /mob/living/basic/carp/magic/RangedAttack(atom/atom_target, modifiers) diff --git a/code/modules/mob/living/basic/space_fauna/cat_surgeon.dm b/code/modules/mob/living/basic/space_fauna/cat_surgeon.dm index 487727fb53cc1c..02faf7c2cc9f20 100644 --- a/code/modules/mob/living/basic/space_fauna/cat_surgeon.dm +++ b/code/modules/mob/living/basic/space_fauna/cat_surgeon.dm @@ -64,7 +64,7 @@ /datum/ai_controller/basic_controller/cat_butcherer blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm b/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm index a64250d891cfa9..606df8f136f75f 100644 --- a/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm +++ b/code/modules/mob/living/basic/space_fauna/changeling/flesh_spider.dm @@ -63,13 +63,12 @@ outline_colour = COLOR_PINK,\ ) - var/datum/action/cooldown/mob_cooldown/lay_web/webbing = new(src) - webbing.webbing_time *= 0.7 - webbing.Grant(src) - ai_controller?.set_blackboard_key(BB_SPIDER_WEB_ACTION, webbing) - - var/datum/action/cooldown/mob_cooldown/lay_web/web_spikes/spikes_web = new(src) - spikes_web.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/mob_cooldown/lay_web = BB_SPIDER_WEB_ACTION, + /datum/action/cooldown/mob_cooldown/lay_web/sticky_web = null, + /datum/action/cooldown/mob_cooldown/lay_web/web_spikes = null, + ) + grant_actions_by_list(innate_actions) - var/datum/action/cooldown/mob_cooldown/lay_web/sticky_web/web_sticky = new(src) - web_sticky.Grant(src) +/datum/action/cooldown/mob_cooldown/lay_web/flesh + webbing_time = 3 SECONDS diff --git a/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm b/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm index ed3c131949dd1b..d8c419ea2e3bc6 100644 --- a/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm +++ b/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm @@ -37,8 +37,7 @@ /mob/living/basic/demon/slaughter/Initialize(mapload) . = ..() - var/datum/action/cooldown/spell/jaunt/bloodcrawl/slaughter_demon/crawl = new crawl_type(src) - crawl.Grant(src) + GRANT_ACTION(/datum/action/cooldown/spell/jaunt/bloodcrawl/slaughter_demon) RegisterSignal(src, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_attack)) RegisterSignals(src, list(COMSIG_MOB_ENTER_JAUNT, COMSIG_MOB_AFTER_EXIT_JAUNT), PROC_REF(on_crawl)) diff --git a/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm b/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm index 47e43704079b4d..b72815d8325ab4 100644 --- a/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm +++ b/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm @@ -52,9 +52,11 @@ /mob/living/basic/eyeball/Initialize(mapload) . = ..() - var/datum/action/cooldown/spell/pointed/death_glare/glare = new(src) - glare.Grant(src) - ai_controller.set_blackboard_key(BB_GLARE_ABILITY, glare) + var/static/list/innate_actions = list( + /datum/action/cooldown/spell/pointed/death_glare = BB_GLARE_ABILITY + ) + grant_actions_by_list(innate_actions) + AddElement(/datum/element/simple_flying) AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/carrot), tame_chance = 100, after_tame = CALLBACK(src, PROC_REF(on_tame))) ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) diff --git a/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_subtree.dm b/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_subtree.dm index b3033b27a4bd34..29ea1dfc352eaa 100644 --- a/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_subtree.dm +++ b/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_subtree.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/eyeball blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/eyeball, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/eyeball, BB_EYE_DAMAGE_THRESHOLD = 10, ) @@ -22,7 +22,7 @@ return SUBTREE_RETURN_FINISH_PLANNING controller.queue_behavior(/datum/ai_behavior/find_the_blind, BB_BLIND_TARGET, BB_EYE_DAMAGE_THRESHOLD) -/datum/targetting_datum/basic/eyeball/can_attack(mob/living/owner, atom/target, vision_range) +/datum/targeting_strategy/basic/eyeball/can_attack(mob/living/owner, atom/target, vision_range) . = ..() if(!.) return FALSE diff --git a/code/modules/mob/living/basic/space_fauna/faithless.dm b/code/modules/mob/living/basic/space_fauna/faithless.dm index 5cfdd4b47b6e21..39f5652d1a0a4f 100644 --- a/code/modules/mob/living/basic/space_fauna/faithless.dm +++ b/code/modules/mob/living/basic/space_fauna/faithless.dm @@ -55,7 +55,7 @@ /datum/ai_controller/basic_controller/faithless blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = UNCONSCIOUS, BB_LOW_PRIORITY_HUNTING_TARGET = null, // lights ) diff --git a/code/modules/mob/living/basic/space_fauna/garden_gnome.dm b/code/modules/mob/living/basic/space_fauna/garden_gnome.dm index d9dfc3c5343286..40debc7622bc43 100644 --- a/code/modules/mob/living/basic/space_fauna/garden_gnome.dm +++ b/code/modules/mob/living/basic/space_fauna/garden_gnome.dm @@ -125,7 +125,7 @@ /datum/ai_controller/basic_controller/garden_gnome blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/ghost.dm b/code/modules/mob/living/basic/space_fauna/ghost.dm index ad79fefc3e6bca..981357d1a130c1 100644 --- a/code/modules/mob/living/basic/space_fauna/ghost.dm +++ b/code/modules/mob/living/basic/space_fauna/ghost.dm @@ -94,7 +94,7 @@ /datum/ai_controller/basic_controller/ghost blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/hivebot/_hivebot.dm b/code/modules/mob/living/basic/space_fauna/hivebot/_hivebot.dm index db0d310a71c770..d914e0589c48f5 100644 --- a/code/modules/mob/living/basic/space_fauna/hivebot/_hivebot.dm +++ b/code/modules/mob/living/basic/space_fauna/hivebot/_hivebot.dm @@ -95,8 +95,7 @@ /mob/living/basic/hivebot/mechanic/Initialize(mapload) . = ..() - var/datum/action/cooldown/spell/conjure/foam_wall/foam = new(src) - foam.Grant(src) + GRANT_ACTION(/datum/action/cooldown/spell/conjure/foam_wall) RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) /mob/living/basic/hivebot/mechanic/proc/pre_attack(mob/living/fixer, atom/target) diff --git a/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_subtree.dm b/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_subtree.dm index 5bd957a7609729..067b0a03c13cca 100644 --- a/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_subtree.dm +++ b/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_subtree.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/hivebot blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/killer_tomato.dm b/code/modules/mob/living/basic/space_fauna/killer_tomato.dm index a3fd64eb798606..c859289b56d7d0 100644 --- a/code/modules/mob/living/basic/space_fauna/killer_tomato.dm +++ b/code/modules/mob/living/basic/space_fauna/killer_tomato.dm @@ -42,7 +42,7 @@ /datum/ai_controller/basic_controller/killer_tomato blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/lightgeist.dm b/code/modules/mob/living/basic/space_fauna/lightgeist.dm index 9ab6ffe677855f..5847b2b6d771c5 100644 --- a/code/modules/mob/living/basic/space_fauna/lightgeist.dm +++ b/code/modules/mob/living/basic/space_fauna/lightgeist.dm @@ -78,7 +78,7 @@ /datum/ai_controller/basic_controller/lightgeist blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/lightgeist, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/lightgeist, ) ai_traits = STOP_MOVING_WHEN_PULLED @@ -91,13 +91,13 @@ ) /// Attack only mobs who have damage that we can heal, I think this is specific enough not to be a generic type -/datum/targetting_datum/lightgeist +/datum/targeting_strategy/lightgeist /// Types of mobs we can heal, not in a blackboard key because there is no point changing this at runtime because the component will already exist var/heal_biotypes = MOB_ORGANIC | MOB_MINERAL /// Type of limb we can heal var/required_bodytype = BODYTYPE_ORGANIC -/datum/targetting_datum/lightgeist/can_attack(mob/living/living_mob, mob/living/target, vision_range) +/datum/targeting_strategy/lightgeist/can_attack(mob/living/living_mob, mob/living/target, vision_range) if (!isliving(target) || target.stat == DEAD) return FALSE if (!(heal_biotypes & target.mob_biotypes)) diff --git a/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart.dm b/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart.dm index 6a41993526e858..72f2001011cc09 100644 --- a/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart.dm +++ b/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart.dm @@ -2,6 +2,8 @@ #define HEARTBEAT_FAST (0.6 SECONDS) #define HEARTBEAT_FRANTIC (0.4 SECONDS) +#define SPIKES_ABILITY_TYPEPATH /datum/action/cooldown/mob_cooldown/chasing_spikes + /mob/living/basic/meteor_heart name = "meteor heart" desc = "A pulsing lump of flesh and bone growing directly out of the ground." @@ -25,10 +27,7 @@ maximum_survivable_temperature = 1500 combat_mode = TRUE move_resist = INFINITY // This mob IS the floor - /// Action which sends a line of spikes chasing a player - var/datum/action/cooldown/mob_cooldown/chasing_spikes/spikes - /// Action which summons areas the player can't stand in - var/datum/action/cooldown/mob_cooldown/spine_traps/traps + /// Looping heartbeat sound var/datum/looping_sound/heartbeat/soundloop @@ -39,14 +38,11 @@ AddElement(/datum/element/death_drops, death_loot) AddElement(/datum/element/relay_attackers) - spikes = new(src) - spikes.Grant(src) - ai_controller.set_blackboard_key(BB_METEOR_HEART_GROUND_SPIKES, spikes) - - traps = new(src) - traps.Grant(src) - ai_controller.set_blackboard_key(BB_METEOR_HEART_SPINE_TRAPS, traps) - + var/static/list/innate_actions = list( + SPIKES_ABILITY_TYPEPATH = BB_METEOR_HEART_GROUND_SPIKES, + /datum/action/cooldown/mob_cooldown/spine_traps = BB_METEOR_HEART_SPINE_TRAPS, + ) + grant_actions_by_list(innate_actions) ai_controller.set_ai_status(AI_STATUS_OFF) RegisterSignal(src, COMSIG_MOB_ABILITY_FINISHED, PROC_REF(used_ability)) @@ -60,12 +56,13 @@ soundloop.pressure_affected = FALSE soundloop.start() - - AddComponent(/datum/component/bloody_spreader,\ + AddComponent(\ + /datum/component/bloody_spreader,\ blood_left = INFINITY,\ blood_dna = list("meaty DNA" = "MT-"),\ diseases = null,\ ) + /// Called when we get mad at something, either for attacking us or attacking the nearby area /mob/living/basic/meteor_heart/proc/aggro() if (ai_controller.ai_status == AI_STATUS_ON) @@ -85,13 +82,11 @@ /// Animate when using certain abilities /mob/living/basic/meteor_heart/proc/used_ability(mob/living/owner, datum/action/cooldown/mob_cooldown/ability) SIGNAL_HANDLER - if (ability != spikes) + if(!istype(ability, SPIKES_ABILITY_TYPEPATH)) return Shake(1, 0, 1.5 SECONDS) /mob/living/basic/meteor_heart/Destroy() - QDEL_NULL(spikes) - QDEL_NULL(traps) QDEL_NULL(soundloop) return ..() @@ -136,3 +131,5 @@ #undef HEARTBEAT_NORMAL #undef HEARTBEAT_FAST #undef HEARTBEAT_FRANTIC + +#undef SPIKES_ABILITY_TYPEPATH diff --git a/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart_ai.dm b/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart_ai.dm index 7684011bd667ce..09659956c58139 100644 --- a/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart_ai.dm +++ b/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart_ai.dm @@ -1,7 +1,7 @@ /// A spellcasting AI which does not move /datum/ai_controller/basic_controller/meteor_heart blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGETLESS_TIME = 0, ) diff --git a/code/modules/mob/living/basic/space_fauna/morph.dm b/code/modules/mob/living/basic/space_fauna/morph.dm index 32115d05602551..22cce322b13a78 100644 --- a/code/modules/mob/living/basic/space_fauna/morph.dm +++ b/code/modules/mob/living/basic/space_fauna/morph.dm @@ -200,7 +200,7 @@ /// Only real human-powered intelligence is capable of playing prop hunt in SS13 (until further notice). /datum/ai_controller/basic_controller/morph blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/mushroom.dm b/code/modules/mob/living/basic/space_fauna/mushroom.dm index 056a4558081ed9..b45c2714d4ab4c 100644 --- a/code/modules/mob/living/basic/space_fauna/mushroom.dm +++ b/code/modules/mob/living/basic/space_fauna/mushroom.dm @@ -57,7 +57,7 @@ /datum/ai_controller/basic_controller/mushroom blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/mushroom, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/mushroom, BB_TARGET_MINIMUM_STAT = DEAD, ) @@ -70,10 +70,10 @@ ) -/datum/targetting_datum/basic/mushroom +/datum/targeting_strategy/basic/mushroom ///we only attacked another mushrooms -/datum/targetting_datum/basic/mushroom/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) +/datum/targeting_strategy/basic/mushroom/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) return !living_mob.faction_check_atom(the_target, exact_match = check_factions_exactly) /datum/ai_planning_subtree/find_and_hunt_target/mushroom_food diff --git a/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm b/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm index cdde6ad05e4c85..c55376c4fcc8f5 100644 --- a/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm +++ b/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm @@ -39,8 +39,7 @@ min_health_slowdown = -1.5,\ ) - var/datum/action/cooldown/spell/jaunt/creature_teleport/teleport = new(src) - teleport.Grant(src) + GRANT_ACTION(/datum/action/cooldown/spell/jaunt/creature_teleport) /mob/living/basic/creature/proc/can_be_seen(turf/location) // Check for darkness diff --git a/code/modules/mob/living/basic/space_fauna/paper_wizard/paper_wizard.dm b/code/modules/mob/living/basic/space_fauna/paper_wizard/paper_wizard.dm index 519e8ba1a73904..720e0c031c0a32 100644 --- a/code/modules/mob/living/basic/space_fauna/paper_wizard/paper_wizard.dm +++ b/code/modules/mob/living/basic/space_fauna/paper_wizard/paper_wizard.dm @@ -36,24 +36,19 @@ AddElement(/datum/element/effect_trail, /obj/effect/temp_visual/paper_scatter) /mob/living/basic/paper_wizard/proc/grant_abilities() - summon = new(src) - summon.Grant(src) - ai_controller.set_blackboard_key(BB_WIZARD_SUMMON_MINIONS, summon) - mimic = new(src) - mimic.Grant(src) - ai_controller.set_blackboard_key(BB_WIZARD_MIMICS, mimic) + var/static/list/innate_actions = list( + /datum/action/cooldown/spell/conjure/wizard_summon_minions = BB_WIZARD_SUMMON_MINIONS, + /datum/action/cooldown/spell/pointed/wizard_mimic = BB_WIZARD_MIMICS, + ) + + grant_actions_by_list(innate_actions) /mob/living/basic/paper_wizard/proc/grant_loot() AddElement(/datum/element/death_drops, dropped_loot) -/mob/living/basic/paper_wizard/Destroy() - QDEL_NULL(summon) - QDEL_NULL(mimic) - return ..() - /datum/ai_controller/basic_controller/paper_wizard blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_WRITING_LIST = list( "I can turn the paper into gold and ink into diamonds!", "Your fate is written and sealed!", diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm index 24e53b3bf444c9..43108c67ef377c 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm @@ -64,13 +64,12 @@ after_assumed_control = CALLBACK(src, PROC_REF(became_player_controlled)),\ ) - var/datum/action/cooldown/mob_cooldown/domain/domain = new(src) - domain.Grant(src) - ai_controller.set_blackboard_key(BB_DOMAIN_ABILITY, domain) + var/static/list/innate_actions = list( + /datum/action/cooldown/mob_cooldown/domain = BB_DOMAIN_ABILITY, + /datum/action/cooldown/mob_cooldown/riot = BB_RAISE_HORDE_ABILITY, + ) - var/datum/action/cooldown/mob_cooldown/riot/riot = new(src) - riot.Grant(src) - ai_controller.set_blackboard_key(BB_RAISE_HORDE_ABILITY, riot) + grant_actions_by_list(innate_actions) /mob/living/basic/regal_rat/examine(mob/user) . = ..() @@ -104,7 +103,7 @@ "All rise for [name], ascendant to the throne in \the [get_area(src)].", source = src, action = NOTIFY_ORBIT, - flashwindow = FALSE, + notify_flags = NOTIFY_CATEGORY_NOFLASH, header = "Sentient Rat Created", ) diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm index e617ae0a670af5..1ab7bd36594c67 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm @@ -56,7 +56,7 @@ /datum/pet_command/free, /datum/pet_command/protect_owner, /datum/pet_command/follow, - /datum/pet_command/point_targetting/attack/mouse + /datum/pet_command/point_targeting/attack/mouse ) /// Commands you can give to glockroaches var/static/list/glockroach_commands = list( @@ -64,7 +64,7 @@ /datum/pet_command/free, /datum/pet_command/protect_owner/glockroach, /datum/pet_command/follow, - /datum/pet_command/point_targetting/attack/glockroach + /datum/pet_command/point_targeting/attack/glockroach ) /datum/action/cooldown/mob_cooldown/riot/Activate(atom/target) @@ -193,7 +193,7 @@ return TRUE // Command you can give to a mouse to make it kill someone -/datum/pet_command/point_targetting/attack/mouse +/datum/pet_command/point_targeting/attack/mouse speech_commands = list("attack", "sic", "kill", "cheese em") command_feedback = "squeak!" // Frogs and roaches can squeak too it's fine pointed_reaction = "and squeaks aggressively" @@ -201,7 +201,7 @@ attack_behaviour = /datum/ai_behavior/basic_melee_attack // Command you can give to a mouse to make it kill someone -/datum/pet_command/point_targetting/attack/glockroach +/datum/pet_command/point_targeting/attack/glockroach speech_commands = list("attack", "sic", "kill", "cheese em") command_feedback = "squeak!" pointed_reaction = "and cocks its gun" diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_ai.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_ai.dm index 8a7013b9623733..073029bef3c265 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_ai.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_ai.dm @@ -1,7 +1,7 @@ /datum/ai_controller/basic_controller/regal_rat blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_FLEE_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm index 856b5820b9852b..6da3352c9d6dd9 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -97,9 +97,7 @@ AddElement(/datum/element/simple_flying) add_traits(list(TRAIT_SPACEWALK, TRAIT_SIXTHSENSE, TRAIT_FREE_HYPERSPACE_MOVEMENT), INNATE_TRAIT) - for(var/ability in abilities) - var/datum/action/spell = new ability(src) - spell.Grant(src) + grant_actions_by_list(abilities) RegisterSignal(src, COMSIG_LIVING_BANED, PROC_REF(on_baned)) RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move)) diff --git a/code/modules/mob/living/basic/space_fauna/snake/snake.dm b/code/modules/mob/living/basic/space_fauna/snake/snake.dm index 164752e277d978..135402a5b441c1 100644 --- a/code/modules/mob/living/basic/space_fauna/snake/snake.dm +++ b/code/modules/mob/living/basic/space_fauna/snake/snake.dm @@ -71,7 +71,7 @@ /// Snakes are primarily concerned with getting those tasty, tasty mice, but aren't afraid to strike back at those who attack them /datum/ai_controller/basic_controller/snake blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends/allow_items, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends/allow_items, ) ai_traits = STOP_MOVING_WHEN_PULLED diff --git a/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm b/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm index 50c54da6c9be32..547e35cf413a99 100644 --- a/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm +++ b/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm @@ -63,7 +63,7 @@ add_traits(list(TRAIT_SPACEWALK, TRAIT_FREE_HYPERSPACE_MOVEMENT, TRAIT_NO_FLOATING_ANIM, TRAIT_HEALS_FROM_CARP_RIFTS), INNATE_TRAIT) AddElement(/datum/element/simple_flying) AddElement(/datum/element/content_barfer) - AddElement(/datum/element/wall_tearer, do_after_key = DOAFTER_SOURCE_SPACE_DRAGON_INTERACTION) + AddElement(/datum/element/wall_tearer, tear_time = 4 SECONDS, reinforced_multiplier = 3, do_after_key = DOAFTER_SOURCE_SPACE_DRAGON_INTERACTION) AddElement(/datum/element/door_pryer, pry_time = 4 SECONDS, interaction_key = DOAFTER_SOURCE_SPACE_DRAGON_INTERACTION) AddComponent(/datum/component/seethrough_mob) RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) @@ -76,11 +76,6 @@ buffet = new(src) buffet.Grant(src) -/mob/living/basic/space_dragon/Destroy() - QDEL_NULL(fire_breath) - QDEL_NULL(buffet) - return ..() - /mob/living/basic/space_dragon/Login() . = ..() if(!isnull(chosen_colour)) diff --git a/code/modules/mob/living/basic/space_fauna/spaceman.dm b/code/modules/mob/living/basic/space_fauna/spaceman.dm index 5851bfa531b373..8a9ba36287ae35 100644 --- a/code/modules/mob/living/basic/space_fauna/spaceman.dm +++ b/code/modules/mob/living/basic/space_fauna/spaceman.dm @@ -32,7 +32,7 @@ /datum/ai_controller/basic_controller/spaceman blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_ai.dm b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_ai.dm index 7dd61b72070df1..ae971fd2558e54 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_ai.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_ai.dm @@ -1,7 +1,7 @@ /// Attacks people it can see, spins webs if it can't see anything to attack. /datum/ai_controller/basic_controller/giant_spider blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED | PAUSE_DURING_DO_AFTER @@ -30,7 +30,7 @@ /// Used by Araneus, who only attacks those who attack first. He is house-trained and will not web up the HoS office. /datum/ai_controller/basic_controller/giant_spider/retaliate blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) planning_subtrees = list( @@ -43,8 +43,8 @@ /// Retaliates, hunts other maintenance creatures, runs away from larger attackers, and spins webs. /datum/ai_controller/basic_controller/giant_spider/pest blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/of_size/ours_or_smaller(), // Hunt mobs our size - BB_FLEE_TARGETTING_DATUM = new /datum/targetting_datum/basic/of_size/larger(), // Run away from mobs bigger than we are + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/of_size/ours_or_smaller, // Hunt mobs our size + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic/of_size/larger, // Run away from mobs bigger than we are ) idle_behavior = /datum/idle_behavior/idle_random_walk diff --git a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm index 8cb7d8398bf366..99e4b2b03cc065 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm @@ -19,7 +19,12 @@ melee_damage_upper = 25 gold_core_spawnable = HOSTILE_SPAWN ai_controller = /datum/ai_controller/basic_controller/giant_spider + /// Actions to grant on Initialize + var/list/innate_actions = null +/mob/living/basic/spider/giant/Initialize(mapload) + . = ..() + grant_actions_by_list(innate_actions) /** * ### Ambush Spider @@ -37,11 +42,13 @@ maxHealth = 125 health = 125 obj_damage = 45 + melee_damage_lower = 25 melee_damage_upper = 30 speed = 5 player_speed_modifier = -3.1 - menu_description = "Slow spider variant specializing in stalking and ambushing prey, above avarage health and damage with a strong grip." + menu_description = "Slow spider, with a strong disarming pull and above average health and damage." + innate_actions = list(/datum/action/cooldown/mob_cooldown/sneak/spider) /mob/living/basic/spider/giant/ambush/Initialize(mapload) . = ..() @@ -49,9 +56,6 @@ AddElement(/datum/element/web_walker, /datum/movespeed_modifier/slow_web) - var/datum/action/cooldown/mob_cooldown/sneak/spider/sneak_web = new(src) - sneak_web.Grant(src) - /** * ### Guard Spider * A subtype of the giant spider which is similar on every single way, @@ -72,14 +76,12 @@ obj_damage = 45 speed = 5 player_speed_modifier = -4 - menu_description = "Tanky and strong for the defense of the nest and other spiders." + menu_description = "Tanky and strong able to shed a carcass for protection." + innate_actions = list(/datum/action/cooldown/mob_cooldown/web_effigy) /mob/living/basic/spider/giant/guard/Initialize(mapload) . = ..() - AddElement(/datum/element/web_walker, /datum/movespeed_modifier/average_web) - var/datum/action/cooldown/mob_cooldown/web_effigy/shed = new(src) - shed.Grant(src) /** * ### Hunter Spider @@ -100,11 +102,10 @@ poison_per_bite = 5 speed = 3 player_speed_modifier = -3.1 - menu_description = "Fast spider variant specializing in catching running prey and toxin injection, but has less health and damage." + menu_description = "Fast spider with toxin injection, but has less health and damage." /mob/living/basic/spider/giant/hunter/Initialize(mapload) . = ..() - AddElement(/datum/element/web_walker, /datum/movespeed_modifier/fast_web) /** @@ -129,15 +130,13 @@ speed = 2.8 player_speed_modifier = -3.1 sight = SEE_SELF|SEE_MOBS - menu_description = "Fast spider variant specializing in scouting and alerting of prey, with the ability to travel in vents." + menu_description = "Fast spider able to see enemies through walls, send messages to the nest and the ability to travel in vents." + innate_actions = list(/datum/action/cooldown/mob_cooldown/command_spiders/communication_spiders) /mob/living/basic/spider/giant/scout/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) - var/datum/action/cooldown/mob_cooldown/command_spiders/communication_spiders/spiders_communication = new(src) - spiders_communication.Grant(src) - /** * ### Nurse Spider * @@ -162,7 +161,7 @@ player_speed_modifier = -3.1 web_speed = 0.25 web_type = /datum/action/cooldown/mob_cooldown/lay_web/sealer - menu_description = "Support spider variant specializing in healing their brethren and placing webbings very swiftly, but has very low amount of health and deals low damage." + menu_description = "Avarage speed spider able to heal other spiders and itself together with a fast web laying capability, has low damage and health." ///The health HUD applied to the mob. var/health_hud = DATA_HUD_MEDICAL_ADVANCED @@ -209,21 +208,16 @@ speed = 4 player_speed_modifier = -3.1 web_type = /datum/action/cooldown/mob_cooldown/lay_web/sealer - menu_description = "Support spider variant specializing in contruction to protect their brethren, but has very low amount of health and deals low damage." + menu_description = "Average speed spider with self healing abilities and multiple web types to reinforce the nest with little to no damage and low health." + innate_actions = list( + /datum/action/cooldown/mob_cooldown/lay_web/solid_web, + /datum/action/cooldown/mob_cooldown/lay_web/sticky_web, + /datum/action/cooldown/mob_cooldown/lay_web/web_passage, + /datum/action/cooldown/mob_cooldown/lay_web/web_spikes, + ) /mob/living/basic/spider/giant/tangle/Initialize(mapload) . = ..() - var/datum/action/cooldown/mob_cooldown/lay_web/solid_web/web_solid = new(src) - web_solid.Grant(src) - - var/datum/action/cooldown/mob_cooldown/lay_web/web_passage/passage_web = new(src) - passage_web.Grant(src) - - var/datum/action/cooldown/mob_cooldown/lay_web/web_spikes/spikes_web = new(src) - spikes_web.Grant(src) - - var/datum/action/cooldown/mob_cooldown/lay_web/sticky_web/web_sticky = new(src) - web_sticky.Grant(src) AddElement(/datum/element/web_walker, /datum/movespeed_modifier/average_web) @@ -231,7 +225,7 @@ heal_brute = 15,\ heal_burn = 15,\ heal_time = 3 SECONDS,\ - self_targetting = HEALING_TOUCH_SELF_ONLY,\ + self_targeting = HEALING_TOUCH_SELF_ONLY,\ interaction_key = DOAFTER_SOURCE_SPIDER,\ valid_targets_typecache = typecacheof(list(/mob/living/basic/spider/growing/young/tangle, /mob/living/basic/spider/giant/tangle)),\ extra_checks = CALLBACK(src, PROC_REF(can_mend)),\ @@ -246,6 +240,97 @@ return FALSE return TRUE +/** + * ### Spider Tank + * A subtype of the giant spider, specialized in taking damage. + * This spider is only slightly slower than a human. + */ +/mob/living/basic/spider/giant/tank + name = "tank spider" + desc = "Furry and Purple with a white top, it makes you shudder to look at it. This one has bright yellow eyes." + icon_state = "tank" + icon_living = "tank" + icon_dead = "tank_dead" + maxHealth = 500 + health = 500 + damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1) + melee_damage_lower = 5 + melee_damage_upper = 5 + obj_damage = 15 + speed = 5 + player_speed_modifier = -4 + menu_description = "Extremly tanky with very poor offence. Able to self heal and lay reflective silk screens." + +/mob/living/basic/spider/giant/tank/Initialize(mapload) + . = ..() + var/datum/action/cooldown/mob_cooldown/lay_web/web_reflector/reflector_web = new(src) + reflector_web.Grant(src) + + var/datum/action/cooldown/mob_cooldown/lay_web/web_passage/passage_web = new(src) + passage_web.Grant(src) + + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/below_average_web) + + AddComponent(/datum/component/healing_touch,\ + heal_brute = 50,\ + heal_burn = 50,\ + heal_time = 5 SECONDS,\ + self_targeting = HEALING_TOUCH_SELF_ONLY,\ + interaction_key = DOAFTER_SOURCE_SPIDER,\ + valid_targets_typecache = typecacheof(list(/mob/living/basic/spider/growing/young/tank, /mob/living/basic/spider/giant/tank)),\ + extra_checks = CALLBACK(src, PROC_REF(can_mend)),\ + action_text = "%SOURCE% begins mending themselves...",\ + complete_text = "%SOURCE%'s wounds mend together.",\ + ) + +/// Prevent you from healing when on fire +/mob/living/basic/spider/giant/tank/proc/can_mend(mob/living/source, mob/living/target) + if (on_fire) + balloon_alert(src, "on fire!") + return FALSE + return TRUE + +/** + * ### Spider Breacher + * A subtype of the giant spider, specialized in breaching and invasion. + * This spider is only slightly slower than a human. + */ +/mob/living/basic/spider/giant/breacher + name = "breacher spider" + desc = "Furry and light brown with dark brown and red highlights, it makes you shudder to look at it. This one has bright red eyes." + icon_state = "breacher" + icon_living = "breacher" + icon_dead = "breacher_dead" + maxHealth = 120 + health = 120 + melee_damage_lower = 5 + melee_damage_upper = 10 + unsuitable_atmos_damage = 0 + minimum_survivable_temperature = 0 + maximum_survivable_temperature = 700 + unsuitable_cold_damage = 0 + wound_bonus = 25 + bare_wound_bonus = 50 + sharpness = SHARP_EDGED + obj_damage = 60 + web_speed = 0.25 + limb_destroyer = 50 + speed = 5 + player_speed_modifier = -4 + sight = SEE_TURFS + menu_description = "Atmospherically resistant with the ability to destroy walls and limbs, and to send warnings to the nest." + +/mob/living/basic/spider/giant/breacher/Initialize(mapload) + . = ..() + var/datum/action/cooldown/mob_cooldown/lay_web/solid_web/web_solid = new(src) + web_solid.Grant(src) + + var/datum/action/cooldown/mob_cooldown/command_spiders/warning_spiders/spiders_warning = new(src) + spiders_warning.Grant(src) + + AddElement(/datum/element/wall_tearer) + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/below_average_web) + /** * ### Tarantula * @@ -259,8 +344,8 @@ icon_state = "tarantula" icon_living = "tarantula" icon_dead = "tarantula_dead" - maxHealth = 360 // woah nelly - health = 360 + maxHealth = 400 // woah nelly + health = 400 melee_damage_lower = 35 melee_damage_upper = 40 obj_damage = 100 @@ -272,21 +357,19 @@ web_speed = 0.7 web_type = /datum/action/cooldown/mob_cooldown/lay_web/sealer menu_description = "Tank spider variant with an enormous amount of health and damage, but is very slow when not on webbing. It also has a charge ability to close distance with a target after a small windup." - /// Charging ability + innate_actions = list( + /datum/action/cooldown/mob_cooldown/charge/basic_charge, + /datum/action/cooldown/mob_cooldown/lay_web/solid_web, + /datum/action/cooldown/mob_cooldown/lay_web/web_passage, + ) + /// Charging ability, kept seperate from innate_actions due to implementation details var/datum/action/cooldown/mob_cooldown/charge/basic_charge/charge /mob/living/basic/spider/giant/tarantula/Initialize(mapload) . = ..() - var/datum/action/cooldown/mob_cooldown/lay_web/solid_web/web_solid = new(src) - web_solid.Grant(src) - - var/datum/action/cooldown/mob_cooldown/lay_web/web_passage/passage_web = new(src) - passage_web.Grant(src) - charge = new /datum/action/cooldown/mob_cooldown/charge/basic_charge() charge.Grant(src) - AddElement(/datum/element/tear_wall) AddElement(/datum/element/web_walker, /datum/movespeed_modifier/slow_web) /mob/living/basic/spider/giant/tarantula/Destroy() @@ -320,15 +403,14 @@ player_speed_modifier = -2.5 gold_core_spawnable = NO_SPAWN menu_description = "Assassin spider variant with an unmatched speed and very deadly poison, but has very low amount of health and damage." + innate_actions = list( + /datum/action/cooldown/mob_cooldown/defensive_mode, + ) /mob/living/basic/spider/giant/viper/Initialize(mapload) . = ..() - AddElement(/datum/element/bonus_damage) - var/datum/action/cooldown/mob_cooldown/defensive_mode/defensive_action = new(src) - defensive_action.Grant(src) - /** * ### Spider Broodmother * @@ -355,35 +437,21 @@ web_speed = 0.5 web_type = /datum/action/cooldown/mob_cooldown/lay_web/sealer menu_description = "Royal spider variant specializing in reproduction and leadership, deals low damage." + innate_actions = list( + /datum/action/cooldown/mob_cooldown/command_spiders, + /datum/action/cooldown/mob_cooldown/lay_eggs, + /datum/action/cooldown/mob_cooldown/lay_eggs/abnormal, + /datum/action/cooldown/mob_cooldown/lay_eggs/enriched, + /datum/action/cooldown/mob_cooldown/lay_web/solid_web, + /datum/action/cooldown/mob_cooldown/lay_web/sticky_web, + /datum/action/cooldown/mob_cooldown/lay_web/web_passage, + /datum/action/cooldown/mob_cooldown/lay_web/web_spikes, + /datum/action/cooldown/mob_cooldown/set_spider_directive, + /datum/action/cooldown/mob_cooldown/wrap, + ) /mob/living/basic/spider/giant/midwife/Initialize(mapload) . = ..() - var/datum/action/cooldown/mob_cooldown/lay_web/solid_web/web_solid = new(src) - web_solid.Grant(src) - - var/datum/action/cooldown/mob_cooldown/lay_web/web_passage/passage_web = new(src) - passage_web.Grant(src) - - var/datum/action/cooldown/mob_cooldown/lay_web/web_spikes/spikes_web = new(src) - spikes_web.Grant(src) - - var/datum/action/cooldown/mob_cooldown/lay_web/sticky_web/web_sticky = new(src) - web_sticky.Grant(src) - - var/datum/action/cooldown/mob_cooldown/wrap/wrapping = new(src) - wrapping.Grant(src) - - var/datum/action/cooldown/mob_cooldown/lay_eggs/make_eggs = new(src) - make_eggs.Grant(src) - - var/datum/action/cooldown/mob_cooldown/lay_eggs/enriched/make_better_eggs = new(src) - make_better_eggs.Grant(src) - - var/datum/action/cooldown/mob_cooldown/set_spider_directive/give_orders = new(src) - give_orders.Grant(src) - - var/datum/action/cooldown/mob_cooldown/command_spiders/not_hivemind_talk = new(src) - not_hivemind_talk.Grant(src) AddElement(/datum/element/web_walker, /datum/movespeed_modifier/average_web) @@ -498,18 +566,15 @@ unsuitable_heat_damage = 1 menu_description = "Stronger assassin spider variant with an unmatched speed, high amount of health and very deadly poison, but deals very low amount of damage. It also has ability to ventcrawl." apply_spider_antag = FALSE + innate_actions = list( + /datum/action/cooldown/mob_cooldown/lay_web/sticky_web, + /datum/action/cooldown/mob_cooldown/lay_web/web_spikes, + ) /mob/living/basic/spider/giant/viper/wizard/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) - var/datum/action/cooldown/mob_cooldown/lay_web/web_spikes/spikes_web = new(src) - spikes_web.Grant(src) - - var/datum/action/cooldown/mob_cooldown/lay_web/sticky_web/web_sticky = new(src) - web_sticky.Grant(src) - - /** * ### Sergeant Araneus * diff --git a/code/modules/mob/living/basic/space_fauna/spider/spider.dm b/code/modules/mob/living/basic/space_fauna/spider/spider.dm index 53b48129e2ed49..9ce7f50d0174d7 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spider.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spider.dm @@ -54,6 +54,7 @@ AddElement(/datum/element/nerfed_pulling, GLOB.typecache_general_bad_things_to_easily_move) AddElement(/datum/element/prevent_attacking_of_types, GLOB.typecache_general_bad_hostile_attack_targets, "this tastes awful!") AddElement(/datum/element/cliff_walking) + AddComponent(/datum/component/health_scaling_effects, min_health_slowdown = 1.5) if(poison_per_bite) AddElement(/datum/element/venomous, poison_type, poison_per_bite) diff --git a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/hivemind.dm b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/hivemind.dm index bbeb2b28bb5493..790879b0de2c1e 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/hivemind.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/hivemind.dm @@ -84,3 +84,16 @@ /datum/action/cooldown/mob_cooldown/command_spiders/communication_spiders/format_message(mob/living/user, message) return span_spiderscout("Report from [user]: [message]") + +/** + * Sends a smaller message to all currently living spiders. + */ +/datum/action/cooldown/mob_cooldown/command_spiders/warning_spiders + name = "Warning" + desc = "Send a warning to all living spiders." + button_icon = 'icons/mob/actions/actions_animal.dmi' + button_icon_state = "warning" + +/datum/action/cooldown/mob_cooldown/command_spiders/warning_spiders/format_message(mob/living/user, message) + return span_spiderbreacher("Warning from [user]: [message]") + diff --git a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/lay_eggs.dm b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/lay_eggs.dm index 01477cd843541b..5979c98448dedb 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/lay_eggs.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/lay_eggs.dm @@ -5,8 +5,8 @@ button_icon_state = "lay_eggs" background_icon_state = "bg_alien" overlay_icon_state = "bg_alien_border" - cooldown_time = 0 - melee_cooldown_time = 0 + cooldown_time = 20 SECONDS + melee_cooldown_time = 5 SECONDS shared_cooldown = NONE click_to_activate = FALSE ///How long it takes for a broodmother to lay eggs. @@ -60,10 +60,18 @@ if (spider_directive) new_eggs.directive = spider_directive.current_directive +/datum/action/cooldown/mob_cooldown/lay_eggs/abnormal + name = "Lay Abnormal Eggs" + desc = "Lay a cluster of eggs, which will soon grow into a uncommon spider." + button_icon_state = "lay_abnormal_eggs" + cooldown_time = 180 SECONDS + egg_type = /obj/effect/mob_spawn/ghost_role/spider/abnormal + /datum/action/cooldown/mob_cooldown/lay_eggs/enriched name = "Lay Enriched Eggs" - desc = "Lay a cluster of eggs, which will soon grow into a greater spider. Requires you drain a human per cluster of these eggs." + desc = "Lay a cluster of eggs, which will soon grow into a rare spider. Requires you drain a human per cluster of these eggs." button_icon_state = "lay_enriched_eggs" + cooldown_time = 60 SECONDS egg_type = /obj/effect/mob_spawn/ghost_role/spider/enriched /// How many charges we have to make eggs var/charges = 0 diff --git a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/web.dm b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/web.dm index d4f587c93864f6..fa44cb35b2d121 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/web.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/web.dm @@ -117,7 +117,6 @@ /datum/action/cooldown/mob_cooldown/lay_web/web_passage/plant_web(turf/target_turf, obj/structure/spider/stickyweb/existing_web) new /obj/structure/spider/passage(target_turf) - /datum/action/cooldown/mob_cooldown/lay_web/sticky_web name = "Spin Sticky Web" desc = "Spin a sticky web to trap intruders." @@ -171,3 +170,16 @@ /datum/action/cooldown/mob_cooldown/web_effigy/Activate() new /obj/structure/spider/effigy(get_turf(owner)) return ..() + +/datum/action/cooldown/mob_cooldown/lay_web/web_reflector + name = "Spin reflective silk screen" + desc = "Spin a web to reflect missiles from the nest." + button_icon_state = "lay_web_reflector" + cooldown_time = 30 SECONDS + webbing_time = 4 SECONDS + +/datum/action/cooldown/mob_cooldown/lay_web/web_reflector/obstructed_by_other_web() + return !!(locate(/obj/structure/spider/reflector) in get_turf(owner)) + +/datum/action/cooldown/mob_cooldown/lay_web/web_reflector/plant_web(turf/target_turf, obj/structure/spider/stickyweb/existing_web) + new /obj/structure/spider/reflector(target_turf) diff --git a/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling.dm b/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling.dm index c949b438683cb6..2bce05b1a61bad 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling.dm @@ -39,6 +39,7 @@ AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW, volume = 0.2) // they're small but you can hear 'em AddElement(/datum/element/web_walker, /datum/movespeed_modifier/spiderling_web) AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/fast_web) // keep in mind we have infinite range (the entire pipenet is our playground, it's just a matter of random choice as to where we end up) so lower and upper both have their gives and takes. // but, also remember the more time we aren't in a vent, the more susceptible we are to dying to anything and everything. @@ -60,7 +61,7 @@ /// Opportunistically hops in and out of vents, if it can find one. We aren't interested in attacking due to how weak we are, we gotta be quick and hidey. /datum/ai_controller/basic_controller/spiderling blackboard = list( - BB_FLEE_TARGETTING_DATUM = new /datum/targetting_datum/basic/of_size/larger, // Run away from mobs bigger than we are + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic/of_size/larger, // Run away from mobs bigger than we are BB_VENTCRAWL_COOLDOWN = 20 SECONDS, // enough time to get splatted while we're out in the open. BB_TIME_TO_GIVE_UP_ON_VENT_PATHING = 30 SECONDS, ) diff --git a/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling_subtypes.dm b/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling_subtypes.dm index 5d42ca5cb6189b..06d086d89672b7 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling_subtypes.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling_subtypes.dm @@ -1,5 +1,4 @@ -// This whole file is just a container for the spiderling subtypes that actually differentiate into different young spiders. None of them are particularly special as of now. - +/// This whole file is just a container for the spiderling subtypes that actually differentiate into different young spiders. None of them are particularly special as of now. /// Will differentiate into the base young spider (known colloquially as the "guard" spider). /mob/living/basic/spider/growing/spiderling/guard grow_as = /mob/living/basic/spider/growing/young/guard @@ -52,6 +51,24 @@ icon_state = "tangle_spiderling" icon_dead = "tangle_spiderling_dead" +/// Will differentiate into the "tank" young spider. +/mob/living/basic/spider/growing/spiderling/tank + grow_as = /mob/living/basic/spider/growing/young/tank + name = "tank spiderling" + desc = "Furry and purple, it looks defenseless. This one has dim yellow eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "tank_spiderling" + icon_dead = "tank_spiderling_dead" + +/// Will differentiate into the "breacher" young spider. +/mob/living/basic/spider/growing/spiderling/breacher + grow_as = /mob/living/basic/spider/growing/young/breacher + name = "breacher spiderling" + desc = "Furry and baige, it looks defenseless. This one has dim red eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "breacher_spiderling" + icon_dead = "breacher_spiderling_dead" + /// Will differentiate into the "midwife" young spider. /mob/living/basic/spider/growing/spiderling/midwife grow_as = /mob/living/basic/spider/growing/young/midwife diff --git a/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider.dm b/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider.dm index 50ec85e342c913..8c17833c0c7e8e 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider.dm @@ -29,7 +29,7 @@ /// Used by all young spiders if they ever appear. /datum/ai_controller/basic_controller/young_spider blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_BASIC_MOB_FLEE_DISTANCE = 6, ) @@ -47,3 +47,6 @@ /datum/ai_planning_subtree/find_unwebbed_turf, /datum/ai_planning_subtree/spin_web, ) + +/mob/living/basic/spider/growing/young/start_pulling(atom/movable/pulled_atom, state, force = move_force, supress_message = FALSE) // we're TOO FUCKING WEAK + return diff --git a/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider_subtypes.dm b/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider_subtypes.dm index f5d128e41b709a..3a9bad4e75f989 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider_subtypes.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider_subtypes.dm @@ -11,6 +11,11 @@ melee_damage_upper = 15 speed = 0.7 +/mob/living/basic/spider/growing/young/guard/Initialize(mapload) + . = ..() + + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/average_web) + /// Will differentiate into the "ambush" giant spider. /mob/living/basic/spider/growing/young/ambush grow_as = /mob/living/basic/spider/giant/ambush @@ -27,8 +32,9 @@ /mob/living/basic/spider/growing/young/ambush/Initialize(mapload) . = ..() - var/datum/action/cooldown/mob_cooldown/sneak/spider/sneak_web = new(src) - sneak_web.Grant(src) + + GRANT_ACTION(/datum/action/cooldown/mob_cooldown/sneak/spider) + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/slow_web) /// Will differentiate into the "scout" giant spider. /mob/living/basic/spider/growing/young/scout @@ -66,6 +72,11 @@ speed = 0.5 poison_per_bite = 2 +/mob/living/basic/spider/growing/young/Initialize(mapload) + . = ..() + + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/fast_web) + /// Will differentiate into the "nurse" giant spider. /mob/living/basic/spider/growing/young/nurse grow_as = /mob/living/basic/spider/giant/nurse @@ -98,6 +109,8 @@ complete_text = "%SOURCE% wraps the wounds of %TARGET%.",\ ) + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/average_web) + /// Will differentiate into the "tangle" giant spider. /mob/living/basic/spider/growing/young/tangle grow_as = /mob/living/basic/spider/giant/tangle @@ -122,7 +135,7 @@ heal_brute = 10,\ heal_burn = 10,\ heal_time = 3 SECONDS,\ - self_targetting = HEALING_TOUCH_SELF_ONLY,\ + self_targeting = HEALING_TOUCH_SELF_ONLY,\ interaction_key = DOAFTER_SOURCE_SPIDER,\ valid_targets_typecache = typecacheof(list(/mob/living/basic/spider/growing/young/tangle, /mob/living/basic/spider/giant/tangle)),\ extra_checks = CALLBACK(src, PROC_REF(can_mend)),\ @@ -130,6 +143,8 @@ complete_text = "%SOURCE%'s wounds mend together.",\ ) + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/average_web) + /// Prevent you from healing other tangle spiders, or healing when on fire /mob/living/basic/spider/growing/young/tangle/proc/can_mend(mob/living/source, mob/living/target) if (on_fire) @@ -137,6 +152,64 @@ return FALSE return TRUE + +/// Will differentiate into the "tank" giant spider. +/mob/living/basic/spider/growing/young/tank + grow_as = /mob/living/basic/spider/giant/tank + name = "young tank spider" + desc = "Furry and purple, it looks defenseless. This one has dim yellow eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_tank" + icon_dead = "young_tank_dead" + maxHealth = 50 + health = 50 + damage_coeff = list(BRUTE = 0.5, BURN = 0.5, TOX = 0.5, CLONE = 0.5, STAMINA = 0.5, OXY = 1) + melee_damage_lower = 10 + melee_damage_upper = 15 + speed = 1 + +/mob/living/basic/spider/growing/young/tank/Initialize(mapload) + . = ..() + AddComponent(/datum/component/healing_touch,\ + heal_brute = 5,\ + heal_burn = 5,\ + heal_time = 2 SECONDS,\ + self_targeting = HEALING_TOUCH_SELF_ONLY,\ + interaction_key = DOAFTER_SOURCE_SPIDER,\ + valid_targets_typecache = typecacheof(list(/mob/living/basic/spider/growing/young/tank, /mob/living/basic/spider/giant/tank)),\ + extra_checks = CALLBACK(src, PROC_REF(can_mend)),\ + action_text = "%SOURCE% begins mending themselves...",\ + complete_text = "%SOURCE%'s wounds mend together.",\ + ) + + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/below_average_web) + +/// Prevent you from healing when on fire +/mob/living/basic/spider/growing/young/tank/proc/can_mend(mob/living/source, mob/living/target) + if (on_fire) + balloon_alert(src, "on fire!") + return FALSE + return TRUE + +/// Will differentiate into the "breacher" giant spider. +/mob/living/basic/spider/growing/young/breacher + grow_as = /mob/living/basic/spider/giant/breacher + name = "young breacher spider" + desc = "Furry and baige, it looks defenseless. This one has dim red eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_breacher" + icon_dead = "young_breacher_dead" + maxHealth = 60 + health = 60 + melee_damage_lower = 5 + melee_damage_upper = 10 + speed = 1 + +/mob/living/basic/spider/growing/young/breacher/Initialize(mapload) + . = ..() + + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/below_average_web) + /// Will differentiate into the "midwife" giant spider. /mob/living/basic/spider/growing/young/midwife grow_as = /mob/living/basic/spider/giant/midwife @@ -153,6 +226,11 @@ web_speed = 0.5 web_type = /datum/action/cooldown/mob_cooldown/lay_web/sealer +/mob/living/basic/spider/growing/young/midwife/Initialize(mapload) + . = ..() + + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/average_web) + /// Will differentiate into the "viper" giant spider. /mob/living/basic/spider/growing/young/viper grow_as = /mob/living/basic/spider/giant/viper @@ -183,3 +261,8 @@ melee_damage_upper = 25 speed = 1 obj_damage = 40 + +/mob/living/basic/spider/growing/young/tarantula/Initialize(mapload) + . = ..() + + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/slow_web) diff --git a/code/modules/mob/living/basic/space_fauna/statue/statue.dm b/code/modules/mob/living/basic/space_fauna/statue/statue.dm index d2ea5e8a831d05..801aa271d91f76 100644 --- a/code/modules/mob/living/basic/space_fauna/statue/statue.dm +++ b/code/modules/mob/living/basic/space_fauna/statue/statue.dm @@ -56,14 +56,14 @@ /mob/living/basic/statue/Initialize(mapload, mob/living/creator) . = ..() - AddComponent(/datum/component/unobserved_actor, unobserved_flags = NO_OBSERVED_MOVEMENT | NO_OBSERVED_ATTACKS) ADD_TRAIT(src, TRAIT_UNOBSERVANT, INNATE_TRAIT) + AddComponent(/datum/component/unobserved_actor, unobserved_flags = NO_OBSERVED_MOVEMENT | NO_OBSERVED_ATTACKS) - // Give spells - var/datum/action/cooldown/spell/aoe/flicker_lights/flicker = new(src) - flicker.Grant(src) - var/datum/action/cooldown/spell/aoe/blindness/blind = new(src) - blind.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/spell/aoe/blindness, + /datum/action/cooldown/spell/aoe/flicker_lights, + ) + grant_actions_by_list(innate_actions) // Set creator if(creator) @@ -141,7 +141,7 @@ /datum/ai_controller/basic_controller/statue blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_LOW_PRIORITY_HUNTING_TARGET = null, // lights ) diff --git a/code/modules/mob/living/basic/space_fauna/supermatter_spider.dm b/code/modules/mob/living/basic/space_fauna/supermatter_spider.dm index 2a3ba326eaca95..02fd9ed1bcf1ea 100644 --- a/code/modules/mob/living/basic/space_fauna/supermatter_spider.dm +++ b/code/modules/mob/living/basic/space_fauna/supermatter_spider.dm @@ -82,7 +82,7 @@ /datum/ai_controller/basic_controller/supermatter_spider blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/fugu_gland.dm b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/fugu_gland.dm index 63eb39c74e6fd5..98daeb6d8c232b 100644 --- a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/fugu_gland.dm +++ b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/fugu_gland.dm @@ -15,7 +15,7 @@ if(fugu_blacklist) return fugu_blacklist = typecacheof(list( - /mob/living/simple_animal/hostile/guardian, + /mob/living/basic/guardian, )) /obj/item/fugu_gland/afterattack(atom/target, mob/user, proximity_flag) @@ -38,6 +38,6 @@ animal.melee_damage_lower = max((animal.melee_damage_lower * 2), 10) animal.melee_damage_upper = max((animal.melee_damage_upper * 2), 10) animal.transform *= 2 - animal.AddElement(/datum/element/wall_smasher, strength_flag = ENVIRONMENT_SMASH_RWALLS) + AddElement(/datum/element/wall_tearer) to_chat(user, span_info("You increase the size of [animal], giving [animal.p_them()] a surge of strength!")) qdel(src) diff --git a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm index a9e2b538bdd741..70b3506527a187 100644 --- a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm +++ b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm @@ -58,7 +58,7 @@ RegisterSignal(fugu, COMSIG_MOB_STATCHANGE, PROC_REF(check_death)) fugu.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/inflated) ADD_TRAIT(fugu, TRAIT_FUGU_GLANDED, TRAIT_STATUS_EFFECT(id)) - fugu.AddElement(/datum/element/wall_smasher) + fugu.AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE) fugu.mob_size = MOB_SIZE_LARGE fugu.icon_state = "Fugu1" fugu.melee_damage_lower = 15 @@ -76,7 +76,7 @@ UnregisterSignal(fugu, COMSIG_MOB_STATCHANGE) fugu.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/inflated) REMOVE_TRAIT(fugu, TRAIT_FUGU_GLANDED, TRAIT_STATUS_EFFECT(id)) - fugu.RemoveElement(/datum/element/wall_smasher) + fugu.RemoveElement(/datum/element/wall_tearer, allow_reinforced = FALSE) fugu.mob_size = MOB_SIZE_SMALL fugu.melee_damage_lower = 0 fugu.melee_damage_upper = 0 diff --git a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_ai.dm b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_ai.dm index e405ee3755abf1..1b4e2cdd62019f 100644 --- a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_ai.dm +++ b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_ai.dm @@ -1,7 +1,7 @@ /// Cowardly when small, aggressive when big. Tries to transform whenever possible. /datum/ai_controller/basic_controller/wumborian_fugu blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/trader/trader.dm b/code/modules/mob/living/basic/trader/trader.dm new file mode 100644 index 00000000000000..29a2bda419930f --- /dev/null +++ b/code/modules/mob/living/basic/trader/trader.dm @@ -0,0 +1,79 @@ +/mob/living/basic/trader + name = "Trader" + desc = "Come buy some!" + unique_name = FALSE + icon = 'icons/mob/simple/simple_human.dmi' + maxHealth = 200 + health = 200 + melee_damage_lower = 10 + melee_damage_upper = 10 + attack_verb_continuous = "punches" + attack_verb_simple = "punch" + attack_sound = 'sound/weapons/punch1.ogg' + basic_mob_flags = DEL_ON_DEATH + unsuitable_atmos_damage = 2.5 + combat_mode = FALSE + move_resist = MOVE_FORCE_STRONG + mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + sentience_type = SENTIENCE_HUMANOID + speed = 0 + + ai_controller = /datum/ai_controller/basic_controller/trader + + ///Sound used when item sold/bought + var/sell_sound = 'sound/effects/cashregister.ogg' + ///The currency name + var/currency_name = "credits" + ///The spawner we use to create our look + var/spawner_path = /obj/effect/mob_spawn/corpse/human/generic_assistant + ///Our species to create our look + var/species_path = /datum/species/human + ///The loot we drop when we die + var/loot = list(/obj/effect/mob_spawn/corpse/human/generic_assistant) + ///Casing used to shoot during retaliation + var/ranged_attack_casing = /obj/item/ammo_casing/shotgun/buckshot + ///Sound to make while doing a retalitory attack + var/ranged_attack_sound = 'sound/weapons/gun/pistol/shot.ogg' + ///Weapon path, for visuals + var/held_weapon_visual = /obj/item/gun/ballistic/shotgun + + ///Type path for the trader datum to use for retrieving the traders wares, speech, etc + var/trader_data_path = /datum/trader_data + + +/mob/living/basic/trader/Initialize(mapload) + . = ..() + apply_dynamic_human_appearance(src, species_path = species_path, mob_spawn_path = spawner_path, r_hand = held_weapon_visual) + + var/datum/trader_data/trader_data = new trader_data_path + AddComponent(/datum/component/trader, trader_data = trader_data) + AddComponent(/datum/component/ranged_attacks, casing_type = ranged_attack_casing, projectile_sound = ranged_attack_sound, cooldown_time = 3 SECONDS) + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/ai_swap_combat_mode, BB_BASIC_MOB_CURRENT_TARGET, string_list(trader_data.say_phrases[TRADER_BATTLE_START_PHRASE]), string_list(trader_data.say_phrases[TRADER_BATTLE_END_PHRASE])) + if(LAZYLEN(loot)) + loot = string_list(loot) + AddElement(/datum/element/death_drops, loot) + + var/datum/action/setup_shop/setup_shop = new (src, trader_data.shop_spot_type, trader_data.sign_type, trader_data.sell_sound, trader_data.say_phrases[TRADER_SHOP_OPENING_PHRASE]) + setup_shop.Grant(src) + ai_controller.set_blackboard_key(BB_SETUP_SHOP, setup_shop) + +/mob/living/basic/trader/mrbones + name = "Mr. Bones" + desc = "A skeleton merchant, he seems very humerus." + speak_emote = list("rattles") + speech_span = SPAN_SANS + mob_biotypes = MOB_UNDEAD|MOB_HUMANOID + icon_state = "mrbones" + gender = MALE + + ai_controller = /datum/ai_controller/basic_controller/trader/jumpscare + + sell_sound = 'sound/voice/hiss2.ogg' + species_path = /datum/species/skeleton + spawner_path = /obj/effect/mob_spawn/corpse/human/skeleton/mrbones + loot = list(/obj/effect/decal/remains/human) + ranged_attack_casing = /obj/item/ammo_casing/energy/bolt/halloween + held_weapon_visual = /obj/item/gun/ballistic/revolver + + trader_data_path = /datum/trader_data/mr_bones diff --git a/code/modules/mob/living/basic/trader/trader_actions.dm b/code/modules/mob/living/basic/trader/trader_actions.dm new file mode 100644 index 00000000000000..ded9fbd46d0d57 --- /dev/null +++ b/code/modules/mob/living/basic/trader/trader_actions.dm @@ -0,0 +1,72 @@ +/datum/action/setup_shop + name = "Setup shop" + desc = "Summons a wacky sales sign, and a comfy sitting spot to conduct your business from." + button_icon = 'icons/mob/actions/actions_trader.dmi' + button_icon_state = "setup_shop" + /// The shop spot + var/datum/weakref/shop_spot_ref + /// The server this console is connected to. + var/datum/weakref/sign_ref + /// The type of the chair we sit on + var/shop_spot_type + /// The type of our advertising sign + var/sign_type + /// The sound we make when we summon our shop gear + var/shop_sound + /// Lines we say when we open our shop + var/opening_lines + +/datum/action/setup_shop/IsAvailable(feedback = FALSE) + . = ..() + if (!.) + return FALSE + if(shop_spot_ref?.resolve()) + if(feedback) + owner.balloon_alert(owner, "already set up!") + return FALSE + return TRUE + +/datum/action/setup_shop/New(Target, shop_spot_type = /obj/structure/chair/plastic, sign_type = /obj/structure/trader_sign, sell_sound = 'sound/effects/cashregister.ogg', opening_lines = list("Welcome to my shop, friend!")) + . = ..() + + src.shop_spot_type = shop_spot_type + src.sign_type = sign_type + src.shop_sound = sell_sound + src.opening_lines = opening_lines + +/datum/action/setup_shop/Trigger(trigger_flags) + . = ..() + if(!.) + return + + owner.say(pick(opening_lines)) + var/obj/shop_spot = new shop_spot_type(owner.loc) + shop_spot.dir = owner.dir + shop_spot_ref = WEAKREF(shop_spot) + owner.ai_controller?.set_blackboard_key(BB_SHOP_SPOT, shop_spot) + + playsound(owner, shop_sound, 50, TRUE) + + var/turf/sign_turf + + sign_turf = try_find_valid_spot(owner.loc, turn(shop_spot.dir, -90)) + if(isnull(sign_turf)) //No space to my left, lets try right + sign_turf = try_find_valid_spot(owner.loc, turn(shop_spot.dir, 90)) + + if(isnull(sign_turf)) + return + + var/obj/sign = sign_ref?.resolve() + if(QDELETED(sign)) + var/obj/new_sign = new sign_type(sign_turf) + sign_ref = WEAKREF(sign) + do_sparks(3, FALSE, new_sign) + else + do_teleport(sign,sign_turf) + +///Look for a spot we can place our sign on +/datum/action/setup_shop/proc/try_find_valid_spot(origin_turf, direction_to_check) + var/turf/sign_turf = get_step(origin_turf, direction_to_check) + if(sign_turf && !isgroundlessturf(sign_turf) && !isclosedturf(sign_turf) && !sign_turf.is_blocked_turf()) + return sign_turf + return null diff --git a/code/modules/mob/living/basic/trader/trader_ai.dm b/code/modules/mob/living/basic/trader/trader_ai.dm new file mode 100644 index 00000000000000..5f447ab3229af6 --- /dev/null +++ b/code/modules/mob/living/basic/trader/trader_ai.dm @@ -0,0 +1,95 @@ +/datum/ai_controller/basic_controller/trader + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk/not_while_on_target/trader + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/basic_ranged_attack_subtree/trader, + /datum/ai_planning_subtree/prepare_travel_to_destination/trader, + /datum/ai_planning_subtree/travel_to_point/and_clear_target, + /datum/ai_planning_subtree/setup_shop, + ) + +/datum/ai_controller/basic_controller/trader/jumpscare + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/basic_ranged_attack_subtree/trader, + /datum/ai_planning_subtree/prepare_travel_to_destination/trader, + /datum/ai_planning_subtree/travel_to_point/and_clear_target, + /datum/ai_planning_subtree/setup_shop/jumpscare, + ) + +/datum/ai_planning_subtree/basic_ranged_attack_subtree/trader + ranged_attack_behavior = /datum/ai_behavior/basic_ranged_attack/trader + +/datum/ai_behavior/basic_ranged_attack/trader + action_cooldown = 3 SECONDS + avoid_friendly_fire = TRUE + +///Subtree to find our very first customer and set up our shop after walking right into their face +/datum/ai_planning_subtree/setup_shop + ///What do we do in order to offer our deals? + var/datum/ai_behavior/setup_shop/setup_shop_behavior = /datum/ai_behavior/setup_shop + +/datum/ai_planning_subtree/setup_shop/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + + //If we don't have our ability, return + if(!controller.blackboard_key_exists(BB_SETUP_SHOP)) + return + + //If we already have a shop spot, return + if(controller.blackboard_key_exists(BB_SHOP_SPOT)) + return + + //If we don't have a costurmer to greet, look for one + if(!controller.blackboard_key_exists(BB_FIRST_CUSTOMER)) + controller.queue_behavior(/datum/ai_behavior/find_and_set/conscious_person, BB_FIRST_CUSTOMER, /mob/living/carbon/human) + return + + //We have our first customer, time to tell them about incredible deals + controller.queue_behavior(setup_shop_behavior, BB_FIRST_CUSTOMER) + return SUBTREE_RETURN_FINISH_PLANNING + +///The ai will create a shop the moment they see a potential costumer +/datum/ai_behavior/setup_shop + +/datum/ai_behavior/setup_shop/setup(datum/ai_controller/controller, target_key) + var/obj/target = controller.blackboard[target_key] + return !QDELETED(target) + +/datum/ai_behavior/setup_shop/perform(seconds_per_tick, datum/ai_controller/controller, target_key) + . = ..() + + //We lost track of our costumer or our ability, abort + if(!controller.blackboard_key_exists(target_key) || !controller.blackboard_key_exists(BB_SETUP_SHOP)) + finish_action(controller, FALSE, target_key) + return + + var/datum/action/setup_shop/shop = controller.blackboard[BB_SETUP_SHOP] + shop.Trigger() + + controller.clear_blackboard_key(BB_FIRST_CUSTOMER) + + finish_action(controller, TRUE, target_key) + +/datum/idle_behavior/idle_random_walk/not_while_on_target/trader + target_key = BB_SHOP_SPOT + +///Version of setup show where the trader will run at you to assault you with incredible deals +/datum/ai_planning_subtree/setup_shop/jumpscare + setup_shop_behavior = /datum/ai_behavior/setup_shop/jumpscare + +/datum/ai_behavior/setup_shop/jumpscare + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH + +/datum/ai_behavior/setup_shop/jumpscare/setup(datum/ai_controller/controller, target_key) + . = ..() + if(.) + set_movement_target(controller, controller.blackboard[target_key]) + +/datum/ai_behavior/setup_shop/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + controller.clear_blackboard_key(target_key) diff --git a/code/modules/mob/living/basic/trader/trader_data.dm b/code/modules/mob/living/basic/trader/trader_data.dm new file mode 100644 index 00000000000000..9762dc02be5001 --- /dev/null +++ b/code/modules/mob/living/basic/trader/trader_data.dm @@ -0,0 +1,156 @@ +///Used to contain the traders initial wares, and speech +/datum/trader_data + + ///The item that marks the shopkeeper will sit on + var/shop_spot_type = /obj/structure/chair/plastic + ///The sign that will greet the customers + var/sign_type = /obj/structure/trader_sign + ///Sound used when item sold/bought + var/sell_sound = 'sound/effects/cashregister.ogg' + ///The currency name + var/currency_name = "credits" + ///The initial products that the trader offers + var/list/initial_products = list( + /obj/item/food/burger/ghost = list(PAYCHECK_CREW * 4, INFINITY), + ) + ///The initial products that the trader buys + var/list/initial_wanteds = list( + /obj/item/ectoplasm = list(PAYCHECK_CREW * 2, INFINITY, ""), + ) + ///The speech data of the trader + var/list/say_phrases = list( + ITEM_REJECTED_PHRASE = list( + "Sorry, I'm not a fan of anything you're showing me. Give me something better and we'll talk.", + ), + ITEM_SELLING_CANCELED_PHRASE = list( + "What a shame, tell me if you changed your mind.", + ), + ITEM_SELLING_ACCEPTED_PHRASE = list( + "Pleasure doing business with you.", + ), + INTERESTED_PHRASE = list( + "Hey, you've got an item that interests me, I'd like to buy it, I'll give you some cash for it, deal?", + ), + BUY_PHRASE = list( + "Pleasure doing business with you.", + ), + NO_CASH_PHRASE = list( + "Sorry adventurer, I can't give credit! Come back when you're a little mmmmm... richer!", + ), + NO_STOCK_PHRASE = list( + "Sorry adventurer, but that item is not in stock at the moment.", + ), + NOT_WILLING_TO_BUY_PHRASE = list( + "I don't want to buy that item for the time being, check back another time.", + ), + ITEM_IS_WORTHLESS_PHRASE = list( + "This item seems to be worthless on a closer look, I won't buy this.", + ), + TRADER_HAS_ENOUGH_ITEM_PHRASE = list( + "I already bought enough of this for the time being.", + ), + TRADER_LORE_PHRASE = list( + "Hello! I am the test trader.", + "Oooooooo~!", + ), + TRADER_NOT_BUYING_ANYTHING = list( + "I'm currently buying nothing at the moment.", + ), + TRADER_NOT_SELLING_ANYTHING = list( + "I'm currently selling nothing at the moment.", + ), + TRADER_BATTLE_START_PHRASE = list( + "Thief!", + ), + TRADER_BATTLE_END_PHRASE = list( + "That is a discount I call death.", + ), + TRADER_SHOP_OPENING_PHRASE = list( + "Welcome to my shop, friend!", + ), + ) + +/** + * Depending on the passed parameter/override, returns a randomly picked string out of a list + * + * Do note when overriding this argument, you will need to ensure pick(the list) doesn't get supplied with a list of zero length + * Arguments: + * * say_text - (String) a define that matches the key of a entry in say_phrases + */ +/datum/trader_data/proc/return_trader_phrase(say_text) + if(!length(say_phrases[say_text])) + return + return pick(say_phrases[say_text]) + +/datum/trader_data/mr_bones + shop_spot_type = /obj/structure/chair/wood/wings + sign_type = /obj/structure/trader_sign/mrbones + sell_sound = 'sound/voice/hiss2.ogg' + + initial_products = list( + /obj/item/clothing/head/helmet/skull = list(PAYCHECK_CREW * 3, INFINITY), + /obj/item/clothing/mask/bandana/skull/black = list(PAYCHECK_CREW, INFINITY), + /obj/item/food/cookie/sugar/spookyskull = list(PAYCHECK_CREW * 0.2, INFINITY), + /obj/item/instrument/trombone/spectral = list(PAYCHECK_CREW * 200, INFINITY), + /obj/item/shovel/serrated = list(PAYCHECK_CREW * 3, INFINITY), + ) + + initial_wanteds = list( + /obj/item/reagent_containers/condiment/milk = list(PAYCHECK_CREW * 20, INFINITY, ""), + /obj/item/stack/sheet/bone = list(PAYCHECK_CREW * 8.4, INFINITY, ", per sheet of bone"), + ) + + say_phrases = list( + ITEM_REJECTED_PHRASE = list( + "Sorry, I'm not a fan of anything you're showing me. Give me something better and we'll talk.", + ), + ITEM_SELLING_CANCELED_PHRASE = list( + "What a shame, tell me if you changed your mind.", + ), + ITEM_SELLING_ACCEPTED_PHRASE = list( + "Pleasure doing business with you.", + ), + INTERESTED_PHRASE = list( + "Hey, you've got an item that interests me, I'd like to buy it, I'll give you some cash for it, deal?", + ), + BUY_PHRASE = list( + "Bone appetit!", + ), + NO_CASH_PHRASE = list( + "Sorry adventurer, I can't give credit! Come back when you're a little mmmmm... richer!", + ), + NO_STOCK_PHRASE = list( + "Sorry adventurer, but that item is not in stock at the moment.", + ), + NOT_WILLING_TO_BUY_PHRASE = list( + "I don't want to buy that item for the time being, check back another time.", + ), + ITEM_IS_WORTHLESS_PHRASE = list( + "This item seems to be worthless on a closer look, I won't buy this.", + ), + TRADER_HAS_ENOUGH_ITEM_PHRASE = list( + "I already bought enough of this for the time being.", + ), + TRADER_LORE_PHRASE = list( + "Hello, I am Mr. Bones!", + "The ride never ends!", + "I'd really like a refreshing carton of milk!", + "I'm willing to play big prices for BONES! Need materials to make merch, eh?", + "It's a beautiful day outside. Birds are singing, Flowers are blooming... On days like these, kids like you... Should be buying my wares!", + ), + TRADER_NOT_BUYING_ANYTHING = list( + "I'm currently buying nothing at the moment.", + ), + TRADER_NOT_SELLING_ANYTHING = list( + "I'm currently selling nothing at the moment.", + ), + TRADER_BATTLE_START_PHRASE = list( + "The ride ends for you!", + ), + TRADER_BATTLE_END_PHRASE = list( + "Mr. Bones never misses!", + ), + TRADER_SHOP_OPENING_PHRASE = list( + "My wild ride is open!", + ), + ) diff --git a/code/modules/mob/living/basic/trader/trader_items.dm b/code/modules/mob/living/basic/trader/trader_items.dm new file mode 100644 index 00000000000000..173e33d4c2f623 --- /dev/null +++ b/code/modules/mob/living/basic/trader/trader_items.dm @@ -0,0 +1,36 @@ +///Sale signs +/obj/structure/trader_sign + name = "holographic store sign" + desc = "A holographic sign that promises great deals." + icon = 'icons/obj/trader_signs.dmi' + icon_state = "faceless" + anchored = TRUE + armor_type = /datum/armor/trader_sign + max_integrity = 15 + layer = FLY_LAYER + +/datum/armor/trader_sign + bullet = 50 + laser = 50 + energy = 50 + fire = 20 + acid = 20 + +/obj/structure/trader_sign/Initialize(mapload) + . = ..() + add_overlay("sign") + makeHologram() + + +/obj/structure/trader_sign/mrbones + icon_state = "mrbones" + + +///Spawners for outfits +/obj/effect/mob_spawn/corpse/human/skeleton/mrbones + mob_species = /datum/species/skeleton + outfit = /datum/outfit/mrbonescorpse + +/datum/outfit/mrbonescorpse + name = "Mr Bones' Corpse" + head = /obj/item/clothing/head/hats/tophat diff --git a/code/modules/mob/living/basic/tree.dm b/code/modules/mob/living/basic/tree.dm index 2a0806b105c983..3f3894f190b5e0 100644 --- a/code/modules/mob/living/basic/tree.dm +++ b/code/modules/mob/living/basic/tree.dm @@ -56,7 +56,7 @@ . = ..() AddComponent(/datum/component/seethrough_mob) AddElement(/datum/element/swabable, CELL_LINE_TABLE_PINE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) - var/static/list/death_loot = list(/obj/item/stack/sheet/mineral/wood) + var/list/death_loot = string_list(list(/obj/item/stack/sheet/mineral/wood)) AddElement(/datum/element/death_drops, death_loot) AddComponent(/datum/component/aggro_emote, emote_list = string_list(list("growls")), emote_chance = 20) @@ -100,7 +100,7 @@ /datum/ai_controller/basic_controller/tree blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/code/modules/mob/living/basic/trooper/nanotrasen.dm b/code/modules/mob/living/basic/trooper/nanotrasen.dm index 7dfab5298c2085..6da3d2d9fb21b1 100644 --- a/code/modules/mob/living/basic/trooper/nanotrasen.dm +++ b/code/modules/mob/living/basic/trooper/nanotrasen.dm @@ -34,6 +34,8 @@ cooldown_time = ranged_cooldown,\ burst_shots = burst_shots,\ ) + if (ranged_cooldown <= 1 SECONDS) + AddComponent(/datum/component/ranged_mob_full_auto) /mob/living/basic/trooper/nanotrasen/ranged/smg ai_controller = /datum/ai_controller/basic_controller/trooper/ranged/burst diff --git a/code/modules/mob/living/basic/trooper/pirate.dm b/code/modules/mob/living/basic/trooper/pirate.dm new file mode 100644 index 00000000000000..714fc53856e23b --- /dev/null +++ b/code/modules/mob/living/basic/trooper/pirate.dm @@ -0,0 +1,89 @@ +/// Pirate trooper subtype +/mob/living/basic/trooper/pirate + name = "Pirate" + desc = "Does what he wants cause a pirate is free." + response_help_continuous = "pushes" + response_help_simple = "push" + speed = 0 + speak_emote = list("yarrs") + faction = list(FACTION_PIRATE) + loot = list(/obj/effect/mob_spawn/corpse/human/pirate) + mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate + + /// The amount of money to steal with a melee attack + var/plunder_credits = 25 + +/mob/living/basic/trooper/pirate/Initialize(mapload) + . = ..() + AddComponent(/datum/component/plundering_attacks, plunder_amount = plunder_credits) + +/mob/living/basic/trooper/pirate/melee + name = "Pirate Swashbuckler" + melee_damage_lower = 30 + melee_damage_upper = 30 + armour_penetration = 35 + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" + attack_sound = 'sound/weapons/blade1.ogg' + attack_vis_effect = ATTACK_EFFECT_SLASH + loot = list(/obj/effect/mob_spawn/corpse/human/pirate/melee) + light_range = 2 + light_power = 2.5 + light_color = COLOR_SOFT_RED + loot = list( + /obj/effect/mob_spawn/corpse/human/pirate/melee, + /obj/item/melee/energy/sword/pirate, + ) + mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/melee + r_hand = /obj/item/melee/energy/sword/pirate + plunder_credits = 50 //they hit hard so they steal more + +/mob/living/basic/trooper/pirate/melee/space + name = "Space Pirate Swashbuckler" + unsuitable_atmos_damage = 0 + minimum_survivable_temperature = 0 + speed = 1 + loot = list(/obj/effect/mob_spawn/corpse/human/pirate/melee/space) + mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/melee/space + +/mob/living/basic/trooper/pirate/melee/space/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) + +/mob/living/basic/trooper/pirate/ranged + name = "Pirate Gunner" + loot = list(/obj/effect/mob_spawn/corpse/human/pirate/ranged) + mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/ranged + r_hand = /obj/item/gun/energy/laser + ai_controller = /datum/ai_controller/basic_controller/trooper/ranged + /// Type of bullet we use + var/casingtype = /obj/item/ammo_casing/energy/laser + /// Sound to play when firing weapon + var/projectilesound = 'sound/weapons/laser.ogg' + /// number of burst shots + var/burst_shots = 2 + /// Time between taking shots + var/ranged_cooldown = 6 SECONDS + +/mob/living/basic/trooper/pirate/ranged/Initialize(mapload) + . = ..() + AddComponent(\ + /datum/component/ranged_attacks,\ + casing_type = casingtype,\ + projectile_sound = projectilesound,\ + cooldown_time = ranged_cooldown,\ + burst_shots = burst_shots,\ + ) + +/mob/living/basic/trooper/pirate/ranged/space + name = "Space Pirate Gunner" + unsuitable_atmos_damage = 0 + minimum_survivable_temperature = 0 + speed = 1 + loot = list(/obj/effect/mob_spawn/corpse/human/pirate/ranged/space) + mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/ranged/space + r_hand = /obj/item/gun/energy/e_gun/lethal + +/mob/living/basic/trooper/pirate/ranged/space/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) diff --git a/code/modules/mob/living/basic/trooper/syndicate.dm b/code/modules/mob/living/basic/trooper/syndicate.dm index 43242649193d5e..76ad808ceb38c1 100644 --- a/code/modules/mob/living/basic/trooper/syndicate.dm +++ b/code/modules/mob/living/basic/trooper/syndicate.dm @@ -3,8 +3,6 @@ name = "Syndicate Operative" desc = "Death to Nanotrasen." speed = 1.1 - melee_damage_lower = 10 - melee_damage_upper = 10 faction = list(ROLE_SYNDICATE) loot = list(/obj/effect/mob_spawn/corpse/human/syndicatesoldier) mob_spawner = /obj/effect/mob_spawn/corpse/human/syndicatesoldier @@ -123,6 +121,8 @@ cooldown_time = ranged_cooldown,\ burst_shots = burst_shots,\ ) + if (ranged_cooldown <= 1 SECONDS) + AddComponent(/datum/component/ranged_mob_full_auto) /mob/living/basic/trooper/syndicate/ranged/infiltrator //shuttle loan event projectilesound = 'sound/weapons/gun/smg/shot_suppressed.ogg' diff --git a/code/modules/mob/living/basic/trooper/trooper_ai.dm b/code/modules/mob/living/basic/trooper/trooper_ai.dm index 3b89807ea62c28..cf71b38f45b537 100644 --- a/code/modules/mob/living/basic/trooper/trooper_ai.dm +++ b/code/modules/mob/living/basic/trooper/trooper_ai.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/trooper blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = HARD_CRIT, BB_REINFORCEMENTS_SAY = "411 in progress, requesting backup!" ) @@ -90,10 +90,10 @@ /datum/ai_behavior/basic_ranged_attack/trooper_shotgun action_cooldown = 3 SECONDS - required_distance = 1 + required_distance = 3 avoid_friendly_fire = TRUE /datum/ai_controller/basic_controller/trooper/viscerator blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) diff --git a/code/modules/mob/living/basic/vermin/cockroach.dm b/code/modules/mob/living/basic/vermin/cockroach.dm index 639a9720dbce30..595ef0b37d7f3d 100644 --- a/code/modules/mob/living/basic/vermin/cockroach.dm +++ b/code/modules/mob/living/basic/vermin/cockroach.dm @@ -60,8 +60,8 @@ /datum/ai_controller/basic_controller/cockroach blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, ) ai_traits = STOP_MOVING_WHEN_PULLED @@ -106,6 +106,8 @@ burst_shots = burst_shots,\ cooldown_time = ranged_cooldown,\ ) + if (ranged_cooldown <= 1 SECONDS) + AddComponent(/datum/component/ranged_mob_full_auto) /datum/ai_controller/basic_controller/cockroach/glockroach planning_subtrees = list( diff --git a/code/modules/mob/living/basic/vermin/crab.dm b/code/modules/mob/living/basic/vermin/crab.dm index bb81fd29c4d500..3dd3d0db0fea1f 100644 --- a/code/modules/mob/living/basic/vermin/crab.dm +++ b/code/modules/mob/living/basic/vermin/crab.dm @@ -78,8 +78,8 @@ /datum/ai_controller/basic_controller/crab blackboard = list( BB_ALWAYS_IGNORE_FACTION = TRUE, - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/of_size/ours_or_smaller, - BB_FLEE_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/of_size/ours_or_smaller, + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED @@ -92,4 +92,5 @@ /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/random_speech/crab, + /datum/ai_planning_subtree/go_for_swim, ) diff --git a/code/modules/mob/living/basic/vermin/frog.dm b/code/modules/mob/living/basic/vermin/frog.dm index 7ff5260ccb762a..162848d062a45b 100644 --- a/code/modules/mob/living/basic/vermin/frog.dm +++ b/code/modules/mob/living/basic/vermin/frog.dm @@ -75,10 +75,27 @@ if(L.mob_size > MOB_SIZE_TINY) playsound(src, stepped_sound, 50, TRUE) +/mob/living/basic/frog/frog_suicide + name = "suicide frog" + desc = "Driven by sheer will." + icon_state = "frog_trash" + icon_living = "frog_trash" + icon_dead = "frog_trash_dead" + maxHealth = 5 + health = 5 + ai_controller = /datum/ai_controller/basic_controller/frog/suicide_frog + ///how long do we exist for + var/existence_period = 15 SECONDS + +/mob/living/basic/frog/frog_suicide/Initialize(mapload) + . = ..() + AddComponent(/datum/component/explode_on_attack, mob_type_dont_bomb = typecacheof(list(/mob/living/basic/frog, /mob/living/basic/leaper))) + addtimer(CALLBACK(src, PROC_REF(death)), existence_period) + /datum/ai_controller/basic_controller/frog blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, ) ai_movement = /datum/ai_movement/basic_avoidance @@ -87,6 +104,7 @@ /datum/ai_planning_subtree/target_retaliate, /datum/ai_planning_subtree/random_speech/frog, /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/go_for_swim, ) /datum/ai_controller/basic_controller/frog/trash @@ -96,3 +114,9 @@ /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/basic_melee_attack_subtree, ) + +/datum/ai_controller/basic_controller/frog/suicide_frog + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) diff --git a/code/modules/mob/living/basic/vermin/lizard.dm b/code/modules/mob/living/basic/vermin/lizard.dm index d1a30826f4ac4e..760dfecc28fff7 100644 --- a/code/modules/mob/living/basic/vermin/lizard.dm +++ b/code/modules/mob/living/basic/vermin/lizard.dm @@ -55,7 +55,7 @@ /datum/ai_controller/basic_controller/lizard blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, ) ai_traits = STOP_MOVING_WHEN_PULLED diff --git a/code/modules/mob/living/basic/vermin/mouse.dm b/code/modules/mob/living/basic/vermin/mouse.dm index 2929085fb939f2..c1ba3c12e364b0 100644 --- a/code/modules/mob/living/basic/vermin/mouse.dm +++ b/code/modules/mob/living/basic/vermin/mouse.dm @@ -379,7 +379,7 @@ blackboard = list( // Always cowardly BB_CURRENT_HUNTING_TARGET = null, // cheese BB_LOW_PRIORITY_HUNTING_TARGET = null, // cable - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), // Use this to find people to run away from + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, // Use this to find people to run away from BB_BASIC_MOB_FLEE_DISTANCE = 3, ) @@ -411,8 +411,8 @@ /// AI controller for rats, slightly more complex than mice becuase they attack people /datum/ai_controller/basic_controller/mouse/rat blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, BB_BASIC_MOB_CURRENT_TARGET = null, // heathen BB_CURRENT_HUNTING_TARGET = null, // cheese BB_LOW_PRIORITY_HUNTING_TARGET = null, // cable diff --git a/code/modules/mob/living/basic/vermin/space_bat.dm b/code/modules/mob/living/basic/vermin/space_bat.dm index 232febf0f97d24..24718c8481acdb 100644 --- a/code/modules/mob/living/basic/vermin/space_bat.dm +++ b/code/modules/mob/living/basic/vermin/space_bat.dm @@ -42,7 +42,7 @@ ///Controller for space bats, has nothing unique, just retaliation. /datum/ai_controller/basic_controller/space_bat blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_traits = STOP_MOVING_WHEN_PULLED diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm index a2473ce574e78f..1ba926a210e0c8 100644 --- a/code/modules/mob/living/brain/posibrain.dm +++ b/code/modules/mob/living/brain/posibrain.dm @@ -43,7 +43,15 @@ GLOBAL_VAR(posibrain_notify_cooldown) ///Notify ghosts that the posibrain is up for grabs /obj/item/mmi/posibrain/proc/ping_ghosts(msg, newlymade) if(newlymade || GLOB.posibrain_notify_cooldown <= world.time) - notify_ghosts("[name] [msg] in [get_area(src)]! [ask_role ? "Personality requested: \[[ask_role]\]" : ""]", ghost_sound = !newlymade ? 'sound/effects/ghost2.ogg':null, notify_volume = 75, source = src, action = NOTIFY_PLAY, flashwindow = FALSE, ignore_key = POLL_IGNORE_POSIBRAIN, notify_suiciders = FALSE) + notify_ghosts( + "[name] [msg] in [get_area(src)]! [ask_role ? "Personality requested: \[[ask_role]\]" : ""]", + ghost_sound = !newlymade ? 'sound/effects/ghost2.ogg':null, + notify_volume = 75, + source = src, + action = NOTIFY_PLAY, + notify_flags = (GHOST_NOTIFY_IGNORE_MAPLOAD), + ignore_key = POLL_IGNORE_POSIBRAIN, + ) if(!newlymade) GLOB.posibrain_notify_cooldown = world.time + ask_delay diff --git a/code/modules/mob/living/carbon/alien/adult/caste/drone.dm b/code/modules/mob/living/carbon/alien/adult/caste/drone.dm index 3a1843dd93c23d..ff208baabd2296 100644 --- a/code/modules/mob/living/carbon/alien/adult/caste/drone.dm +++ b/code/modules/mob/living/carbon/alien/adult/caste/drone.dm @@ -6,8 +6,7 @@ icon_state = "aliend" /mob/living/carbon/alien/adult/drone/Initialize(mapload) - var/datum/action/cooldown/alien/evolve_to_praetorian/evolution = new(src) - evolution.Grant(src) + GRANT_ACTION(/datum/action/cooldown/alien/evolve_to_praetorian) return ..() /mob/living/carbon/alien/adult/drone/create_internal_organs() diff --git a/code/modules/mob/living/carbon/alien/adult/caste/praetorian.dm b/code/modules/mob/living/carbon/alien/adult/caste/praetorian.dm index a26eb31231c034..8fa142a38f05f6 100644 --- a/code/modules/mob/living/carbon/alien/adult/caste/praetorian.dm +++ b/code/modules/mob/living/carbon/alien/adult/caste/praetorian.dm @@ -9,11 +9,12 @@ /mob/living/carbon/alien/adult/royal/praetorian/Initialize(mapload) real_name = name - var/datum/action/cooldown/spell/aoe/repulse/xeno/tail_whip = new(src) - tail_whip.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/alien/evolve_to_queen, + /datum/action/cooldown/spell/aoe/repulse/xeno, + ) - var/datum/action/cooldown/alien/evolve_to_queen/evolution = new(src) - evolution.Grant(src) + grant_actions_by_list(innate_actions) return ..() diff --git a/code/modules/mob/living/carbon/alien/adult/caste/sentinel.dm b/code/modules/mob/living/carbon/alien/adult/caste/sentinel.dm index 7fffdf35522c76..bef621905f4422 100644 --- a/code/modules/mob/living/carbon/alien/adult/caste/sentinel.dm +++ b/code/modules/mob/living/carbon/alien/adult/caste/sentinel.dm @@ -7,8 +7,7 @@ alien_speed = 0.2 /mob/living/carbon/alien/adult/sentinel/Initialize(mapload) - var/datum/action/cooldown/mob_cooldown/sneak/alien/sneaky_beaky = new(src) - sneaky_beaky.Grant(src) + GRANT_ACTION(/datum/action/cooldown/mob_cooldown/sneak/alien) return ..() /mob/living/carbon/alien/adult/sentinel/create_internal_organs() diff --git a/code/modules/mob/living/carbon/alien/adult/queen.dm b/code/modules/mob/living/carbon/alien/adult/queen.dm index dd8e61b6699fc2..df03ce3fa9eae8 100644 --- a/code/modules/mob/living/carbon/alien/adult/queen.dm +++ b/code/modules/mob/living/carbon/alien/adult/queen.dm @@ -55,11 +55,11 @@ real_name = src.name - var/datum/action/cooldown/spell/aoe/repulse/xeno/tail_whip = new(src) - tail_whip.Grant(src) - - var/datum/action/cooldown/alien/promote/promotion = new(src) - promotion.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/alien/promote, + /datum/action/cooldown/spell/aoe/repulse/xeno, + ) + grant_actions_by_list(innate_actions) return ..() diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 0b1396520b3218..f4159813ed9bc7 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -31,10 +31,12 @@ //This is fine right now, if we're adding organ specific damage this needs to be updated /mob/living/carbon/alien/larva/Initialize(mapload) - var/datum/action/cooldown/alien/larva_evolve/evolution = new(src) - evolution.Grant(src) - var/datum/action/cooldown/alien/hide/hide = new(src) - hide.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/alien/hide, + /datum/action/cooldown/alien/larva_evolve, + ) + grant_actions_by_list(innate_actions) + return ..() /mob/living/carbon/alien/larva/create_internal_organs() diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 35dffd7c27ea93..28b7caa16fddf7 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -259,6 +259,8 @@ /mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 1 MINUTES, cuff_break = 0) + if((cuff_break != INSTANT_CUFFBREAK) && (SEND_SIGNAL(src, COMSIG_MOB_REMOVING_CUFFS, I) & COMSIG_MOB_BLOCK_CUFF_REMOVAL)) + return //The blocking object should sent a fluff-appropriate to_chat about cuff removal being blocked if(I.item_flags & BEING_REMOVED) to_chat(src, span_warning("You're already attempting to remove [I]!")) return diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm index 6ecc62b04981d9..e8a9f5bd46728f 100644 --- a/code/modules/mob/living/carbon/damage_procs.dm +++ b/code/modules/mob/living/carbon/damage_procs.dm @@ -28,6 +28,12 @@ return . +/mob/living/carbon/human/get_damage_mod(damage_type) + if (!dna?.species?.damage_modifier) + return ..() + var/species_mod = (100 - dna.species.damage_modifier) / 100 + return ..() * species_mod + /mob/living/carbon/human/apply_damage( damage = 0, damagetype = BRUTE, diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index f443d57b271538..f9dc29af278056 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -132,8 +132,6 @@ GLOBAL_LIST_EMPTY(features_by_species) /// A path to an outfit that is important for species life e.g. plasmaman outfit var/datum/outfit/outfit_important_for_life - //Dictates which wing icons are allowed for a given species. If count is >1 a radial menu is used to choose between all icons in list - var/list/wing_types = list(/obj/item/organ/external/wings/functional/angel) /// The natural temperature for a body var/bodytemp_normal = BODYTEMP_NORMAL /// Minimum amount of kelvin moved toward normal body temperature per tick. @@ -205,8 +203,6 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/New() - wing_types = string_list(wing_types) - if(!plural_form) plural_form = "[name]\s" if(!examine_limb_id) @@ -883,9 +879,6 @@ GLOBAL_LIST_EMPTY(features_by_species) if(HAS_TRAIT(H, TRAIT_NOBREATH) && (H.health < H.crit_threshold) && !HAS_TRAIT(H, TRAIT_NOCRITDAMAGE)) H.adjustBruteLoss(0.5 * seconds_per_tick) -/datum/species/proc/spec_death(gibbed, mob/living/carbon/human/H) - return - /datum/species/proc/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action = FALSE) if(no_equip_flags & slot) if(!I.species_exception || !is_type_in_list(src, I.species_exception)) @@ -1260,10 +1253,6 @@ GLOBAL_LIST_EMPTY(features_by_species) return FALSE user.disarm(target) - -/datum/species/proc/spec_hitby(atom/movable/AM, mob/living/carbon/human/H) - return - /datum/species/proc/spec_attack_hand(mob/living/carbon/human/owner, mob/living/carbon/human/target, datum/martial_art/attacker_style, modifiers) if(!istype(owner)) return diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 3c0ffb2536b790..3de70b2e01d0c9 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -30,9 +30,6 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift) if(client && !HAS_TRAIT(src, TRAIT_SUICIDED) && !(client in GLOB.dead_players_during_shift)) GLOB.dead_players_during_shift += client - if(!QDELETED(dna)) //The gibbed param is bit redundant here since dna won't exist at this point if they got deleted. - dna.species.spec_death(gibbed, src) - if(SSticker.HasRoundStarted()) SSblackbox.ReportDeath(src) log_message("has died (BRUTE: [src.getBruteLoss()], BURN: [src.getFireLoss()], TOX: [src.getToxLoss()], OXY: [src.getOxyLoss()], CLONE: [src.getCloneLoss()])", LOG_ATTACK) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 90cee5fce9bfe1..692dc52c798cb5 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -119,6 +119,7 @@ message = "salutes." message_param = "salutes to %t." hands_use_check = TRUE + sound = 'sound/misc/salute.ogg' /datum/emote/living/carbon/human/shrug key = "shrug" diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 860e8392dd40ca..da1a9332ab8beb 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -10,7 +10,7 @@ var/obj/item/bodypart/affecting = get_bodypart(check_zone(def_zone)) if(affecting) return check_armor(affecting, type) - //If a specific bodypart is targetted, check how that bodypart is protected and return the value. + //If a specific bodypart is targeted, check how that bodypart is protected and return the value. //If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values for(var/X in bodyparts) @@ -122,10 +122,6 @@ return FALSE /mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) - if(dna?.species) - var/spec_return = dna.species.spec_hitby(AM, src) - if(spec_return) - return spec_return var/obj/item/I var/damage_type = BRUTE var/throwpower = 30 diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index a6f6a484afcda3..47617890bcc26a 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -4,7 +4,6 @@ examine_limb_id = SPECIES_HUMAN inherent_traits = list( TRAIT_NO_UNDERWEAR, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_GENELESS, TRAIT_LIMBATTACHMENT, TRAIT_NOBREATH, @@ -36,7 +35,6 @@ mutanteyes = /obj/item/organ/internal/eyes/robotic mutantears = /obj/item/organ/internal/ears/cybernetic species_language_holder = /datum/language_holder/synthetic - wing_types = list(/obj/item/organ/external/wings/functional/robotic) changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT bodypart_overrides = list( diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 61647c5aba23cf..4773cf769ada5f 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -13,7 +13,6 @@ ) */ // SKYRAT EDIT REMOVAL END inherent_traits = list( - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_HATED_BY_DOGS, TRAIT_USES_SKINTONES, ) diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm index c2c73becdecf84..44e8981c553151 100644 --- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm @@ -3,7 +3,6 @@ plural_form = "Flypeople" id = SPECIES_FLYPERSON inherent_traits = list( - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_TACKLING_FRAIL_ATTACKER, TRAIT_ANTENNAE, ) @@ -12,7 +11,6 @@ mutanteyes = /obj/item/organ/internal/eyes/fly changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT species_language_holder = /datum/language_holder/fly - wing_types = list(/obj/item/organ/external/wings/functional/fly) payday_modifier = 1.0 mutanttongue = /obj/item/organ/internal/tongue/fly diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index 9db5a3253eb60d..b169beba940508 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -2,7 +2,6 @@ name = "\improper Human" id = SPECIES_HUMAN inherent_traits = list( - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_USES_SKINTONES, ) mutant_bodyparts = list("wings" = "None") diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 2f5c977110a351..1708220cbf0ac4 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -215,6 +215,7 @@ // so if someone mindswapped into them, they'd still be shared. bodies = null C.blood_volume = min(C.blood_volume, BLOOD_VOLUME_NORMAL) + UnregisterSignal(C, COMSIG_LIVING_DEATH) ..() /datum/species/jelly/slime/on_species_gain(mob/living/carbon/C, datum/species/old_species) @@ -230,20 +231,25 @@ else bodies |= C -/datum/species/jelly/slime/spec_death(gibbed, mob/living/carbon/human/H) - if(slime_split) - if(!H.mind || !H.mind.active) - return + RegisterSignal(C, COMSIG_LIVING_DEATH, PROC_REF(on_death_move_body)) - var/list/available_bodies = (bodies - H) - for(var/mob/living/L in available_bodies) - if(!swap_body.can_swap(L)) - available_bodies -= L +/datum/species/jelly/slime/proc/on_death_move_body(mob/living/carbon/human/source, gibbed) + SIGNAL_HANDLER - if(!LAZYLEN(available_bodies)) - return + if(!slime_split) + return + if(!source.mind?.active) + return + + var/list/available_bodies = bodies - source + for(var/mob/living/other_body as anything in available_bodies) + if(!swap_body.can_swap(other_body)) + available_bodies -= other_body + + if(!length(available_bodies)) + return - swap_body.swap_to_dupe(H.mind, pick(available_bodies)) + swap_body.swap_to_dupe(source.mind, pick(available_bodies)) //If you're cloned you get your body pool back /datum/species/jelly/slime/copy_properties_from(datum/species/jelly/slime/old_species) diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 020cd7b4ebf89b..5f91cbb2830ba9 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -5,7 +5,6 @@ id = SPECIES_LIZARD inherent_traits = list( TRAIT_MUTANT_COLORS, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_TACKLING_TAILED_DEFENDER, ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE @@ -28,7 +27,6 @@ exotic_bloodtype = "L" inert_mutation = /datum/mutation/human/firebreath death_sound = 'sound/voice/lizard/deathsound.ogg' - wing_types = list(/obj/item/organ/external/wings/functional/dragon) species_language_holder = /datum/language_holder/lizard digitigrade_customization = DIGITIGRADE_OPTIONAL diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index d8d49f7958f1f7..df816fbca359d4 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -4,7 +4,6 @@ id = SPECIES_MOTH inherent_traits = list( TRAIT_HAS_MARKINGS, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_TACKLING_WINGED_ATTACKER, TRAIT_ANTENNAE, ) @@ -17,7 +16,6 @@ changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT species_language_holder = /datum/language_holder/moth death_sound = 'sound/voice/moth/moth_death.ogg' - wing_types = list(/obj/item/organ/external/wings/functional/moth/megamoth, /obj/item/organ/external/wings/functional/moth/mothra) payday_modifier = 1.0 family_heirlooms = list(/obj/item/flashlight/lantern/heirloom_moth) diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index 67051c20607252..a63afeeea29a55 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -6,7 +6,6 @@ meat = /obj/item/food/meat/slab/human/mutant/skeleton inherent_traits = list( TRAIT_NO_UNDERWEAR, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_EASYDISMEMBER, TRAIT_FAKEDEATH, TRAIT_GENELESS, @@ -32,7 +31,6 @@ mutantheart = null mutantliver = /obj/item/organ/internal/liver/bone mutantlungs = null - wing_types = list(/obj/item/organ/external/wings/functional/skeleton) //They can technically be in an ERT changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN species_cookie = /obj/item/reagent_containers/condiment/milk diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 54382dcf021765..14c4c4d1c15205 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -174,26 +174,6 @@ if(!HAS_TRAIT(carbon_mob, TRAIT_CRITICAL_CONDITION) && SPT_PROB(2, seconds_per_tick)) playsound(carbon_mob, pick(spooks), 50, TRUE, 10) -//Congrats you somehow died so hard you stopped being a zombie -/datum/species/zombie/infectious/spec_death(gibbed, mob/living/carbon/C) - . = ..() - var/obj/item/organ/internal/zombie_infection/infection - infection = C.get_organ_slot(ORGAN_SLOT_ZOMBIE) - if(infection) - qdel(infection) - -/datum/species/zombie/infectious/on_species_gain(mob/living/carbon/C, datum/species/old_species) - . = ..() - - // Deal with the source of this zombie corruption - // Infection organ needs to be handled separately from mutant_organs - // because it persists through species transitions - var/obj/item/organ/internal/zombie_infection/infection - infection = C.get_organ_slot(ORGAN_SLOT_ZOMBIE) - if(!infection) - infection = new() - infection.Insert(C) - // Your skin falls off /datum/species/human/krokodil_addict name = "\improper Krokodil Human" diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 41eb7bb06f4ddf..35b1a2c064fbd1 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -262,6 +262,17 @@ return TRUE +/// Returns a multiplier to apply to a specific kind of damage +/mob/living/proc/get_damage_mod(damage_type) + switch(damage_type) + if (OXY) + return HAS_TRAIT(src, TRAIT_NOBREATH) ? 0 : 1 + if (TOX) + if (HAS_TRAIT(src, TRAIT_TOXINLOVER)) + return -1 + return HAS_TRAIT(src, TRAIT_TOXIMMUNE) ? 0 : 1 + return 1 + /mob/living/proc/getBruteLoss() return bruteloss diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index be71ef5c35042d..a434f89408292c 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -575,7 +575,7 @@ if(!isliving(user)) return - if(!TIMER_COOLDOWN_CHECK(user, COOLDOWN_YAWN_PROPAGATION)) + if(TIMER_COOLDOWN_FINISHED(user, COOLDOWN_YAWN_PROPAGATION)) TIMER_COOLDOWN_START(user, COOLDOWN_YAWN_PROPAGATION, cooldown * 3) var/mob/living/carbon/carbon_user = user @@ -585,7 +585,7 @@ var/propagation_distance = user.client ? 5 : 2 // mindless mobs are less able to spread yawns for(var/mob/living/iter_living in view(user, propagation_distance)) - if(IS_DEAD_OR_INCAP(iter_living) || TIMER_COOLDOWN_CHECK(iter_living, COOLDOWN_YAWN_PROPAGATION)) + if(IS_DEAD_OR_INCAP(iter_living) || TIMER_COOLDOWN_RUNNING(iter_living, COOLDOWN_YAWN_PROPAGATION)) continue var/dist_between = get_dist(user, iter_living) @@ -604,7 +604,7 @@ /// This yawn has been triggered by someone else yawning specifically, likely after a delay. Check again if they don't have the yawned recently trait /datum/emote/living/yawn/proc/propagate_yawn(mob/user) - if(!istype(user) || TIMER_COOLDOWN_CHECK(user, COOLDOWN_YAWN_PROPAGATION)) + if(!istype(user) || TIMER_COOLDOWN_RUNNING(user, COOLDOWN_YAWN_PROPAGATION)) return user.emote("yawn") diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index fc847ebc4750b8..190a6ea2b95272 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1611,9 +1611,9 @@ GLOBAL_LIST_EMPTY(fire_appearances) return fire_status.ignite(silent) /mob/living/proc/update_fire() - var/datum/status_effect/fire_handler/fire_handler = has_status_effect(/datum/status_effect/fire_handler) - if(fire_handler) - fire_handler.update_overlay() + var/datum/status_effect/fire_handler/fire_stacks/fire_stacks = has_status_effect(/datum/status_effect/fire_handler/fire_stacks) + if(fire_stacks) + fire_stacks.update_overlay() /** * Extinguish all fire on the mob @@ -2562,7 +2562,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) /mob/living/proc/compare_sentience_type(compare_type) return FALSE -/// Proc called when targetted by a lazarus injector +/// Proc called when TARGETED by a lazarus injector /mob/living/proc/lazarus_revive(mob/living/reviver, malfunctioning) revive(HEAL_ALL) befriend(reviver) @@ -2576,7 +2576,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) lazarus_policy = get_policy(ROLE_LAZARUS_BAD) || "You have been revived by a malfunctioning lazarus injector! You are now enslaved by whoever revived you." to_chat(src, span_boldnotice(lazarus_policy)) -/// Proc for giving a mob a new 'friend', generally used for AI control and targetting. Returns false if already friends. +/// Proc for giving a mob a new 'friend', generally used for AI control and targeting. Returns false if already friends. /mob/living/proc/befriend(mob/living/new_friend) SHOULD_CALL_PARENT(TRUE) var/friend_ref = REF(new_friend) @@ -2636,14 +2636,10 @@ GLOBAL_LIST_EMPTY(fire_appearances) return var/del_mob = FALSE var/mob/old_mob - var/ai_control = FALSE - var/list/possible_players = list("None", "Poll Ghosts") + sort_list(GLOB.clients) + var/list/possible_players = list("Poll Ghosts") + sort_list(GLOB.clients) var/client/guardian_client = tgui_input_list(admin, "Pick the player to put in control.", "Guardian Controller", possible_players) - if(!guardian_client) + if(isnull(guardian_client)) return - else if(guardian_client == "None") - guardian_client = null - ai_control = (tgui_alert(admin, "Do you want to give the spirit AI control?", "Guardian Controller", list("Yes", "No")) == "Yes") else if(guardian_client == "Poll Ghosts") var/list/candidates = poll_ghost_candidates("Do you want to play as an admin created Guardian Spirit of [real_name]?", ROLE_PAI, FALSE, 100, POLL_IGNORE_HOLOPARASITE) if(LAZYLEN(candidates)) @@ -2656,7 +2652,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) old_mob = guardian_client.mob if(isobserver(old_mob) || tgui_alert(admin, "Do you want to delete [guardian_client]'s old mob?", "Guardian Controller", list("Yes"," No")) == "Yes") del_mob = TRUE - var/picked_type = tgui_input_list(admin, "Pick the guardian type.", "Guardian Controller", subtypesof(/mob/living/simple_animal/hostile/guardian)) + var/picked_type = tgui_input_list(admin, "Pick the guardian type.", "Guardian Controller", subtypesof(/mob/living/basic/guardian)) var/picked_theme = tgui_input_list(admin, "Pick the guardian theme.", "Guardian Controller", list(GUARDIAN_THEME_TECH, GUARDIAN_THEME_MAGIC, GUARDIAN_THEME_CARP, GUARDIAN_THEME_MINER, "Random")) if(picked_theme == "Random") picked_theme = null //holopara code handles not having a theme by giving a random one @@ -2664,20 +2660,16 @@ GLOBAL_LIST_EMPTY(fire_appearances) var/picked_color = input(admin, "Set the guardian's color, cancel to let player set it.", "Guardian Controller", "#ffffff") as color|null if(tgui_alert(admin, "Confirm creation.", "Guardian Controller", list("Yes", "No")) != "Yes") return - var/mob/living/simple_animal/hostile/guardian/summoned_guardian = new picked_type(src, picked_theme) + var/mob/living/basic/guardian/summoned_guardian = new picked_type(src, picked_theme) summoned_guardian.set_summoner(src, different_person = TRUE) if(picked_name) summoned_guardian.fully_replace_character_name(null, picked_name) if(picked_color) - summoned_guardian.set_guardian_color(picked_color) + summoned_guardian.set_guardian_colour(picked_color) summoned_guardian.key = guardian_client?.key guardian_client?.init_verbs() if(del_mob) qdel(old_mob) - if(ai_control) - summoned_guardian.can_have_ai = TRUE - summoned_guardian.toggle_ai(AI_ON) - summoned_guardian.manifest() message_admins(span_adminnotice("[key_name_admin(admin)] gave a guardian spirit controlled by [guardian_client || "AI"] to [src].")) log_admin("[key_name(admin)] gave a guardian spirit controlled by [guardian_client] to [src].") SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Guardian Spirit") diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index ffa6c8ce264a6e..3f5dd6f3340b15 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -490,11 +490,11 @@ if(1) new /mob/living/basic/construct/juggernaut/hostile(get_turf(src)) if(2) - new /mob/living/simple_animal/hostile/construct/wraith/hostile(get_turf(src)) + new /mob/living/basic/construct/wraith/hostile(get_turf(src)) if(3) new /mob/living/basic/construct/artificer/hostile(get_turf(src)) if(4) - new /mob/living/simple_animal/hostile/construct/proteon/hostile(get_turf(src)) + new /mob/living/basic/construct/proteon/hostile(get_turf(src)) spawn_dust() investigate_log("has been gibbed by Nar'Sie.", INVESTIGATE_DEATHS) gib() diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 5b2f0fc020bf7d..bbc4a75ede2fff 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -225,6 +225,3 @@ /// What our current gravity state is. Used to avoid duplicate animates and such var/gravity_state = null - - /// Whether this mob can be mutated into a cybercop via quantum server get_valid_domain_targets(). Specifically dodges megafauna - var/can_be_cybercop = TRUE diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm index 52daa3c2f0ab92..f4c1772721c052 100644 --- a/code/modules/mob/living/living_say.dm +++ b/code/modules/mob/living/living_say.dm @@ -147,7 +147,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( say_dead(original_message) return - if(HAS_TRAIT(src, TRAIT_SOFTSPOKEN)) + if(HAS_TRAIT(src, TRAIT_SOFTSPOKEN) && !HAS_TRAIT(src, TRAIT_SIGN_LANG)) // softspoken trait only applies to spoken languages message_mods[WHISPER_MODE] = MODE_WHISPER if(client && SSlag_switch.measures[SLOWMODE_SAY] && !HAS_TRAIT(src, TRAIT_BYPASS_MEASURES) && !forced && src == usr) diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm index 59d08fe7339e04..98d34fc2f711ee 100644 --- a/code/modules/mob/living/simple_animal/bot/firebot.dm +++ b/code/modules/mob/living/simple_animal/bot/firebot.dm @@ -119,7 +119,7 @@ if(!(bot_cover_flags & BOT_COVER_EMAGGED)) return - to_chat(user, span_warning("You enable the very ironically named \"fighting with fire\" mode, and disable the targetting safeties.")) // heheehe. funny + to_chat(user, span_warning("You enable the very ironically named \"fighting with fire\" mode, and disable the targeting safeties.")) // heheehe. funny audible_message(span_danger("[src] buzzes oddly!")) playsound(src, SFX_SPARKS, 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) diff --git a/code/modules/mob/living/simple_animal/damage_procs.dm b/code/modules/mob/living/simple_animal/damage_procs.dm index 9640dbb9de4403..d92478907a1c05 100644 --- a/code/modules/mob/living/simple_animal/damage_procs.dm +++ b/code/modules/mob/living/simple_animal/damage_procs.dm @@ -18,6 +18,12 @@ if(AIStatus == AI_IDLE) toggle_ai(AI_ON) +/mob/living/simple_animal/get_damage_mod(damage_type) + var/modifier = ..() + if (damage_type in damage_coeff) + return modifier * damage_coeff[damage_type] + return modifier + /mob/living/simple_animal/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype) if(!can_adjust_brute_loss(amount, forced, required_bodytype)) return 0 diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm deleted file mode 100644 index 212867877554c4..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ /dev/null @@ -1,616 +0,0 @@ -GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians - -/mob/living/simple_animal/hostile/guardian - name = "Guardian Spirit" - real_name = "Guardian Spirit" - desc = "A mysterious being that stands by its charge, ever vigilant." - speak_emote = list("hisses") - gender = NEUTER - mob_biotypes = MOB_SPECIAL - sentience_type = SENTIENCE_HUMANOID - bubble_icon = "guardian" - response_help_continuous = "passes through" - response_help_simple = "pass through" - response_disarm_continuous = "flails at" - response_disarm_simple = "flail at" - response_harm_continuous = "punches" - response_harm_simple = "punch" - icon = 'icons/mob/nonhuman-player/guardian.dmi' - icon_state = "magicbase" - icon_living = "magicbase" - icon_dead = "magicbase" - speed = 0 - combat_mode = TRUE - stop_automated_movement = 1 - attack_sound = 'sound/weapons/punch1.ogg' - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - maxbodytemp = INFINITY - attack_verb_continuous = "punches" - attack_verb_simple = "punch" - maxHealth = INFINITY //The spirit itself is invincible - health = INFINITY - mob_biotypes = MOB_BEAST - damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) //how much damage from each damage type we transfer to the owner - environment_smash = ENVIRONMENT_SMASH_STRUCTURES - obj_damage = 40 - melee_damage_lower = 15 - melee_damage_upper = 15 - del_on_death = TRUE - loot = list(/obj/effect/temp_visual/guardian/phase/out) - AIStatus = AI_OFF - can_have_ai = FALSE - light_system = MOVABLE_LIGHT - light_range = 3 - light_on = FALSE - hud_type = /datum/hud/guardian - faction = list() - - /// The guardian's color, used for their sprite, chat, and some effects made by it. - var/guardian_color - /// List of overlays we use. - var/list/guardian_overlays[GUARDIAN_TOTAL_LAYERS] - - /// The summoner of the guardian, the one it's intended to guard! - var/mob/living/summoner - /// How far from the summoner the guardian can be. - var/range = 10 - - /// Which toggle button the HUD uses. - var/toggle_button_type = /atom/movable/screen/guardian/toggle_mode/inactive - /// Name used by the guardian creator. - var/creator_name = "Error" - /// Description used by the guardian creator. - var/creator_desc = "This shouldn't be here! Report it on GitHub!" - /// Icon used by the guardian creator. - var/creator_icon = "fuck" - - /// A string explaining to the guardian what they can do. - var/playstyle_string = span_boldholoparasite("You are a Guardian without any type. You shouldn't exist!") - /// The fluff string we actually use. - var/used_fluff_string - /// Fluff string from tarot cards. - var/magic_fluff_string = span_holoparasite("You draw the Coder, symbolizing bugs and errors. This shouldn't happen! Submit a bug report!") - /// Fluff string from holoparasite injectors. - var/tech_fluff_string = span_holoparasite("BOOT SEQUENCE COMPLETE. ERROR MODULE LOADED. THIS SHOULDN'T HAPPEN. Submit a bug report!") - /// Fluff string from holocarp fishsticks. - var/carp_fluff_string = span_holoparasite("CARP CARP CARP SOME SORT OF HORRIFIC BUG BLAME THE CODERS CARP CARP CARP") - /// Fluff string from the dusty shard. - var/miner_fluff_string = span_holoparasite("You encounter... Mythril, it shouldn't exist... Submit a bug report!") - - /// Are we forced to not be able to manifest/recall? - var/locked = FALSE - /// Cooldown between manifests/recalls. - COOLDOWN_DECLARE(manifest_cooldown) - /// Cooldown between the summoner resetting the guardian's client. - COOLDOWN_DECLARE(resetting_cooldown) - -/mob/living/simple_animal/hostile/guardian/Initialize(mapload, theme) - . = ..() - GLOB.parasites += src - update_theme(theme) - AddElement(/datum/element/simple_flying) - AddComponent(/datum/component/basic_inhands) - manifest_effects() - -/mob/living/simple_animal/hostile/guardian/Destroy() //if deleted by admins or something random, cut from the summoner - if(is_deployed()) - recall_effects() - if(!QDELETED(summoner)) - cut_summoner(different_person = TRUE) - return ..() - -/// Setter for our summoner mob. -/mob/living/simple_animal/hostile/guardian/proc/set_summoner(mob/living/to_who, different_person = FALSE) - if(QDELETED(to_who)) - qdel(src) //no gettin off scot-free pal......... - return - if(summoner) - cut_summoner(different_person) - summoner = to_who - update_health_hud() - med_hud_set_health() - med_hud_set_status() - add_verb(to_who, list( - /mob/living/proc/guardian_comm, - /mob/living/proc/guardian_recall, - /mob/living/proc/guardian_reset, - )) - if(different_person) - if(mind) - mind.enslave_mind_to_creator(to_who) - else //mindless guardian, manually give them factions - faction += summoner.faction - summoner.faction += "[REF(src)]" - remove_all_languages(LANGUAGE_MASTER) - copy_languages(to_who, LANGUAGE_MASTER) // make sure holoparasites speak same language as master - RegisterSignal(to_who, COMSIG_MOVABLE_MOVED, PROC_REF(check_distance)) - RegisterSignal(to_who, COMSIG_QDELETING, PROC_REF(on_summoner_deletion)) - RegisterSignal(to_who, COMSIG_LIVING_DEATH, PROC_REF(on_summoner_death)) - RegisterSignal(to_who, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(on_summoner_health_update)) - RegisterSignal(to_who, COMSIG_LIVING_ON_WABBAJACKED, PROC_REF(on_summoner_wabbajacked)) - RegisterSignal(to_who, COMSIG_LIVING_SHAPESHIFTED, PROC_REF(on_summoner_shapeshifted)) - RegisterSignal(to_who, COMSIG_LIVING_UNSHAPESHIFTED, PROC_REF(on_summoner_unshapeshifted)) - recall(forced = TRUE) - if(to_who.stat == DEAD) - on_summoner_death(to_who) - -/mob/living/simple_animal/hostile/guardian/proc/cut_summoner(different_person = FALSE) - if(is_deployed()) - recall_effects() - var/summoner_turf = get_turf(src) - if (!isnull(summoner_turf)) - forceMove(summoner_turf) - UnregisterSignal(summoner, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING, COMSIG_LIVING_DEATH, COMSIG_LIVING_HEALTH_UPDATE, COMSIG_LIVING_ON_WABBAJACKED, COMSIG_LIVING_SHAPESHIFTED, COMSIG_LIVING_UNSHAPESHIFTED)) - if(different_person) - summoner.faction -= "[REF(src)]" - faction -= summoner.faction - mind?.remove_all_antag_datums() - if(!length(summoner.get_all_linked_holoparasites() - src)) - remove_verb(summoner, list( - /mob/living/proc/guardian_comm, - /mob/living/proc/guardian_recall, - /mob/living/proc/guardian_reset, - )) - summoner = null - -/// Signal proc for [COMSIG_LIVING_ON_WABBAJACKED], when our summoner is wabbajacked we should be alerted. -/mob/living/simple_animal/hostile/guardian/proc/on_summoner_wabbajacked(mob/living/source, mob/living/new_mob) - SIGNAL_HANDLER - - set_summoner(new_mob) - to_chat(src, span_holoparasite("Your summoner has changed form!")) - -/// Signal proc for [COMSIG_LIVING_SHAPESHIFTED], when our summoner is shapeshifted we should change to the new mob -/mob/living/simple_animal/hostile/guardian/proc/on_summoner_shapeshifted(mob/living/source, mob/living/new_shape) - SIGNAL_HANDLER - - set_summoner(new_shape) - to_chat(src, span_holoparasite("Your summoner has shapeshifted into that of a [new_shape]!")) - -/// Signal proc for [COMSIG_LIVING_UNSHAPESHIFTED], when our summoner unshapeshifts go back to that mob -/mob/living/simple_animal/hostile/guardian/proc/on_summoner_unshapeshifted(mob/living/source, mob/living/old_summoner) - SIGNAL_HANDLER - - set_summoner(old_summoner) - to_chat(src, span_holoparasite("Your summoner has shapeshifted back into their normal form!")) - -// Ha, no -/mob/living/simple_animal/hostile/guardian/wabbajack(what_to_randomize, change_flags = WABBAJACK) - visible_message(span_warning("[src] resists the polymorph!")) - -/mob/living/simple_animal/hostile/guardian/proc/on_summoner_health_update(mob/living/source) - SIGNAL_HANDLER - - update_health_hud() - med_hud_set_health() - med_hud_set_status() - -/mob/living/simple_animal/hostile/guardian/med_hud_set_health() - var/image/holder = hud_list?[HEALTH_HUD] - if(isnull(holder)) - return - holder.icon_state = "hud[RoundHealth(summoner || src)]" - var/icon/size_check = icon(icon, icon_state, dir) - holder.pixel_y = size_check.Height() - world.icon_size - -/mob/living/simple_animal/hostile/guardian/med_hud_set_status() - var/image/holder = hud_list?[STATUS_HUD] - if(isnull(holder)) - return - var/icon/size_check = icon(icon, icon_state, dir) - holder.pixel_y = size_check.Height() - world.icon_size - var/mob/living/checking_mob = summoner || src - if(checking_mob.stat == DEAD || HAS_TRAIT(checking_mob, TRAIT_FAKEDEATH)) - holder.icon_state = "huddead" - else - holder.icon_state = "hudhealthy" - -/mob/living/simple_animal/hostile/guardian/Destroy() - GLOB.parasites -= src - return ..() - -/mob/living/simple_animal/hostile/guardian/proc/update_theme(theme) //update the guardian's theme - if(!theme) - theme = pick(GUARDIAN_THEME_MAGIC, GUARDIAN_THEME_TECH, GUARDIAN_THEME_CARP, GUARDIAN_THEME_MINER) - switch(theme)//should make it easier to create new stand designs in the future if anyone likes that - if(GUARDIAN_THEME_MAGIC) - name = "Guardian Spirit" - real_name = "Guardian Spirit" - bubble_icon = "guardian" - icon_state = "magicbase" - icon_living = "magicbase" - icon_dead = "magicbase" - used_fluff_string = magic_fluff_string - if(GUARDIAN_THEME_TECH) - name = "Holoparasite" - real_name = "Holoparasite" - bubble_icon = "holo" - icon_state = "techbase" - icon_living = "techbase" - icon_dead = "techbase" - used_fluff_string = tech_fluff_string - if(GUARDIAN_THEME_MINER) - name = "Power Miner" - real_name = "Power Miner" - bubble_icon = "guardian" - icon_state = "minerbase" - icon_living = "minerbase" - icon_dead = "minerbase" - used_fluff_string = miner_fluff_string - if(GUARDIAN_THEME_CARP) - name = "Holocarp" - real_name = "Holocarp" - bubble_icon = "holo" - icon_state = null //entirely handled by overlays - icon_living = null - icon_dead = null - speak_emote = string_list(list("gnashes")) - desc = "A mysterious fish that stands by its charge, ever vigilant." - attack_verb_continuous = "bites" - attack_verb_simple = "bite" - attack_sound = 'sound/weapons/bite.ogg' - attack_vis_effect = ATTACK_EFFECT_BITE - used_fluff_string = carp_fluff_string - guardian_overlays[GUARDIAN_COLOR_LAYER] = mutable_appearance(icon, theme) - apply_overlay(GUARDIAN_COLOR_LAYER) - -/mob/living/simple_animal/hostile/guardian/Login() //if we have a mind, set its name to ours when it logs in - . = ..() - if(!. || !client) - return FALSE - if(!summoner) - to_chat(src, span_boldholoparasite("For some reason, somehow, you have no summoner. Please report this bug immediately.")) - else - to_chat(src, span_holoparasite("You are a [real_name], bound to serve [summoner.real_name].")) - to_chat(src, span_holoparasite("You are capable of manifesting or recalling to your master with the buttons on your HUD. You will also find a button to communicate with [summoner.p_them()] privately there.")) - to_chat(src, span_holoparasite("While personally invincible, you will die if [summoner.real_name] does, and any damage dealt to you will have a portion passed on to [summoner.p_them()] as you feed upon [summoner.p_them()] to sustain yourself.")) - to_chat(src, playstyle_string) - if(!guardian_color) - locked = TRUE - guardian_rename() - guardian_recolor() - locked = FALSE - -/mob/living/simple_animal/hostile/guardian/mind_initialize() - . = ..() - if(!summoner) - to_chat(src, span_boldholoparasite("For some reason, somehow, you have no summoner. Please report this bug immediately.")) - return - mind.enslave_mind_to_creator(summoner) //once our mind is created, we become enslaved to our summoner. cant be done in the first run of set_summoner, because by then we dont have a mind yet. - -/mob/living/simple_animal/hostile/guardian/proc/guardian_recolor() - if(!client) - return - var/chosen_guardian_color = input(src, "What would you like your color to be?","Choose Your Color","#ffffff") as color|null - if(!chosen_guardian_color) //redo proc until we get a color - to_chat(src, span_warning("Not a valid color, please try again.")) - guardian_recolor() - return - set_guardian_color(chosen_guardian_color) - -/mob/living/simple_animal/hostile/guardian/proc/set_guardian_color(colour) - guardian_color = colour - set_light_color(guardian_color) - var/mutable_appearance/guardian_color_overlay = guardian_overlays[GUARDIAN_COLOR_LAYER] - remove_overlay(GUARDIAN_COLOR_LAYER) - guardian_color_overlay.color = guardian_color - guardian_overlays[GUARDIAN_COLOR_LAYER] = guardian_color_overlay - apply_overlay(GUARDIAN_COLOR_LAYER) - -/mob/living/simple_animal/hostile/guardian/proc/guardian_rename() - if(!client) - return - var/new_name = sanitize_name(reject_bad_text(tgui_input_text(src, "What would you like your name to be?", "Choose Your Name", real_name, MAX_NAME_LEN))) - if(!new_name) //redo proc until we get a good name - to_chat(src, span_warning("Not a valid name, please try again.")) - guardian_rename() - return - to_chat(src, span_notice("Your new name [span_name("[new_name]")] anchors itself in your mind.")) - fully_replace_character_name(null, new_name) - -/mob/living/simple_animal/hostile/guardian/proc/on_summoner_death(mob/living/source) - SIGNAL_HANDLER - - cut_summoner() - if (!isnull(source.loc)) - forceMove(source.loc) - to_chat(src, span_danger("Your summoner has died!")) - visible_message(span_bolddanger("\The [src] dies along with its user!")) - source.visible_message(span_bolddanger("[source]'s body is completely consumed by the strain of sustaining [src]!")) - source.dust(drop_items = TRUE) - death(TRUE) - -/mob/living/simple_animal/hostile/guardian/proc/on_summoner_deletion(mob/living/source) - SIGNAL_HANDLER - - cut_summoner() - to_chat(src, span_danger("Your summoner is gone!")) - qdel(src) - -/mob/living/simple_animal/hostile/guardian/get_status_tab_items() - . += ..() - if(summoner) - var/healthpercent = health_percentage(summoner) - . += "Summoner Health: [round(healthpercent, 0.5)]%" - if(!COOLDOWN_FINISHED(src, manifest_cooldown)) - . += "Manifest/Recall Cooldown Remaining: [DisplayTimeText(COOLDOWN_TIMELEFT(src, manifest_cooldown))]" - -/mob/living/simple_animal/hostile/guardian/Move() //Returns to summoner if they move out of range - . = ..() - check_distance() - -/mob/living/simple_animal/hostile/guardian/proc/check_distance() - SIGNAL_HANDLER - - if(!summoner) - return - if(get_dist(get_turf(summoner), get_turf(src)) <= range) - return - to_chat(src, span_holoparasite("You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]!")) - visible_message(span_danger("\The [src] jumps back to its user.")) - new /obj/effect/temp_visual/guardian/phase/out(loc) - if(istype(summoner.loc, /obj/effect) || isnull(summoner.loc)) - recall(forced = TRUE) - return - forceMove(summoner.loc) - new /obj/effect/temp_visual/guardian/phase(loc) - -/mob/living/simple_animal/hostile/guardian/can_suicide() - return FALSE - -/mob/living/simple_animal/hostile/guardian/proc/is_deployed() - return loc != summoner || !summoner - -/mob/living/simple_animal/hostile/guardian/AttackingTarget(atom/attacked_target) - if(!is_deployed()) - to_chat(src, span_bolddanger("You must be manifested to attack!")) - return FALSE - else - return ..() - -/mob/living/simple_animal/hostile/guardian/death(gibbed) - if(!QDELETED(summoner)) - to_chat(summoner, span_bolddanger("Your [name] died somehow!")) - summoner.dust() - return ..() - -/mob/living/simple_animal/hostile/guardian/update_health_hud() - var/severity = 0 - var/healthpercent = health_percentage(summoner || src) - switch(healthpercent) - if(100 to INFINITY) - severity = 0 - if(85 to 100) - severity = 1 - if(70 to 85) - severity = 2 - if(55 to 70) - severity = 3 - if(40 to 55) - severity = 4 - if(25 to 40) - severity = 5 - else - severity = 6 - if(severity > 0) - overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity) - else - clear_fullscreen("brute") - if(hud_used?.healths) - hud_used.healths.maptext = MAPTEXT("
[round(healthpercent, 0.5)]%
") - -/mob/living/simple_animal/hostile/guardian/adjustHealth(amount, updating_health = TRUE, forced = FALSE) //The spirit is invincible, but passes on damage to the summoner - . = amount - if(!summoner) - return ..() - if(!is_deployed()) - return FALSE - summoner.adjustBruteLoss(amount) - if(amount < 0 || QDELETED(summoner)) - return - to_chat(summoner, span_bolddanger("Your [name] is under attack! You take damage!")) - summoner.visible_message(span_bolddanger("Blood sprays from [summoner] as [src] takes damage!")) - if(summoner.stat == UNCONSCIOUS || summoner.stat == HARD_CRIT) - to_chat(summoner, span_bolddanger("Your head pounds, you can't take the strain of sustaining [src] in this condition!")) - summoner.adjustOrganLoss(ORGAN_SLOT_BRAIN, amount * 0.5) - -/mob/living/simple_animal/hostile/guardian/ex_act(severity, target) - switch(severity) - if(EXPLODE_DEVASTATE) - investigate_log("has been gibbed by an explosion.", INVESTIGATE_DEATHS) - gib() - return TRUE - if(EXPLODE_HEAVY) - adjustBruteLoss(60) - if(EXPLODE_LIGHT) - adjustBruteLoss(30) - - return TRUE - -/mob/living/simple_animal/hostile/guardian/gib() - death(TRUE) - -/mob/living/simple_animal/hostile/guardian/dust(just_ash, drop_items, force) - death(TRUE) - -//HAND HANDLING - -/mob/living/simple_animal/hostile/guardian/equip_to_slot(obj/item/equipping, slot, initial = FALSE, redraw_mob = FALSE, indirect_action = FALSE) - if(!slot) - return FALSE - if(!istype(equipping)) - return FALSE - - . = TRUE - var/index = get_held_index_of_item(equipping) - if(index) - held_items[index] = null - update_held_items() - - if(equipping.pulledby) - equipping.pulledby.stop_pulling() - - equipping.screen_loc = null // will get moved if inventory is visible - equipping.forceMove(src) - SET_PLANE_EXPLICIT(equipping, ABOVE_HUD_PLANE, src) - equipping.on_equipped(src, slot) - -/mob/living/simple_animal/hostile/guardian/proc/apply_overlay(cache_index) - if((. = guardian_overlays[cache_index])) - add_overlay(.) - -/mob/living/simple_animal/hostile/guardian/proc/remove_overlay(cache_index) - var/overlay = guardian_overlays[cache_index] - if(overlay) - cut_overlay(overlay) - guardian_overlays[cache_index] = null - -/mob/living/simple_animal/hostile/guardian/regenerate_icons() - update_held_items() - -//MANIFEST, RECALL, TOGGLE MODE/LIGHT, SHOW TYPE - -/mob/living/simple_animal/hostile/guardian/proc/manifest(forced) - if(is_deployed() || isnull(summoner.loc) || istype(summoner.loc, /obj/effect) || (!COOLDOWN_FINISHED(src, manifest_cooldown) && !forced) || locked) - return FALSE - forceMove(summoner.loc) - new /obj/effect/temp_visual/guardian/phase(loc) - COOLDOWN_START(src, manifest_cooldown, 1 SECONDS) - reset_perspective() - manifest_effects() - return TRUE - -/mob/living/simple_animal/hostile/guardian/proc/recall(forced) - if(!is_deployed() || !summoner || (!COOLDOWN_FINISHED(src, manifest_cooldown) && !forced) || locked) - return FALSE - new /obj/effect/temp_visual/guardian/phase/out(loc) - forceMove(summoner) - COOLDOWN_START(src, manifest_cooldown, 1 SECONDS) - recall_effects() - return TRUE - -/mob/living/simple_animal/hostile/guardian/proc/manifest_effects() - return - -/mob/living/simple_animal/hostile/guardian/proc/recall_effects() - return - -/mob/living/simple_animal/hostile/guardian/proc/toggle_modes() - to_chat(src, span_bolddanger("You don't have another mode!")) - -/mob/living/simple_animal/hostile/guardian/proc/toggle_light() - if(!light_on) - to_chat(src, span_notice("You activate your light.")) - set_light_on(TRUE) - else - to_chat(src, span_notice("You deactivate your light.")) - set_light_on(FALSE) - - -/mob/living/simple_animal/hostile/guardian/verb/check_type() - set name = "Check Guardian Type" - set category = "Guardian" - set desc = "Check what type you are." - to_chat(src, playstyle_string) - -//COMMUNICATION - -/mob/living/simple_animal/hostile/guardian/proc/communicate() - if(!summoner) - return - var/sender_key = key - var/input = tgui_input_text(src, "Enter a message to tell your summoner", "Guardian") - if(sender_key != key || !input) //guardian got reset, or did not enter anything - return - - var/preliminary_message = span_boldholoparasite("[input]") //apply basic color/bolding - var/my_message = "[src]: [preliminary_message]" //add source, color source with the guardian's color - - to_chat(summoner, "[my_message]") - var/list/guardians = summoner.get_all_linked_holoparasites() - for(var/guardian in guardians) - to_chat(guardian, "[my_message]") - for(var/dead_mob in GLOB.dead_mob_list) - var/link = FOLLOW_LINK(dead_mob, src) - to_chat(dead_mob, "[link] [my_message]") - - src.log_talk(input, LOG_SAY, tag="guardian") - -/mob/living/proc/guardian_comm() - set name = "Communicate" - set category = "Guardian" - set desc = "Communicate telepathically with your guardian." - var/input = tgui_input_text(src, "Enter a message to tell your guardian", "Message") - if(!input) - return - - var/preliminary_message = span_boldholoparasite("[input]") //apply basic color/bolding - var/my_message = span_boldholoparasite("[src]: [preliminary_message]") //add source, color source with default grey... - - to_chat(src, "[my_message]") - var/list/guardians = get_all_linked_holoparasites() - for(var/mob/living/simple_animal/hostile/guardian/guardian as anything in guardians) - to_chat(guardian, "[src]: [preliminary_message]" ) - for(var/dead_mob in GLOB.dead_mob_list) - var/link = FOLLOW_LINK(dead_mob, src) - to_chat(dead_mob, "[link] [my_message]") - - src.log_talk(input, LOG_SAY, tag="guardian") - -//FORCE RECALL/RESET - -/mob/living/proc/guardian_recall() - set name = "Recall Guardian" - set category = "Guardian" - set desc = "Forcibly recall your guardian." - var/list/guardians = get_all_linked_holoparasites() - for(var/mob/living/simple_animal/hostile/guardian/guardian in guardians) - guardian.recall() - -/mob/living/proc/guardian_reset() - set name = "Reset Guardian Player (5 Minute Cooldown)" - set category = "Guardian" - set desc = "Re-rolls which ghost will control your Guardian. Can be used once per 5 minutes." - - var/list/guardians = get_all_linked_holoparasites() - for(var/mob/living/simple_animal/hostile/guardian/resetting_guardian as anything in guardians) - if(!COOLDOWN_FINISHED(resetting_guardian, resetting_cooldown)) - guardians -= resetting_guardian //clear out guardians that are already reset - - var/mob/living/simple_animal/hostile/guardian/chosen_guardian = tgui_input_list(src, "Pick the guardian you wish to reset", "Guardian Reset", sort_names(guardians)) - if(isnull(chosen_guardian)) - to_chat(src, span_holoparasite("You decide not to reset [length(guardians) > 1 ? "any of your guardians":"your guardian"].")) - return - - to_chat(src, span_holoparasite("You attempt to reset [chosen_guardian.real_name]'s personality...")) - var/list/mob/dead/observer/ghost_candidates = poll_ghost_candidates("Do you want to play as [src.real_name]'s Guardian Spirit?", ROLE_PAI, FALSE, 100) - if(!LAZYLEN(ghost_candidates)) - to_chat(src, span_holoparasite("There were no ghosts willing to take control of [chosen_guardian.real_name]. Looks like you're stuck with it for now.")) - return - - var/mob/dead/observer/candidate = pick(ghost_candidates) - to_chat(chosen_guardian, span_holoparasite("Your user reset you, and your body was taken over by a ghost. Looks like they weren't happy with your performance.")) - to_chat(src, span_boldholoparasite("Your [chosen_guardian.real_name] has been successfully reset.")) - message_admins("[key_name_admin(candidate)] has taken control of ([ADMIN_LOOKUPFLW(chosen_guardian)])") - chosen_guardian.ghostize(FALSE) - chosen_guardian.key = candidate.key - COOLDOWN_START(chosen_guardian, resetting_cooldown, 5 MINUTES) - chosen_guardian.guardian_rename() //give it a new color and name, to show it's a new person - chosen_guardian.guardian_recolor() - -////////parasite tracking/finding procs - -/// Returns a list of all holoparasites that has this mob as a summoner. -/mob/living/proc/get_all_linked_holoparasites() - RETURN_TYPE(/list) - var/list/all_parasites = list() - for(var/mob/living/simple_animal/hostile/guardian/stand as anything in GLOB.parasites) - if(stand.summoner != src) - continue - all_parasites += stand - return all_parasites - -/// Returns true if this holoparasite has the same summoner as the passed holoparasite. -/mob/living/simple_animal/hostile/guardian/proc/hasmatchingsummoner(mob/living/simple_animal/hostile/guardian/other_guardian) - return istype(other_guardian) && other_guardian.summoner == summoner diff --git a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm deleted file mode 100644 index 340e92a5b42365..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm +++ /dev/null @@ -1,107 +0,0 @@ -//Assassin -/mob/living/simple_animal/hostile/guardian/assassin - melee_damage_lower = 15 - melee_damage_upper = 15 - attack_verb_continuous = "slashes" - attack_verb_simple = "slash" - attack_sound = 'sound/weapons/bladeslice.ogg' - attack_vis_effect = ATTACK_EFFECT_SLASH - sharpness = SHARP_POINTY - damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) - playstyle_string = span_holoparasite("As an assassin type you do medium damage and have no damage resistance, but can enter stealth, massively increasing the damage of your next attack and causing it to ignore armor. Stealth is broken when you attack or take damage.") - magic_fluff_string = span_holoparasite("..And draw the Space Ninja, a lethal, invisible assassin.") - tech_fluff_string = span_holoparasite("Boot sequence complete. Assassin modules loaded. Holoparasite swarm online.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one! It's an assassin carp! Just when you thought it was safe to go back to the water... which is unhelpful, because we're in space.") - miner_fluff_string = span_holoparasite("You encounter... Glass, a sharp, fragile attacker.") - creator_name = "Assassin" - creator_desc = "Does medium damage and takes full damage, but can enter stealth, causing its next attack to do massive damage and ignore armor. However, it becomes briefly unable to recall after attacking from stealth." - creator_icon = "assassin" - toggle_button_type = /atom/movable/screen/guardian/toggle_mode/assassin - /// Is it in stealth mode? - var/toggle = FALSE - /// Time between going in stealth. - var/stealth_cooldown_time = 16 SECONDS - /// Damage added in stealth mode. - var/damage_bonus = 35 - /// Our wound bonus when in stealth mode. - var/stealth_wound_bonus = -20 //from -100, you can now wound! - /// Screen alert given when we are able to stealth. - var/atom/movable/screen/alert/canstealthalert - /// Screen alert given when we are in stealth. - var/atom/movable/screen/alert/instealthalert - /// Cooldown for the stealth toggle. - COOLDOWN_DECLARE(stealth_cooldown) - -/mob/living/simple_animal/hostile/guardian/assassin/get_status_tab_items() - . = ..() - if(!COOLDOWN_FINISHED(src, stealth_cooldown)) - . += "Stealth Cooldown Remaining: [DisplayTimeText(COOLDOWN_TIMELEFT(src, stealth_cooldown))]" - -/mob/living/simple_animal/hostile/guardian/assassin/AttackingTarget(atom/attacked_target) - . = ..() - if(.) - if(toggle && (isliving(target) || istype(target, /obj/structure/window) || istype(target, /obj/structure/grille))) - toggle_modes(forced = TRUE) - -/mob/living/simple_animal/hostile/guardian/assassin/adjustHealth(amount, updating_health = TRUE, forced = FALSE) - . = ..() - if(. > 0 && toggle) - toggle_modes(forced = TRUE) - -/mob/living/simple_animal/hostile/guardian/assassin/recall_effects() - if(toggle) - toggle_modes(forced = TRUE) - -/mob/living/simple_animal/hostile/guardian/assassin/toggle_modes(forced = FALSE) - if(toggle) - melee_damage_lower -= damage_bonus - melee_damage_upper -= damage_bonus - armour_penetration = initial(armour_penetration) - wound_bonus = initial(wound_bonus) - obj_damage = initial(obj_damage) - environment_smash = initial(environment_smash) - alpha = initial(alpha) - if(!forced) - to_chat(src, span_bolddanger("You exit stealth.")) - else - visible_message(span_danger("\The [src] suddenly appears!")) - COOLDOWN_START(src, stealth_cooldown, stealth_cooldown_time) //we were forced out of stealth and go on cooldown - addtimer(CALLBACK(src, PROC_REF(updatestealthalert)), stealth_cooldown_time) - COOLDOWN_START(src, manifest_cooldown, 4 SECONDS) //can't recall for 4 seconds - updatestealthalert() - toggle = FALSE - else if(COOLDOWN_FINISHED(src, stealth_cooldown)) - if(!is_deployed()) - to_chat(src, span_bolddanger("You have to be manifested to enter stealth!")) - return - melee_damage_lower += damage_bonus - melee_damage_upper += damage_bonus - armour_penetration = 100 - wound_bonus = stealth_wound_bonus - obj_damage = 0 - environment_smash = ENVIRONMENT_SMASH_NONE - new /obj/effect/temp_visual/guardian/phase/out(get_turf(src)) - alpha = 15 - if(!forced) - to_chat(src, span_bolddanger("You enter stealth, empowering your next attack.")) - updatestealthalert() - toggle = TRUE - else if(!forced) - to_chat(src, span_bolddanger("You cannot yet enter stealth, wait another [DisplayTimeText(COOLDOWN_TIMELEFT(src, stealth_cooldown))]!")) - -/mob/living/simple_animal/hostile/guardian/assassin/proc/updatestealthalert() - if(!COOLDOWN_FINISHED(src, stealth_cooldown)) - clear_alert("instealth") - instealthalert = null - clear_alert("canstealth") - canstealthalert = null - return - if(toggle && !instealthalert) - instealthalert = throw_alert("instealth", /atom/movable/screen/alert/instealth) - clear_alert("canstealth") - canstealthalert = null - else if(!toggle && !canstealthalert) - canstealthalert = throw_alert("canstealth", /atom/movable/screen/alert/canstealth) - clear_alert("instealth") - instealthalert = null - diff --git a/code/modules/mob/living/simple_animal/guardian/types/charger.dm b/code/modules/mob/living/simple_animal/guardian/types/charger.dm deleted file mode 100644 index e1e0de66b00a82..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/charger.dm +++ /dev/null @@ -1,74 +0,0 @@ -//Charger -/mob/living/simple_animal/hostile/guardian/charger - melee_damage_lower = 15 - melee_damage_upper = 15 - ranged = TRUE //technically - ranged_message = "charges" - ranged_cooldown_time = 4 SECONDS - speed = -0.5 - damage_coeff = list(BRUTE = 0.75, BURN = 0.75, TOX = 0.75, CLONE = 0.75, STAMINA = 0, OXY = 0.75) - playstyle_string = span_holoparasite("As a charger type you do medium damage, have light damage resistance, move very fast, can be ridden, and can charge at a location, damaging any target hit and forcing them to drop any items they are holding.") - magic_fluff_string = span_holoparasite("..And draw the Hunter, an alien master of rapid assault.") - tech_fluff_string = span_holoparasite("Boot sequence complete. Charge modules loaded. Holoparasite swarm online.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one! It's a charger carp, that likes running at people. But it doesn't have any legs...") - miner_fluff_string = span_holoparasite("You encounter... Titanium, a lightweight, agile fighter.") - creator_name = "Charger" - creator_desc = "Moves very fast, does medium damage on attack, can be ridden and can charge at targets, damaging the first target hit and forcing them to drop any items they are holding." - creator_icon = "charger" - /// Is it currently charging at something? - var/charging = FALSE - /// How much damage it does while charging. - var/charge_damage = 20 - -/mob/living/simple_animal/hostile/guardian/charger/Initialize(mapload, theme) - . = ..() - AddElement(/datum/element/ridable, /datum/component/riding/creature/guardian) - -/mob/living/simple_animal/hostile/guardian/charger/get_status_tab_items() - . = ..() - if(!COOLDOWN_FINISHED(src, ranged_cooldown)) - . += "Charge Cooldown Remaining: [DisplayTimeText(COOLDOWN_TIMELEFT(src, ranged_cooldown))]" - -/mob/living/simple_animal/hostile/guardian/charger/OpenFire(atom/target) - if(charging) - return - visible_message(span_danger("[src] [ranged_message] at [target]!")) - COOLDOWN_START(src, ranged_cooldown, ranged_cooldown_time) - clear_alert(ALERT_CHARGE) - addtimer(CALLBACK(src, PROC_REF(throw_alert), ALERT_CHARGE, /atom/movable/screen/alert/cancharge), ranged_cooldown_time) - Shoot(target) - -/mob/living/simple_animal/hostile/guardian/charger/Shoot(atom/targeted_atom) - charging = TRUE - playsound(src, 'sound/items/modsuit/loader_launch.ogg', 75, TRUE) - throw_at(targeted_atom, range, speed = 1.5, thrower = src, spin = FALSE, diagonals_first = TRUE, callback = CALLBACK(src, PROC_REF(charging_end))) - -/mob/living/simple_animal/hostile/guardian/charger/proc/charging_end() - charging = FALSE - -/mob/living/simple_animal/hostile/guardian/charger/Move() - if(charging) - new /obj/effect/temp_visual/decoy/fading(loc, src) - return ..() - -/mob/living/simple_animal/hostile/guardian/charger/check_distance() - if(!charging) - ..() - -/mob/living/simple_animal/hostile/guardian/charger/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) - if(!charging) - return ..() - if(!isliving(hit_atom) || hit_atom == summoner || hasmatchingsummoner(hit_atom)) - return - var/mob/living/hit_mob = hit_atom - if(ishuman(hit_mob)) - var/mob/living/carbon/human/hit_human = hit_mob - if(hit_human.check_shields(src, charge_damage, name, attack_type = THROWN_PROJECTILE_ATTACK)) - return - hit_mob.drop_all_held_items() - hit_mob.visible_message(span_danger("[src] slams into [hit_mob]!"), span_userdanger("[src] slams into you!")) - hit_mob.apply_damage(charge_damage, BRUTE) - playsound(hit_mob, 'sound/effects/meteorimpact.ogg', 100, TRUE) - shake_camera(hit_mob, 4, 3) - shake_camera(src, 2, 3) - diff --git a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm deleted file mode 100644 index d2fbfc33c877d3..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm +++ /dev/null @@ -1,90 +0,0 @@ -//Dextrous -/mob/living/simple_animal/hostile/guardian/dextrous - melee_damage_lower = 10 - melee_damage_upper = 10 - damage_coeff = list(BRUTE = 0.75, BURN = 0.75, TOX = 0.75, CLONE = 0.75, STAMINA = 0, OXY = 0.75) - playstyle_string = span_holoparasite("As a dextrous type you can hold items, store an item within yourself, and have medium damage resistance, but do low damage on attacks. Recalling and leashing will force you to drop unstored items!") - magic_fluff_string = span_holoparasite("..And draw the Drone, a dextrous master of construction and repair.") - tech_fluff_string = span_holoparasite("Boot sequence complete. Dextrous combat modules loaded. Holoparasite swarm online.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! You caught one! It can hold stuff in its fins, sort of.") - miner_fluff_string = span_holoparasite("You encounter... Gold, a malleable constructor.") - creator_name = "Dextrous" - creator_desc = "Does low damage on attack, but is capable of holding items and storing a single item within it. It will drop items held in its hands when it recalls, but it will retain the stored item." - creator_icon = "dextrous" - dextrous = TRUE - hud_type = /datum/hud/dextrous/guardian - held_items = list(null, null) - var/obj/item/internal_storage //what we're storing within ourself - -/mob/living/simple_animal/hostile/guardian/dextrous/death(gibbed) - . = ..() - if(internal_storage) - dropItemToGround(internal_storage) - -/mob/living/simple_animal/hostile/guardian/dextrous/examine(mob/user) - . = ..() - if(internal_storage && !(internal_storage.item_flags & ABSTRACT)) - . += span_info("It is holding [internal_storage.get_examine_string(user)] in its internal storage.") - -/mob/living/simple_animal/hostile/guardian/dextrous/recall_effects() - drop_all_held_items() - -/mob/living/simple_animal/hostile/guardian/dextrous/check_distance() - if(!summoner || get_dist(get_turf(summoner), get_turf(src)) <= range) - return - drop_all_held_items() - ..() //lose items, then return - -//SLOT HANDLING BULLSHIT FOR INTERNAL STORAGE -/mob/living/simple_animal/hostile/guardian/dextrous/doUnEquip(obj/item/equipped_item, force, newloc, no_move, invdrop = TRUE, silent = FALSE) - if(..()) - update_held_items() - if(equipped_item == internal_storage) - internal_storage = null - update_inv_internal_storage() - return TRUE - return FALSE - -/mob/living/simple_animal/hostile/guardian/dextrous/can_equip(obj/item/equipped_item, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE) - switch(slot) - if(ITEM_SLOT_DEX_STORAGE) - if(internal_storage) - return FALSE - return TRUE - ..() - -/mob/living/simple_animal/hostile/guardian/dextrous/get_item_by_slot(slot_id) - if(slot_id == ITEM_SLOT_DEX_STORAGE) - return internal_storage - return ..() - -/mob/living/simple_animal/hostile/guardian/dextrous/get_slot_by_item(obj/item/looking_for) - if(internal_storage == looking_for) - return ITEM_SLOT_DEX_STORAGE - return ..() - -/mob/living/simple_animal/hostile/guardian/dextrous/equip_to_slot(obj/item/equipping, slot, initial = FALSE, redraw_mob = FALSE, indirect_action = FALSE) - if(!..()) - return - - switch(slot) - if(ITEM_SLOT_DEX_STORAGE) - internal_storage = equipping - update_inv_internal_storage() - else - to_chat(src, span_danger("You are trying to equip this item to an unsupported inventory slot. Report this to a coder!")) - -/mob/living/simple_animal/hostile/guardian/dextrous/getBackSlot() - return ITEM_SLOT_DEX_STORAGE - -/mob/living/simple_animal/hostile/guardian/dextrous/getBeltSlot() - return ITEM_SLOT_DEX_STORAGE - -/mob/living/simple_animal/hostile/guardian/dextrous/proc/update_inv_internal_storage() - if(internal_storage && client && hud_used?.hud_shown) - internal_storage.screen_loc = ui_id - client.screen += internal_storage - -/mob/living/simple_animal/hostile/guardian/dextrous/regenerate_icons() - ..() - update_inv_internal_storage() diff --git a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm deleted file mode 100644 index 6fbc61ee45886c..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm +++ /dev/null @@ -1,72 +0,0 @@ -#define UNREGISTER_BOMB_SIGNALS(A) \ - do { \ - UnregisterSignal(A, boom_signals); \ - UnregisterSignal(A, COMSIG_ATOM_EXAMINE); \ - } while (0) - -//Explosive -/mob/living/simple_animal/hostile/guardian/explosive - melee_damage_lower = 15 - melee_damage_upper = 15 - damage_coeff = list(BRUTE = 0.6, BURN = 0.6, TOX = 0.6, CLONE = 0.6, STAMINA = 0, OXY = 0.6) - range = 13 - playstyle_string = span_holoparasite("As an explosive type, you have moderate close combat abilities and are capable of converting nearby items and objects into disguised bombs via right-click.") - magic_fluff_string = span_holoparasite("..And draw the Scientist, master of explosive death.") - tech_fluff_string = span_holoparasite("Boot sequence complete. Explosive modules active. Holoparasite swarm online.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one! It's an explosive carp! Boom goes the fishy.") - miner_fluff_string = span_holoparasite("You encounter... Gibtonite, an explosive fighter.") - creator_name = "Explosive" - creator_desc = "High damage resist and medium power attack. Can turn any object, including objects too large to pick up, into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered or after a delay." - creator_icon = "explosive" - /// Static list of signals that activate the boom. - var/static/list/boom_signals = list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_BUMPED, COMSIG_ATOM_ATTACK_HAND) - /// After this amount of time passses, boom deactivates. - var/decay_time = 1 MINUTES - /// Time between bombs. - var/bomb_cooldown_time = 20 SECONDS - /// The cooldown timer between bombs. - COOLDOWN_DECLARE(bomb_cooldown) - -/mob/living/simple_animal/hostile/guardian/explosive/get_status_tab_items() - . = ..() - if(!COOLDOWN_FINISHED(src, bomb_cooldown)) - . += "Bomb Cooldown Remaining: [DisplayTimeText(COOLDOWN_TIMELEFT(src, bomb_cooldown))]" - -/mob/living/simple_animal/hostile/guardian/explosive/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) - if(LAZYACCESS(modifiers, RIGHT_CLICK) && proximity_flag && isobj(attack_target)) - plant_bomb(attack_target) - return - return ..() - -/mob/living/simple_animal/hostile/guardian/explosive/proc/plant_bomb(obj/planting_on) - if(!COOLDOWN_FINISHED(src, bomb_cooldown)) - to_chat(src, span_bolddanger("Your powers are on cooldown! You must wait [DisplayTimeText(COOLDOWN_TIMELEFT(src, bomb_cooldown))] between bombs.")) - return - to_chat(src, span_bolddanger("Success! Bomb armed!")) - COOLDOWN_START(src, bomb_cooldown, bomb_cooldown_time) - RegisterSignal(planting_on, COMSIG_ATOM_EXAMINE, PROC_REF(display_examine)) - RegisterSignals(planting_on, boom_signals, PROC_REF(kaboom)) - addtimer(CALLBACK(src, PROC_REF(disable), planting_on), decay_time, TIMER_UNIQUE|TIMER_OVERRIDE) - -/mob/living/simple_animal/hostile/guardian/explosive/proc/kaboom(atom/source, mob/living/explodee) - SIGNAL_HANDLER - if(!istype(explodee)) - return - if(explodee == src || explodee == summoner || hasmatchingsummoner(explodee)) - return - to_chat(explodee, span_bolddanger("[source] was boobytrapped!")) - to_chat(src, span_bolddanger("Success! Your trap caught [explodee]")) - playsound(source, 'sound/effects/explosion2.ogg', 200, TRUE) - new /obj/effect/temp_visual/explosion(get_turf(source)) - EX_ACT(explodee, EXPLODE_HEAVY) - UNREGISTER_BOMB_SIGNALS(source) - -/mob/living/simple_animal/hostile/guardian/explosive/proc/disable(obj/rigged_obj) - to_chat(src, span_bolddanger("Failure! Your trap didn't catch anyone this time.")) - UNREGISTER_BOMB_SIGNALS(rigged_obj) - -/mob/living/simple_animal/hostile/guardian/explosive/proc/display_examine(datum/source, mob/user, text) - SIGNAL_HANDLER - text += span_holoparasite("It glows with a strange light!") - -#undef UNREGISTER_BOMB_SIGNALS diff --git a/code/modules/mob/living/simple_animal/guardian/types/gaseous.dm b/code/modules/mob/living/simple_animal/guardian/types/gaseous.dm deleted file mode 100644 index 7808f8a6b482bd..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/gaseous.dm +++ /dev/null @@ -1,103 +0,0 @@ -//Gaseous -/mob/living/simple_animal/hostile/guardian/gaseous - melee_damage_lower = 10 - melee_damage_upper = 10 - damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 0) - range = 7 - playstyle_string = span_holoparasite("As a gaseous type, you have only light damage resistance, but you can expel gas in an area. In addition, your punches cause sparks, and you make your summoner inflammable.") - magic_fluff_string = span_holoparasite("..And draw the Atmospheric Technician, flooding the area with gas!") - tech_fluff_string = span_holoparasite("Boot sequence complete. Atmospheric modules activated. Holoparasite swarm online.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! You caught one! OH GOD, EVERYTHING'S ON FIRE. Except you and the fish.") - miner_fluff_string = span_holoparasite("You encounter... Plasma, the bringer of fire.") - creator_name = "Gaseous" - creator_desc = "Creates sparks on touch and continuously expels a gas of its choice. Automatically extinguishes the user if they catch on fire." - creator_icon = "gaseous" - toggle_button_type = /atom/movable/screen/guardian/toggle_mode/gases - /// Gas being expelled. - var/expelled_gas = null - /// Rate of temperature stabilization per second. - var/temp_stabilization_rate = 0.1 - /// Possible gases to expel, with how much moles they create. - var/static/list/possible_gases = list( - /datum/gas/oxygen = 50, - /datum/gas/nitrogen = 750, //overpressurizing is hard!. - /datum/gas/water_vapor = 1, //you need incredibly little water vapor for the effects to kick in - /datum/gas/nitrous_oxide = 15, - /datum/gas/carbon_dioxide = 50, - /datum/gas/plasma = 3, - /datum/gas/bz = 10, - ) - /// Gas colors, used for the particles. - var/static/list/gas_colors = list( - /datum/gas/oxygen = "#63BFDD", //color of frozen oxygen - /datum/gas/nitrogen = "#777777", //grey (grey) - /datum/gas/water_vapor = "#96ADCF", //water is slightly blue - /datum/gas/nitrous_oxide = "#FEFEFE", //white like the sprite - /datum/gas/carbon_dioxide = "#222222", //black like coal - /datum/gas/plasma = "#B233CC", //color of the plasma sprite - /datum/gas/bz = "#FAFF00", //color of the bz metabolites reagent - ) - -/mob/living/simple_animal/hostile/guardian/gaseous/Initialize(mapload, theme) - . = ..() - RegisterSignal(src, COMSIG_ATOM_PRE_PRESSURE_PUSH, PROC_REF(stop_pressure)) - -/mob/living/simple_animal/hostile/guardian/gaseous/AttackingTarget(atom/attacked_target) - . = ..() - if(!isliving(target)) - return - do_sparks(1, TRUE, target) - -/mob/living/simple_animal/hostile/guardian/gaseous/recall(forced) - expelled_gas = null - QDEL_NULL(particles) //need to delete before putting in another object - . = ..() - if(. && summoner) - UnregisterSignal(summoner, COMSIG_ATOM_PRE_PRESSURE_PUSH) - -/mob/living/simple_animal/hostile/guardian/gaseous/manifest(forced) - . = ..() - if(. && summoner) - RegisterSignal(summoner, COMSIG_ATOM_PRE_PRESSURE_PUSH, PROC_REF(stop_pressure)) - -/mob/living/simple_animal/hostile/guardian/gaseous/Life(seconds_per_tick, times_fired) - . = ..() - if(summoner) - summoner.extinguish_mob() - summoner.set_fire_stacks(0, remove_wet_stacks = FALSE) - summoner.adjust_bodytemperature(get_temp_change_amount((summoner.get_body_temp_normal() - summoner.bodytemperature), temp_stabilization_rate * seconds_per_tick)) - if(!expelled_gas) - return - var/datum/gas_mixture/mix_to_spawn = new() - mix_to_spawn.add_gas(expelled_gas) - mix_to_spawn.gases[expelled_gas][MOLES] = possible_gases[expelled_gas] * seconds_per_tick - mix_to_spawn.temperature = T20C - var/turf/open/our_turf = get_turf(src) - our_turf.assume_air(mix_to_spawn) - -/mob/living/simple_animal/hostile/guardian/gaseous/toggle_modes() - var/list/gases = list("None") - for(var/datum/gas/gas as anything in possible_gases) - gases[initial(gas.name)] = gas - var/picked_gas = tgui_input_list(src, "Select a gas to expel.", "Gas Producer", gases) - if(picked_gas == "None") - expelled_gas = null - QDEL_NULL(particles) - to_chat(src, span_notice("You stopped expelling gas.")) - return - var/gas_type = gases[picked_gas] - if(!picked_gas || !gas_type) - return - to_chat(src, span_bolddanger("You are now expelling [picked_gas].")) - investigate_log("set their gas type to [picked_gas].", INVESTIGATE_ATMOS) - expelled_gas = gas_type - if(!particles) - particles = new /particles/smoke/steam() - particles.position = list(-1, 8, 0) - particles.fadein = 5 - particles.height = 200 - particles.color = gas_colors[gas_type] - -/mob/living/simple_animal/hostile/guardian/gaseous/proc/stop_pressure(datum/source) - SIGNAL_HANDLER - return COMSIG_ATOM_BLOCKS_PRESSURE diff --git a/code/modules/mob/living/simple_animal/guardian/types/gravitokinetic.dm b/code/modules/mob/living/simple_animal/guardian/types/gravitokinetic.dm deleted file mode 100644 index fe6a0ec58563d3..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/gravitokinetic.dm +++ /dev/null @@ -1,91 +0,0 @@ -//gravitokinetic -/mob/living/simple_animal/hostile/guardian/gravitokinetic - melee_damage_lower = 15 - melee_damage_upper = 15 - damage_coeff = list(BRUTE = 0.75, BURN = 0.75, TOX = 0.75, CLONE = 0.75, STAMINA = 0, OXY = 0.75) - playstyle_string = span_holoparasite("As a gravitokinetic type, you can right-click to make the gravity on the ground stronger, and punching applies this effect to a target.") - magic_fluff_string = span_holoparasite("..And draw the Singularity, an anomalous force of terror.") - tech_fluff_string = span_holoparasite("Boot sequence complete. Gravitokinetic modules loaded. Holoparasite swarm online.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one! It's a gravitokinetic carp! Now do you understand the gravity of the situation?") - miner_fluff_string = span_holoparasite("You encounter... Bananium, a master of gravity business.") - creator_name = "Gravitokinetic" - creator_desc = "Attacks will apply crushing gravity to the target. Can target the ground as well to slow targets advancing on you, but this will affect the user." - creator_icon = "gravitokinetic" - /// Targets we have applied our effects on. - var/list/gravity_targets = list() - /// Distance in which our ability works - var/gravity_power_range = 10 - /// Gravity added on punches. - var/punch_gravity = 5 - /// Gravity added to turfs. - var/turf_gravity = 3 - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/Initialize(mapload, theme) - . = ..() - AddElement(/datum/element/forced_gravity, 1) - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/set_summoner(mob/to_who, different_person) - . = ..() - to_who.AddElement(/datum/element/forced_gravity, 1) - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/cut_summoner(different_person) - summoner.RemoveElement(/datum/element/forced_gravity, 1) - return ..() - -///Removes gravity from affected mobs upon guardian death to prevent permanent effects -/mob/living/simple_animal/hostile/guardian/gravitokinetic/death() - . = ..() - for(var/gravity_target in gravity_targets) - remove_gravity(gravity_target) - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/AttackingTarget(atom/attacked_target) - . = ..() - if(isliving(target) && !hasmatchingsummoner(attacked_target) && target != src && target != summoner && !gravity_targets[target]) - to_chat(src, span_bolddanger("Your punch has applied heavy gravity to [target]!")) - add_gravity(target, punch_gravity) - to_chat(target, span_userdanger("Everything feels really heavy!")) - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) - if(LAZYACCESS(modifiers, RIGHT_CLICK) && proximity_flag && !gravity_targets[target]) - slam_turf(attack_target) - return - return ..() - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/slam_turf(turf/open/slammed) - if(!isopenturf(slammed) || isgroundlessturf(slammed)) - to_chat(src, span_warning("You cannot add gravity to this!")) - return - visible_message(span_danger("[src] slams their fist into the [slammed]!"), span_notice("You modify the gravity of the [slammed].")) - do_attack_animation(slammed) - add_gravity(slammed, turf_gravity) - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/recall_effects() - to_chat(src, span_bolddanger("You have released your gravitokinetic powers!")) - for(var/gravity_target in gravity_targets) - remove_gravity(gravity_target) - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) - . = ..() - for(var/gravity_target in gravity_targets) - if(get_dist(src, gravity_target) > gravity_power_range) - remove_gravity(gravity_target) - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/add_gravity(atom/target, new_gravity = 3) - if(gravity_targets[target]) - return - target.AddElement(/datum/element/forced_gravity, new_gravity) - gravity_targets[target] = new_gravity - RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(distance_check)) - playsound(src, 'sound/effects/gravhit.ogg', 100, TRUE) - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/remove_gravity(atom/target) - if(isnull(gravity_targets[target])) - return - UnregisterSignal(target, COMSIG_MOVABLE_MOVED) - target.RemoveElement(/datum/element/forced_gravity, gravity_targets[target]) - gravity_targets -= target - -/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/distance_check(atom/movable/moving_target, old_loc, dir, forced) - SIGNAL_HANDLER - if(get_dist(src, moving_target) > gravity_power_range) - remove_gravity(moving_target) diff --git a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm deleted file mode 100644 index 9739445f7c9c78..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm +++ /dev/null @@ -1,111 +0,0 @@ -/obj/effect/ebeam/chain - name = "lightning chain" - layer = LYING_MOB_LAYER - plane = GAME_PLANE_FOV_HIDDEN - -//Lightning -/mob/living/simple_animal/hostile/guardian/lightning - melee_damage_lower = 7 - melee_damage_upper = 7 - attack_verb_continuous = "shocks" - attack_verb_simple = "shock" - melee_damage_type = BURN - attack_sound = 'sound/machines/defib_zap.ogg' - damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7) - range = 7 - playstyle_string = span_holoparasite("As a lightning type, you will apply lightning chains to targets on attack and have a lightning chain to your summoner. Lightning chains will shock anyone near them.") - magic_fluff_string = span_holoparasite("..And draw the Tesla, a shocking, lethal source of power.") - tech_fluff_string = span_holoparasite("Boot sequence complete. Lightning modules active. Holoparasite swarm online.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one! It's a lightning carp! Everyone else goes zap zap.") - miner_fluff_string = span_holoparasite("You encounter... Iron, a conductive master of lightning.") - creator_name = "Lightning" - creator_desc = "Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage." - creator_icon = "lightning" - /// Beam datum of our lightning chain to the summoner. - var/datum/beam/summonerchain - /// List of all lightning chains attached to enemies. - var/list/enemychains = list() - /// Amount of shocks we've given through the chain to the summoner. - var/successfulshocks = 0 - /// Cooldown between shocks. - COOLDOWN_DECLARE(shock_cooldown) - -/mob/living/simple_animal/hostile/guardian/lightning/AttackingTarget(atom/attacked_target) - . = ..() - if(!. || !isliving(target) || target == summoner || hasmatchingsummoner(target)) - return - cleardeletedchains() - for(var/datum/beam/chain as anything in enemychains) - if(chain.target == target) - return //oh this guy already HAS a chain, let's not chain again - if(length(enemychains) > 2) - var/datum/beam/enemy_chain = pick(enemychains) - qdel(enemy_chain) - enemychains -= enemy_chain - enemychains += Beam(target, "lightning[rand(1,12)]", maxdistance=7, beam_type=/obj/effect/ebeam/chain) - -/mob/living/simple_animal/hostile/guardian/lightning/manifest_effects() - START_PROCESSING(SSfastprocess, src) - if(summoner) - summonerchain = Beam(summoner, "lightning[rand(1,12)]", beam_type=/obj/effect/ebeam/chain) - -/mob/living/simple_animal/hostile/guardian/lightning/recall_effects() - STOP_PROCESSING(SSfastprocess, src) - removechains() - -/mob/living/simple_animal/hostile/guardian/lightning/process(seconds_per_tick) - if(!COOLDOWN_FINISHED(src, shock_cooldown)) - return - if(successfulshocks > 5) - successfulshocks = 0 - if(shockallchains()) - successfulshocks++ - COOLDOWN_START(src, shock_cooldown, 0.3 SECONDS) - -/mob/living/simple_animal/hostile/guardian/lightning/proc/cleardeletedchains() - if(summonerchain && QDELETED(summonerchain)) - summonerchain = null - for(var/datum/chain as anything in enemychains) - if(QDELETED(chain)) - enemychains -= chain - -/mob/living/simple_animal/hostile/guardian/lightning/proc/shockallchains() - . = 0 - cleardeletedchains() - if(summonerchain) - . += chainshock(summonerchain) - for(var/chain in enemychains) - . += chainshock(chain) - -/mob/living/simple_animal/hostile/guardian/lightning/proc/removechains() - QDEL_NULL(summonerchain) - for(var/chain in enemychains) - qdel(chain) - enemychains = list() - -/mob/living/simple_animal/hostile/guardian/lightning/proc/chainshock(datum/beam/B) //fuck you, fuck this - . = 0 - var/list/turfs = list() - for(var/E in B.elements) - var/obj/effect/ebeam/chainpart = E - if(chainpart && chainpart.x && chainpart.y && chainpart.z) - var/turf/T = get_turf_pixel(chainpart) - turfs |= T - if(T != get_turf(B.origin) && T != get_turf(B.target)) - for(var/turf/TU in circle_range(T, 1)) - turfs |= TU - for(var/turf in turfs) - var/turf/T = turf - for(var/mob/living/L in T) - if(L.stat != DEAD && L != src && L != summoner) - if(hasmatchingsummoner(L)) //if the summoner matches don't hurt them - continue - if(successfulshocks > 4) - L.electrocute_act(0) - L.visible_message( - span_danger("[L] was shocked by the lightning chain!"), \ - span_userdanger("You are shocked by the lightning chain!"), \ - span_hear("You hear a heavy electrical crack.") \ - ) - L.adjustFireLoss(1.2) //adds up very rapidly - . = 1 diff --git a/code/modules/mob/living/simple_animal/guardian/types/protector.dm b/code/modules/mob/living/simple_animal/guardian/types/protector.dm deleted file mode 100644 index 4809c3dc1c6bb9..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/protector.dm +++ /dev/null @@ -1,78 +0,0 @@ -//Protector -/mob/living/simple_animal/hostile/guardian/protector - melee_damage_lower = 15 - melee_damage_upper = 15 - range = 15 //worse for it due to how it leashes - damage_coeff = list(BRUTE = 0.4, BURN = 0.4, TOX = 0.4, CLONE = 0.4, STAMINA = 0, OXY = 0.4) - playstyle_string = span_holoparasite("As a protector type you cause your summoner to leash to you instead of you leashing to them and have two modes; Combat Mode, where you do and take medium damage, and Protection Mode, where you do and take almost no damage, but move slightly slower.") - magic_fluff_string = span_holoparasite("..And draw the Guardian, a stalwart protector that never leaves the side of its charge.") - tech_fluff_string = span_holoparasite("Boot sequence complete. Protector modules loaded. Holoparasite swarm online.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! You caught one! Wait, no... it caught you! The fisher has become the fishy.") - miner_fluff_string = span_holoparasite("You encounter... Uranium, a very resistant guardian.") - creator_name = "Protector" - creator_desc = "Causes you to teleport to it when out of range, unlike other parasites. Has two modes; Combat, where it does and takes medium damage, and Protection, where it does and takes almost no damage but moves slightly slower." - creator_icon = "protector" - toggle_button_type = /atom/movable/screen/guardian/toggle_mode - /// Damage removed in protecting mode. - var/damage_penalty = 13 - /// Is it in protecting mode? - var/toggle = FALSE - /// Overlay of our protection shield. - var/mutable_appearance/shield_overlay - -/mob/living/simple_animal/hostile/guardian/protector/ex_act(severity) - if(severity >= EXPLODE_DEVASTATE) - adjustBruteLoss(400) //if in protector mode, will do 20 damage and not actually necessarily kill the summoner - else - . = ..() - if(QDELETED(src)) - return FALSE - if(toggle) - visible_message(span_danger("The explosion glances off [src]'s energy shielding!")) - - return TRUE - -/mob/living/simple_animal/hostile/guardian/protector/adjustHealth(amount, updating_health = TRUE, forced = FALSE) - . = ..() - if(. > 0 && toggle) - var/image/flash_overlay = new('icons/effects/effects.dmi', src, "shield-flash", dir = pick(GLOB.cardinals)) - flash_overlay.color = guardian_color - flick_overlay_view(flash_overlay, 0.5 SECONDS) - -/mob/living/simple_animal/hostile/guardian/protector/toggle_modes() - if(COOLDOWN_FINISHED(src, manifest_cooldown)) - return - COOLDOWN_START(src, manifest_cooldown, 1 SECONDS) - if(toggle) - cut_overlay(shield_overlay) - melee_damage_lower += damage_penalty - melee_damage_upper += damage_penalty - speed = initial(speed) - damage_coeff = list(BRUTE = 0.4, BURN = 0.4, TOX = 0.4, CLONE = 0.4, STAMINA = 0, OXY = 0.4) - to_chat(src, span_bolddanger("You switch to combat mode.")) - toggle = FALSE - else - if(!shield_overlay) - shield_overlay = mutable_appearance('icons/effects/effects.dmi', "shield-grey") - shield_overlay.color = guardian_color - add_overlay(shield_overlay) - melee_damage_lower -= damage_penalty - melee_damage_upper -= damage_penalty - speed = 1 - damage_coeff = list(BRUTE = 0.05, BURN = 0.05, TOX = 0.05, CLONE = 0.05, STAMINA = 0, OXY = 0.05) //damage? what's damage? - to_chat(src, span_bolddanger("You switch to protection mode.")) - toggle = TRUE - -/mob/living/simple_animal/hostile/guardian/protector/check_distance() //snap to what? snap to the guardian! - if(!summoner || get_dist(summoner, src) <= range) - return - if(istype(summoner.loc, /obj/effect)) - to_chat(src, span_holoparasite("You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]!")) - visible_message(span_danger("\The [src] jumps back to its user.")) - recall(forced = TRUE) - return - to_chat(summoner, span_holoparasite("You moved out of range, and were pulled back! You can only move [range] meters from [real_name]!")) - summoner.visible_message(span_danger("\The [summoner] jumps back to [summoner.p_their()] protector.")) - new /obj/effect/temp_visual/guardian/phase/out(get_turf(summoner)) - summoner.forceMove(get_turf(src)) - new /obj/effect/temp_visual/guardian/phase(get_turf(summoner)) diff --git a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm deleted file mode 100644 index 0cb7303e26a560..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm +++ /dev/null @@ -1,182 +0,0 @@ -//Ranged -/obj/projectile/guardian - name = "crystal spray" - icon_state = "guardian" - damage = 5 - damage_type = BRUTE - armour_penetration = 100 - -/mob/living/simple_animal/hostile/guardian/ranged - combat_mode = FALSE - friendly_verb_continuous = "quietly assesses" - friendly_verb_simple = "quietly assess" - melee_damage_lower = 10 - melee_damage_upper = 10 - damage_coeff = list(BRUTE = 0.9, BURN = 0.9, TOX = 0.9, CLONE = 0.9, STAMINA = 0, OXY = 0.9) - projectiletype = /obj/projectile/guardian - ranged_cooldown_time = 1 //fast! - projectilesound = 'sound/effects/hit_on_shattered_glass.ogg' - ranged = 1 - range = 13 - playstyle_string = span_holoparasite("As a ranged type, you have only light damage resistance, but are capable of spraying shards of crystal at incredibly high speed. You can also deploy surveillance snares to monitor enemy movement. Finally, you can switch to scout mode, in which you can't attack, but can move without limit.") - magic_fluff_string = span_holoparasite("..And draw the Sentinel, an alien master of ranged combat.") - tech_fluff_string = span_holoparasite("Boot sequence complete. Ranged combat modules active. Holoparasite swarm online.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! Caught one, it's a ranged carp. This fishy can watch people pee in the ocean.") - miner_fluff_string = span_holoparasite("You encounter... Diamond, a powerful projectile thrower.") - creator_name = "Ranged" - creator_desc = "Has two modes. Ranged; which fires a constant stream of weak, armor-ignoring projectiles. Scout; where it cannot attack, but can move through walls and is quite hard to see. Can lay surveillance snares, which alert it when crossed, in either mode." - creator_icon = "ranged" - see_invisible = SEE_INVISIBLE_LIVING - toggle_button_type = /atom/movable/screen/guardian/toggle_mode - /// List of all deployed snares. - var/list/snares = list() - /// Is it in scouting mode? - var/toggle = FALSE - /// Maximum snares deployed at once. - var/max_snares = 6 - /// Lower damage before scouting. - var/previous_lower_damage = 0 - /// Upper damage before scouting. - var/previous_upper_damage = 0 - -/mob/living/simple_animal/hostile/guardian/ranged/toggle_modes() - if(is_deployed() && summoner) - to_chat(src, span_bolddanger("You have to be recalled to toggle modes!")) - return - if(toggle) - ranged = initial(ranged) - melee_damage_lower = previous_lower_damage - melee_damage_upper = previous_upper_damage - previous_lower_damage = 0 - previous_upper_damage = 0 - obj_damage = initial(obj_damage) - environment_smash = initial(environment_smash) - alpha = 255 - range = initial(range) - to_chat(src, span_bolddanger("You switch to combat mode.")) - toggle = FALSE - else - ranged = 0 - previous_lower_damage = melee_damage_lower - melee_damage_lower = 0 - previous_upper_damage = melee_damage_upper - melee_damage_upper = 0 - obj_damage = 0 - environment_smash = ENVIRONMENT_SMASH_NONE - alpha = 45 - range = 255 - to_chat(src, span_bolddanger("You switch to scout mode.")) - toggle = TRUE - - -/mob/living/simple_animal/hostile/guardian/ranged/Shoot(atom/targeted_atom) - . = ..() - if(!istype(., /obj/projectile)) - return - var/obj/projectile/shot_projectile = . - shot_projectile.color = guardian_color - -/mob/living/simple_animal/hostile/guardian/ranged/toggle_light() - var/msg - switch(lighting_cutoff) - if (LIGHTING_CUTOFF_VISIBLE) - lighting_cutoff_red = 10 - lighting_cutoff_green = 10 - lighting_cutoff_blue = 15 - msg = "You activate your night vision." - if (LIGHTING_CUTOFF_MEDIUM) - lighting_cutoff_red = 25 - lighting_cutoff_green = 25 - lighting_cutoff_blue = 35 - msg = "You increase your night vision." - if (LIGHTING_CUTOFF_HIGH) - lighting_cutoff_red = 35 - lighting_cutoff_green = 35 - lighting_cutoff_blue = 50 - msg = "You maximize your night vision." - else - lighting_cutoff_red = 0 - lighting_cutoff_green = 0 - lighting_cutoff_blue = 0 - msg = "You deactivate your night vision." - sync_lighting_plane_cutoff() - to_chat(src, span_notice(msg)) - - -/mob/living/simple_animal/hostile/guardian/ranged/verb/Snare() - set name = "Set Surveillance Snare" - set category = "Guardian" - set desc = "Set an invisible snare that will alert you when living creatures walk over it. Max of 5" - if(length(snares) < max_snares) - var/turf/snare_loc = get_turf(src) - var/obj/effect/snare/new_snare = new /obj/effect/snare(snare_loc, src) - new_snare.name = "[get_area(snare_loc)] snare ([rand(1, 1000)])" - snares += new_snare - to_chat(src, span_bolddanger("Surveillance snare deployed!")) - else - to_chat(src, span_bolddanger("You have too many snares deployed. Remove some first.")) - -/mob/living/simple_animal/hostile/guardian/ranged/verb/DisarmSnare() - set name = "Remove Surveillance Snare" - set category = "Guardian" - set desc = "Disarm unwanted surveillance snares." - var/picked_snare = tgui_input_list(src, "Pick which snare to remove.", "Remove Snare", sort_names(snares)) - if(isnull(picked_snare)) - return - qdel(picked_snare) - to_chat(src, span_bolddanger("Snare disarmed.")) - -/obj/effect/snare - name = "snare" - desc = "You shouldn't be seeing this!" - invisibility = INVISIBILITY_ABSTRACT - var/datum/weakref/guardian_ref - -/obj/effect/snare/Initialize(mapload, spawning_guardian) - . = ..() - guardian_ref = WEAKREF(spawning_guardian) - var/static/list/loc_connections = list( - COMSIG_ATOM_ENTERED = PROC_REF(on_entered), - ) - AddElement(/datum/element/connect_loc, loc_connections) - -/obj/effect/snare/Destroy(force) - var/mob/living/simple_animal/hostile/guardian/ranged/spawning_guardian = guardian_ref?.resolve() - if(spawning_guardian) - spawning_guardian.snares -= src - return ..() - -/obj/effect/snare/proc/on_entered(datum/source, crossed_object) - SIGNAL_HANDLER - var/mob/living/simple_animal/hostile/guardian/ranged/spawning_guardian = guardian_ref?.resolve() - if(!spawning_guardian) - qdel(src) - return - if(!isliving(crossed_object) || crossed_object == spawning_guardian || spawning_guardian.hasmatchingsummoner(crossed_object)) - return - send_message(spawning_guardian.summoner || spawning_guardian, crossed_object) - -/obj/effect/snare/proc/send_message(mob/living/recipient, crossed_object) - to_chat(recipient, span_bolddanger("[crossed_object] has crossed [name].")) - var/list/guardians = recipient.get_all_linked_holoparasites() - for(var/guardian in guardians) - send_message(guardian, crossed_object) - -/obj/effect/snare/singularity_act() - return - -/obj/effect/snare/singularity_pull() - return - -/mob/living/simple_animal/hostile/guardian/ranged/manifest_effects() - if(toggle) - incorporeal_move = INCORPOREAL_MOVE_BASIC - -/mob/living/simple_animal/hostile/guardian/ranged/recall_effects() - // To stop scout mode from moving when recalled - incorporeal_move = FALSE - -/mob/living/simple_animal/hostile/guardian/ranged/AttackingTarget(atom/attacked_target) - if(toggle) - return - return ..() diff --git a/code/modules/mob/living/simple_animal/guardian/types/standard.dm b/code/modules/mob/living/simple_animal/guardian/types/standard.dm deleted file mode 100644 index 89f671d3ffa19d..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/standard.dm +++ /dev/null @@ -1,41 +0,0 @@ -//Standard -/mob/living/simple_animal/hostile/guardian/standard - damage_coeff = list(BRUTE = 0.5, BURN = 0.5, TOX = 0.5, CLONE = 0.5, STAMINA = 0, OXY = 0.5) - melee_damage_lower = 20 - melee_damage_upper = 20 - wound_bonus = -5 //you can wound! - obj_damage = 80 - next_move_modifier = 0.8 //attacks 20% faster - environment_smash = ENVIRONMENT_SMASH_WALLS - playstyle_string = span_holoparasite("As a standard type you have no special abilities, but have a high damage resistance and a powerful attack capable of smashing through walls.") - magic_fluff_string = span_holoparasite("..And draw the Assistant, faceless and generic, but never to be underestimated.") - tech_fluff_string = span_holoparasite("Boot sequence complete. Standard combat modules loaded. Holoparasite swarm online.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! You caught one! It's really boring and standard. Better punch some walls to ease the tension.") - miner_fluff_string = span_holoparasite("You encounter... Adamantine, a powerful attacker.") - creator_name = "Standard" - creator_desc = "Devastating close combat attacks and high damage resistance. Can smash through weak walls." - creator_icon = "standard" - /// The text we shout when attacking. - var/battlecry = "AT" - -/mob/living/simple_animal/hostile/guardian/standard/verb/Battlecry() - set name = "Set Battlecry" - set category = "Guardian" - set desc = "Choose what you shout as you punch people." - var/input = tgui_input_text(src, "What do you want your battlecry to be?", "Battle Cry", max_length = 6) - if(input) - battlecry = input - -/mob/living/simple_animal/hostile/guardian/standard/AttackingTarget(atom/attacked_target) - . = ..() - if(!isliving(target) || attacked_target == src) - return - var/msg = "" - for(var/i in 1 to 9) - msg += battlecry - say("[msg]!!", ignore_spam = TRUE) - for(var/j in 1 to 4) - addtimer(CALLBACK(src, PROC_REF(do_attack_sound), target.loc), j) - -/mob/living/simple_animal/hostile/guardian/standard/proc/do_attack_sound(atom/playing_from) - playsound(playing_from, attack_sound, 50, TRUE, TRUE) diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm deleted file mode 100644 index 9afdf231ce7c41..00000000000000 --- a/code/modules/mob/living/simple_animal/guardian/types/support.dm +++ /dev/null @@ -1,141 +0,0 @@ -//Support -/mob/living/simple_animal/hostile/guardian/support - speed = 0 - damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7) - melee_damage_lower = 15 - melee_damage_upper = 15 - playstyle_string = span_holoparasite("As a support type, you may right-click to heal targets. In addition, alt-clicking on an adjacent object or mob will warp them to your bluespace beacon after a short delay.") - magic_fluff_string = span_holoparasite("..And draw the Chief Medical Officer, a potent force of life... and death.") - carp_fluff_string = span_holoparasite("CARP CARP CARP! You caught a support carp. It's a kleptocarp!") - tech_fluff_string = span_holoparasite("Boot sequence complete. Support modules active. Holoparasite swarm online.") - miner_fluff_string = span_holoparasite("You encounter... Bluespace, the master of support.") - creator_name = "Support" - creator_desc = "Does medium damage, but can heal its targets and create beacons to teleport people and things to." - creator_icon = "support" - /// Is it in healing mode? - var/toggle = FALSE - /// How much we heal per hit. - var/healing_amount = 5 - /// Our teleportation beacon. - var/obj/structure/receiving_pad/beacon - /// Time it takes to teleport. - var/teleporting_time = 6 SECONDS - /// Time between creating beacons. - var/beacon_cooldown_time = 5 MINUTES - /// Cooldown between creating beacons. - COOLDOWN_DECLARE(beacon_cooldown) - -/mob/living/simple_animal/hostile/guardian/support/Initialize(mapload) - . = ..() - var/datum/atom_hud/medsensor = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] - medsensor.show_to(src) - -/mob/living/simple_animal/hostile/guardian/support/get_status_tab_items() - . = ..() - if(!COOLDOWN_FINISHED(src, beacon_cooldown)) - . += "Beacon Cooldown Remaining: [DisplayTimeText(COOLDOWN_TIMELEFT(src, beacon_cooldown))]" - -/mob/living/simple_animal/hostile/guardian/support/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) - if(LAZYACCESS(modifiers, RIGHT_CLICK) && proximity_flag && isliving(attack_target)) - heal_target(attack_target) - return - return ..() - -/mob/living/simple_animal/hostile/guardian/support/proc/heal_target(mob/living/target) - do_attack_animation(target, ATTACK_EFFECT_PUNCH) - target.visible_message(span_notice("[src] heals [target]!"),\ - span_userdanger("[src] heals you!"), null, COMBAT_MESSAGE_RANGE, src) - to_chat(src, span_notice("You heal [target]!")) - playsound(target, attack_sound, 50, TRUE, TRUE, frequency = -1) //play punch in REVERSE - var/need_mob_update - need_mob_update = target.adjustBruteLoss(-healing_amount, updating_health = FALSE) - need_mob_update += target.adjustFireLoss(-healing_amount, updating_health = FALSE) - need_mob_update += target.adjustOxyLoss(-healing_amount, updating_health = FALSE) - need_mob_update += target.adjustToxLoss(-healing_amount, updating_health = FALSE, forced = TRUE) - if(need_mob_update) - target.updatehealth() - var/obj/effect/temp_visual/heal/heal_effect = new /obj/effect/temp_visual/heal(get_turf(target)) - heal_effect.color = guardian_color - -/mob/living/simple_animal/hostile/guardian/support/verb/Beacon() - set name = "Place Bluespace Beacon" - set category = "Guardian" - set desc = "Mark a floor as your beacon point, allowing you to warp targets to it. Your beacon will not work at extreme distances." - - if(!COOLDOWN_FINISHED(src, beacon_cooldown)) - to_chat(src, span_bolddanger("Your power is on cooldown. You must wait five minutes between placing beacons.")) - return - - var/turf/beacon_loc = get_turf(src.loc) - if(!isfloorturf(beacon_loc)) - return - - if(beacon) - beacon.disappear() - beacon = null - - beacon = new(beacon_loc, src) - - to_chat(src, span_bolddanger("Beacon placed! You may now warp targets and objects to it, including your user, via Alt+Click.")) - - COOLDOWN_START(src, beacon_cooldown, beacon_cooldown_time) - -/obj/structure/receiving_pad - name = "bluespace receiving pad" - icon = 'icons/turf/floors.dmi' - desc = "A receiving zone for bluespace teleportations." - icon_state = "light_on-8" - light_range = MINIMUM_USEFUL_LIGHT_RANGE - density = FALSE - anchored = TRUE - plane = FLOOR_PLANE - layer = ABOVE_OPEN_TURF_LAYER - -/obj/structure/receiving_pad/New(loc, mob/living/simple_animal/hostile/guardian/spawning_guardian) - . = ..() - add_atom_colour(spawning_guardian?.guardian_color, FIXED_COLOUR_PRIORITY) - -/obj/structure/receiving_pad/proc/disappear() - visible_message(span_notice("[src] vanishes!")) - qdel(src) - -/mob/living/simple_animal/hostile/guardian/support/AltClickOn(atom/movable/target) - teleport_to_beacon(target) - -/mob/living/simple_animal/hostile/guardian/support/proc/teleport_to_beacon(atom/movable/teleport_target) - if(!istype(teleport_target)) - return - if(!beacon) - to_chat(src, span_bolddanger("You need a beacon placed to warp things!")) - return - if(!is_deployed()) - to_chat(src, span_bolddanger("You must be manifested to warp a target!")) - return - if(!Adjacent(teleport_target)) - to_chat(src, span_bolddanger("You must be adjacent to your target!")) - return - if(teleport_target.anchored) - to_chat(src, span_bolddanger("Your target is anchored!")) - return - var/turf/target_turf = get_turf(teleport_target) - if(beacon.z != target_turf.z) - to_chat(src, span_bolddanger("The beacon is too far away to warp to!")) - return - to_chat(src, span_bolddanger("You begin to warp [teleport_target].")) - teleport_target.visible_message(span_danger("[teleport_target] starts to glow faintly!"), \ - span_userdanger("You start to faintly glow, and you feel strangely weightless!")) - do_attack_animation(teleport_target) - playsound(teleport_target, attack_sound, 50, TRUE, TRUE, frequency = -1) //play punch in REVERSE - if(!do_after(src, teleporting_time, teleport_target)) //now start the channel - to_chat(src, span_bolddanger("You need to hold still!")) - return - new /obj/effect/temp_visual/guardian/phase/out(target_turf) - if(isliving(teleport_target)) - var/mob/living/living_target = teleport_target - living_target.flash_act() - teleport_target.visible_message( - span_danger("[teleport_target] disappears in a flash of light!"), \ - span_userdanger("Your vision is obscured by a flash of light!"), \ - ) - do_teleport(teleport_target, beacon, 0, channel = TELEPORT_CHANNEL_BLUESPACE) - new /obj/effect/temp_visual/guardian/phase(get_turf(teleport_target)) diff --git a/code/modules/mob/living/simple_animal/hostile/constructs/constructs.dm b/code/modules/mob/living/simple_animal/hostile/constructs/constructs.dm deleted file mode 100644 index 31150a4dc89c17..00000000000000 --- a/code/modules/mob/living/simple_animal/hostile/constructs/constructs.dm +++ /dev/null @@ -1,133 +0,0 @@ -/mob/living/simple_animal/hostile/construct - name = "Construct" - real_name = "Construct" - desc = "" - gender = NEUTER - mob_biotypes = MOB_MINERAL | MOB_SPECIAL - speak_emote = list("hisses") - response_help_continuous = "thinks better of touching" - response_help_simple = "think better of touching" - response_disarm_continuous = "flails at" - response_disarm_simple = "flail at" - response_harm_continuous = "punches" - response_harm_simple = "punch" - speak_chance = 1 - icon = 'icons/mob/nonhuman-player/cult.dmi' - speed = 0 - combat_mode = TRUE - stop_automated_movement = 1 - status_flags = CANPUSH - attack_sound = 'sound/weapons/punch1.ogg' - // Vivid red, cause cult theme - lighting_cutoff_red = 30 - lighting_cutoff_green = 5 - lighting_cutoff_blue = 20 - damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - maxbodytemp = INFINITY - faction = list(FACTION_CULT) - pressure_resistance = 100 - unique_name = TRUE - AIStatus = AI_OFF //normal constructs don't have AI - loot = list(/obj/item/ectoplasm) - del_on_death = TRUE - initial_language_holder = /datum/language_holder/construct - death_message = "collapses in a shattered heap." - /// List of spells that this construct can cast - var/list/construct_spells = list() - /// Flavor text shown to players when they spawn as this construct - var/playstyle_string = "You are a generic construct! Your job is to not exist, and you should probably adminhelp this." - /// The construct's master - var/master = null - /// Whether this construct is currently seeking nar nar - var/seeking = FALSE - /// Whether this construct can repair other constructs or cult buildings. - var/can_repair = FALSE - /// Whether this construct can repair itself. Works independently of can_repair. - var/can_repair_self = FALSE - /// Theme controls color. THEME_CULT is red THEME_WIZARD is purple and THEME_HOLY is blue - var/theme = THEME_CULT - -/mob/living/simple_animal/hostile/construct/Initialize(mapload) - . = ..() - AddElement(/datum/element/simple_flying) - add_traits(list(TRAIT_HEALS_FROM_CULT_PYLONS, TRAIT_SPACEWALK), INNATE_TRAIT) - for(var/spell in construct_spells) - var/datum/action/new_spell = new spell(src) - new_spell.Grant(src) - - var/spell_count = 1 - for(var/datum/action/spell as anything in actions) - if(!(spell.type in construct_spells)) - continue - - var/pos = 2 + spell_count * 31 - if(construct_spells.len >= 4) - pos -= 31 * (construct_spells.len - 4) - spell.default_button_position = "6:[pos],4:-2" // Set the default position to this random position - spell_count++ - update_action_buttons() - - if(icon_state) - add_overlay("glow_[icon_state]_[theme]") - -/mob/living/simple_animal/hostile/construct/Login() - . = ..() - if(!. || !client) - return FALSE - to_chat(src, playstyle_string) - -/mob/living/simple_animal/hostile/construct/examine(mob/user) - var/text_span - switch(theme) - if(THEME_CULT) - text_span = "cult" - if(THEME_WIZARD) - text_span = "purple" - if(THEME_HOLY) - text_span = "blue" - . = list("This is [icon2html(src, user)] \a [src]!\n[desc]") - if(health < maxHealth) - if(health >= maxHealth/2) - . += span_warning("[p_They()] look[p_s()] slightly dented.") - else - . += span_warning("[p_They()] look[p_s()] severely dented!") - . += "" - -/mob/living/simple_animal/hostile/construct/attack_animal(mob/living/simple_animal/user, list/modifiers) - if(!isconstruct(user)) - if(src != user) - return ..() - return - - var/mob/living/simple_animal/hostile/construct/doll = user - if(!doll.can_repair || (doll == src && !doll.can_repair_self)) - return ..() - if(theme != doll.theme) - return ..() - - if(health >= maxHealth) - if(src != user) - to_chat(user, span_cult("You cannot repair [src]'s dents, as [p_they()] [p_have()] none!")) - else - to_chat(user, span_cult("You cannot repair your own dents, as you have none!")) - return - - adjustHealth(-5) - if(src == user) - user.visible_message(span_danger("[user] repairs some of [p_their()] own dents."), \ - span_cult("You repair some of your own dents, leaving you at [user.health]/[user.maxHealth] health.")) - return - - Beam(user, icon_state="sendbeam", time = 4) - user.visible_message(span_danger("[user] repairs some of \the [src]'s dents."), \ - span_cult("You repair some of [src]'s dents, leaving [src] at [health]/[maxHealth] health.")) - - -/mob/living/simple_animal/hostile/construct/narsie_act() - return - -/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE) - return FALSE - diff --git a/code/modules/mob/living/simple_animal/hostile/constructs/wraith.dm b/code/modules/mob/living/simple_animal/hostile/constructs/wraith.dm deleted file mode 100644 index 83bc262e8bccfc..00000000000000 --- a/code/modules/mob/living/simple_animal/hostile/constructs/wraith.dm +++ /dev/null @@ -1,82 +0,0 @@ -/mob/living/simple_animal/hostile/construct/wraith - name = "Wraith" - real_name = "Wraith" - desc = "A wicked, clawed shell constructed to assassinate enemies and sow chaos behind enemy lines." - icon_state = "wraith" - icon_living = "wraith" - maxHealth = 65 - health = 65 - melee_damage_lower = 20 - melee_damage_upper = 20 - retreat_distance = 2 //AI wraiths will move in and out of combat - attack_verb_continuous = "slashes" - attack_verb_simple = "slash" - attack_sound = 'sound/weapons/bladeslice.ogg' - attack_vis_effect = ATTACK_EFFECT_SLASH - construct_spells = list( - /datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift, - /datum/action/innate/cult/create_rune/tele, - ) - playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, \ - can phase through walls, and your attacks will lower the cooldown on phasing." - - // Accomplishing various things gives you a refund on jaunt, to jump in and out. - /// The seconds refunded per attack - var/attack_refund = 1 SECONDS - /// The seconds refunded when putting a target into critical - var/crit_refund = 5 SECONDS - -/mob/living/simple_animal/hostile/construct/wraith/AttackingTarget(atom/attacked_target) //refund jaunt cooldown when attacking living targets - var/prev_stat - var/mob/living/living_target = target - - if(isliving(living_target) && !IS_CULTIST(living_target)) - prev_stat = living_target.stat - - . = ..() - if(!. || !isnum(prev_stat)) - return - - var/datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/jaunt = locate() in actions - if(!jaunt) - return - - var/total_refund = 0 SECONDS - // they're dead, and you killed them - full refund - if(QDELETED(living_target) || (living_target.stat == DEAD && prev_stat != DEAD)) - total_refund += jaunt.cooldown_time - // you knocked them into critical - else if(HAS_TRAIT(living_target, TRAIT_CRITICAL_CONDITION) && prev_stat == CONSCIOUS) - total_refund += crit_refund - - if(living_target.stat != DEAD && prev_stat != DEAD) - total_refund += attack_refund - - jaunt.next_use_time -= total_refund - jaunt.build_all_button_icons() - -/mob/living/simple_animal/hostile/construct/wraith/hostile //actually hostile, will move around, hit things - AIStatus = AI_ON - -//////////////////////////Wraith-alts//////////////////////////// -/mob/living/simple_animal/hostile/construct/wraith/angelic - theme = THEME_HOLY - construct_spells = list( - /datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/angelic, - /datum/action/innate/cult/create_rune/tele, - ) - loot = list(/obj/item/ectoplasm/angelic) - -/mob/living/simple_animal/hostile/construct/wraith/angelic/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_ANGELIC, INNATE_TRAIT) - -/mob/living/simple_animal/hostile/construct/wraith/mystic - theme = THEME_WIZARD - construct_spells = list( - /datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/mystic, - /datum/action/innate/cult/create_rune/tele, - ) - loot = list(/obj/item/ectoplasm/mystic) - -/mob/living/simple_animal/hostile/construct/wraith/noncult diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 4dd2c464a2f072..9d215ed35fccd4 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -172,7 +172,7 @@ Goto(P.starting, move_to_delay, 3) return ..() -//////////////HOSTILE MOB TARGETTING AND AGGRESSION//////////// +//////////////HOSTILE MOB TARGETING AND AGGRESSION//////////// /mob/living/simple_animal/hostile/proc/ListTargets() //Step 1, find out what we can see var/atom/target_from = GET_TARGETS_FROM(src) @@ -196,7 +196,7 @@ possible_targets = ListTargets() for(var/atom/pos_targ as anything in possible_targets) - if(Found(pos_targ)) //Just in case people want to override targetting + if(Found(pos_targ)) //Just in case people want to override targeting all_potential_targets = list(pos_targ) break @@ -422,7 +422,7 @@ LoseAggro() SEND_SIGNAL(src, COMSIG_HOSTILE_MOB_LOST_TARGET) // SKYRAT EDIT ADDITION -//////////////END HOSTILE MOB TARGETTING AND AGGRESSION//////////// +//////////////END HOSTILE MOB TARGETING AND AGGRESSION//////////// /mob/living/simple_animal/hostile/death(gibbed) LoseTarget() diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm b/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm deleted file mode 100644 index 8cccf16b850894..00000000000000 --- a/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm +++ /dev/null @@ -1,17 +0,0 @@ -/mob/living/simple_animal/hostile/jungle - vision_range = 5 - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - faction = list(FACTION_JUNGLE) - obj_damage = 30 - environment_smash = ENVIRONMENT_SMASH_WALLS - minbodytemp = 0 - maxbodytemp = 450 - response_harm_continuous = "strikes" - response_harm_simple = "strike" - status_flags = NONE - combat_mode = TRUE - // Let's do a blue, since they'll be on green turfs if this shit is ever finished - lighting_cutoff_red = 5 - lighting_cutoff_green = 20 - lighting_cutoff_blue = 25 - mob_size = MOB_SIZE_LARGE diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm deleted file mode 100644 index 3330b682a01636..00000000000000 --- a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm +++ /dev/null @@ -1,289 +0,0 @@ -#define PLAYER_HOP_DELAY 25 - -//Huge, carnivorous toads that spit an immobilizing toxin at its victims before leaping onto them. -//It has no melee attack, and its damage comes from the toxin in its bubbles and its crushing leap. -//Its eyes will turn red to signal an imminent attack! -/mob/living/simple_animal/hostile/jungle/leaper - name = "leaper" - desc = "Commonly referred to as 'leapers', the Geron Toad is a massive beast that spits out highly pressurized bubbles containing a unique toxin, knocking down its prey and then crushing it with its girth." - icon = 'icons/mob/simple/jungle/leaper.dmi' - icon_state = "leaper" - icon_living = "leaper" - icon_dead = "leaper_dead" - mob_biotypes = MOB_ORGANIC|MOB_BEAST - maxHealth = 300 - health = 300 - ranged = TRUE - projectiletype = /obj/projectile/leaper - projectilesound = 'sound/weapons/pierce.ogg' - ranged_cooldown_time = 30 - pixel_x = -16 - base_pixel_x = -16 - layer = LARGE_MOB_LAYER - plane = GAME_PLANE_UPPER_FOV_HIDDEN - speed = 10 - stat_attack = HARD_CRIT - robust_searching = 1 - var/hopping = FALSE - var/hop_cooldown = 0 //Strictly for player controlled leapers - var/projectile_ready = FALSE //Stopping AI leapers from firing whenever they want, and only doing it after a hop has finished instead - - footstep_type = FOOTSTEP_MOB_HEAVY - -/obj/projectile/leaper - name = "leaper bubble" - icon_state = "leaper" - paralyze = 50 - damage = 0 - range = 7 - hitsound = 'sound/effects/snap.ogg' - nondirectional_sprite = TRUE - impact_effect_type = /obj/effect/temp_visual/leaper_projectile_impact - -/obj/projectile/leaper/on_hit(atom/target, blocked = 0, pierce_hit) - ..() - if (!isliving(target)) - return - var/mob/living/bubbled = target - if(iscarbon(target)) - bubbled.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5) - return - if(isanimal(target)) - var/mob/living/simple_animal/bubbled_animal = bubbled - bubbled_animal.adjustHealth(25) - return - if (isbasicmob(target)) - bubbled.adjustBruteLoss(25) - -/obj/projectile/leaper/on_range() - var/turf/T = get_turf(src) - ..() - new /obj/structure/leaper_bubble(T) - -/obj/effect/temp_visual/leaper_projectile_impact - name = "leaper bubble" - icon = 'icons/obj/weapons/guns/projectiles.dmi' - icon_state = "leaper_bubble_pop" - layer = ABOVE_ALL_MOB_LAYER - plane = GAME_PLANE_UPPER_FOV_HIDDEN - duration = 3 - -/obj/effect/temp_visual/leaper_projectile_impact/Initialize(mapload) - . = ..() - new /obj/effect/decal/cleanable/leaper_sludge(get_turf(src)) - -/obj/effect/decal/cleanable/leaper_sludge - name = "leaper sludge" - desc = "A small pool of sludge, containing trace amounts of leaper venom." - icon = 'icons/effects/tomatodecal.dmi' - icon_state = "tomato_floor1" - -/obj/effect/decal/cleanable/leaper_sludge/Initialize(mapload, list/datum/disease/diseases) - . = ..() - AddElement(/datum/element/swabable, CELL_LINE_TABLE_LEAPER, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) - -/obj/structure/leaper_bubble - name = "leaper bubble" - desc = "A floating bubble containing leaper venom. The contents are under a surprising amount of pressure." - icon = 'icons/obj/weapons/guns/projectiles.dmi' - icon_state = "leaper" - max_integrity = 10 - density = FALSE - -/obj/structure/leaper_bubble/Initialize(mapload) - . = ..() - AddElement(/datum/element/movetype_handler) - ADD_TRAIT(src, TRAIT_MOVE_FLOATING, LEAPER_BUBBLE_TRAIT) - QDEL_IN(src, 100) - var/static/list/loc_connections = list( - COMSIG_ATOM_ENTERED = PROC_REF(on_entered), - ) - AddElement(/datum/element/connect_loc, loc_connections) - AddElement(/datum/element/swabable, CELL_LINE_TABLE_LEAPER, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) - -/obj/structure/leaper_bubble/Destroy() - new /obj/effect/temp_visual/leaper_projectile_impact(get_turf(src)) - playsound(src,'sound/effects/snap.ogg',50, TRUE, -1) - return ..() - -/obj/structure/leaper_bubble/proc/on_entered(datum/source, atom/movable/bubbled) - SIGNAL_HANDLER - if(!isliving(bubbled) || istype(bubbled, /mob/living/simple_animal/hostile/jungle/leaper)) - return - var/mob/living/bubbled_mob = bubbled - - playsound(src,'sound/effects/snap.ogg',50, TRUE, -1) - bubbled_mob.Paralyze(50) - if(iscarbon(bubbled_mob)) - bubbled_mob.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5) - else if(isanimal(bubbled_mob)) - var/mob/living/simple_animal/bubbled_animal = bubbled_mob - bubbled_animal.adjustHealth(25) - else if(isbasicmob(bubbled_mob)) - bubbled_mob.adjustBruteLoss(25) - qdel(src) - -/datum/reagent/toxin/leaper_venom - name = "Leaper venom" - description = "A toxin spat out by leapers that, while harmless in small doses, quickly creates a toxic reaction if too much is in the body." - color = "#801E28" // rgb: 128, 30, 40 - toxpwr = 0 - taste_description = "french cuisine" - taste_mult = 1.3 - -/datum/reagent/toxin/leaper_venom/on_mob_life(mob/living/carbon/M, seconds_per_tick, times_fired) - . = ..() - if(volume >= 10) - if(M.adjustToxLoss(5 * REM * seconds_per_tick, updating_health = FALSE)) - . = UPDATE_MOB_HEALTH - -/obj/effect/temp_visual/leaper_crush - name = "grim tidings" - desc = "Incoming leaper!" - icon = 'icons/effects/96x96.dmi' - icon_state = "lily_pad" - layer = BELOW_MOB_LAYER - plane = GAME_PLANE - SET_BASE_PIXEL(-32, -32) - duration = 30 - -/mob/living/simple_animal/hostile/jungle/leaper/Initialize(mapload) - . = ..() - AddComponent(/datum/component/seethrough_mob) - remove_verb(src, /mob/living/verb/pulled) - add_cell_sample() - -/mob/living/simple_animal/hostile/jungle/leaper/CtrlClickOn(atom/A) - face_atom(A) - GiveTarget(A) - if(!isturf(loc)) - return - if(next_move > world.time) - return - if(hopping) - return - if(isliving(A)) - var/mob/living/L = A - if(L.incapacitated()) - BellyFlop() - return - if(hop_cooldown <= world.time) - Hop(player_hop = TRUE) - -/mob/living/simple_animal/hostile/jungle/leaper/AttackingTarget(atom/attacked_target) - if(isliving(target)) - return - return ..() - -/mob/living/simple_animal/hostile/jungle/leaper/handle_automated_action() - if(hopping || projectile_ready) - return - . = ..() - if(target) - if(isliving(target)) - var/mob/living/L = target - if(L.incapacitated()) - BellyFlop() - return - if(!hopping) - Hop() - -/mob/living/simple_animal/hostile/jungle/leaper/Life(seconds_per_tick = SSMOBS_DT, times_fired) - . = ..() - update_icons() - -/mob/living/simple_animal/hostile/jungle/leaper/adjustHealth(amount, updating_health = TRUE, forced = FALSE) - if(prob(33) && !ckey) - ranged_cooldown = 0 //Keeps em on their toes instead of a constant rotation - ..() - -/mob/living/simple_animal/hostile/jungle/leaper/OpenFire() - face_atom(target) - if(ranged_cooldown <= world.time) - if(ckey) - if(hopping) - return - if(isliving(target)) - var/mob/living/L = target - if(L.incapacitated()) - return //No stunlocking. Hop on them after you stun them, you donk. - if(AIStatus == AI_ON && !projectile_ready && !ckey) - return - . = ..(target) - projectile_ready = FALSE - update_icons() - -/mob/living/simple_animal/hostile/jungle/leaper/proc/Hop(player_hop = FALSE) - if(z != target.z) - return - hopping = TRUE - add_traits(list(TRAIT_UNDENSE, TRAIT_NO_TRANSFORM), LEAPING_TRAIT) - pass_flags |= PASSMOB - var/turf/new_turf = locate((target.x + rand(-3,3)),(target.y + rand(-3,3)),target.z) - if(player_hop) - new_turf = get_turf(target) - hop_cooldown = world.time + PLAYER_HOP_DELAY - if(AIStatus == AI_ON && ranged_cooldown <= world.time) - projectile_ready = TRUE - update_icons() - throw_at(new_turf, max(3,get_dist(src,new_turf)), 1, src, FALSE, callback = CALLBACK(src, PROC_REF(FinishHop))) - -/mob/living/simple_animal/hostile/jungle/leaper/proc/FinishHop() - remove_traits(list(TRAIT_UNDENSE, TRAIT_NO_TRANSFORM), LEAPING_TRAIT) - pass_flags &= ~PASSMOB - hopping = FALSE - playsound(src.loc, 'sound/effects/meteorimpact.ogg', 100, TRUE) - if(target && AIStatus == AI_ON && projectile_ready && !ckey) - face_atom(target) - addtimer(CALLBACK(src, PROC_REF(OpenFire), target), 5) - -/mob/living/simple_animal/hostile/jungle/leaper/proc/BellyFlop() - var/turf/new_turf = get_turf(target) - hopping = TRUE - ADD_TRAIT(src, TRAIT_NO_TRANSFORM, LEAPING_TRAIT) - new /obj/effect/temp_visual/leaper_crush(new_turf) - addtimer(CALLBACK(src, PROC_REF(BellyFlopHop), new_turf), 3 SECONDS) - -/mob/living/simple_animal/hostile/jungle/leaper/proc/BellyFlopHop(turf/T) - ADD_TRAIT(src, TRAIT_UNDENSE, LEAPING_TRAIT) - throw_at(T, get_dist(src,T),1,src, FALSE, callback = CALLBACK(src, PROC_REF(Crush))) - -/mob/living/simple_animal/hostile/jungle/leaper/proc/Crush() - hopping = FALSE - remove_traits(list(TRAIT_UNDENSE, TRAIT_NO_TRANSFORM), LEAPING_TRAIT) - playsound(src, 'sound/effects/meteorimpact.ogg', 200, TRUE) - for(var/mob/living/L in orange(1, src)) - L.adjustBruteLoss(35) - if(!QDELETED(L)) // Some mobs are deleted on death - var/throw_dir = get_dir(src, L) - if(L.loc == loc) - throw_dir = pick(GLOB.alldirs) - var/throwtarget = get_edge_target_turf(src, throw_dir) - L.throw_at(throwtarget, 3, 1) - visible_message(span_warning("[L] is thrown clear of [src]!")) - if(ckey)//Lessens ability to chain stun as a player - ranged_cooldown = ranged_cooldown_time + world.time - update_icons() - -/mob/living/simple_animal/hostile/jungle/leaper/Goto() - return - -/mob/living/simple_animal/hostile/jungle/leaper/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) - return - -/mob/living/simple_animal/hostile/jungle/leaper/update_icons() - . = ..() - if(stat) - icon_state = "leaper_dead" - return - if(ranged_cooldown <= world.time) - if(AIStatus == AI_ON && projectile_ready || ckey) - icon_state = "leaper_alert" - return - icon_state = "leaper" - -/mob/living/simple_animal/hostile/jungle/leaper/add_cell_sample() - . = ..() - AddElement(/datum/element/swabable, CELL_LINE_TABLE_LEAPER, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) - -#undef PLAYER_HOP_DELAY diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm index 5f9e2678fd8078..4ed79e48834686 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm @@ -59,9 +59,7 @@ AddComponent(/datum/component/gps, gps_name) ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) add_traits(list(TRAIT_NO_TELEPORT, TRAIT_MARTIAL_ARTS_IMMUNE), MEGAFAUNA_TRAIT) - for(var/action_type in attack_action_types) - var/datum/action/innate/megafauna_attack/attack_action = new action_type() - attack_action.Grant(src) + grant_actions_by_list(attack_action_types) /mob/living/simple_animal/hostile/megafauna/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) //Safety check diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm index 113f7431ffc5ca..2e562eb5659064 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm @@ -67,21 +67,23 @@ Difficulty: Medium . = ..() miner_saw = new(src) ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT) - dash = new /datum/action/cooldown/mob_cooldown/dash() - kinetic_accelerator = new /datum/action/cooldown/mob_cooldown/projectile_attack/kinetic_accelerator() - dash_attack = new /datum/action/cooldown/mob_cooldown/dash_attack() - transform_weapon = new /datum/action/cooldown/mob_cooldown/transform_weapon() + + dash = new /datum/action/cooldown/mob_cooldown/dash + kinetic_accelerator = new /datum/action/cooldown/mob_cooldown/projectile_attack/kinetic_accelerator + dash_attack = new /datum/action/cooldown/mob_cooldown/dash_attack + transform_weapon = new /datum/action/cooldown/mob_cooldown/transform_weapon dash.Grant(src) kinetic_accelerator.Grant(src) dash_attack.Grant(src) transform_weapon.Grant(src) + AddComponent(/datum/component/boss_music, 'sound/lavaland/bdm_boss.ogg', 167 SECONDS) /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Destroy() - QDEL_NULL(dash) - QDEL_NULL(kinetic_accelerator) - QDEL_NULL(dash_attack) - QDEL_NULL(transform_weapon) + dash = null + kinetic_accelerator = null + dash_attack = null + transform_weapon = null return ..() /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index a1336bd6a09c48..eaeaddc3e03ee2 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -86,10 +86,10 @@ Difficulty: Hard /mob/living/simple_animal/hostile/megafauna/bubblegum/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT) - triple_charge = new /datum/action/cooldown/mob_cooldown/charge/triple_charge() - hallucination_charge = new /datum/action/cooldown/mob_cooldown/charge/hallucination_charge() - hallucination_charge_surround = new /datum/action/cooldown/mob_cooldown/charge/hallucination_charge/hallucination_surround() - blood_warp = new /datum/action/cooldown/mob_cooldown/blood_warp() + triple_charge = new(src) + hallucination_charge = new(src) + hallucination_charge_surround = new(src) + blood_warp = new(src) triple_charge.Grant(src) hallucination_charge.Grant(src) hallucination_charge_surround.Grant(src) @@ -105,10 +105,10 @@ Difficulty: Hard sound_volume = 200) /mob/living/simple_animal/hostile/megafauna/bubblegum/Destroy() - QDEL_NULL(triple_charge) - QDEL_NULL(hallucination_charge) - QDEL_NULL(hallucination_charge_surround) - QDEL_NULL(blood_warp) + triple_charge = null + hallucination_charge = null + hallucination_charge_surround = null + blood_warp = null return ..() /mob/living/simple_animal/hostile/megafauna/bubblegum/update_cooldowns(list/cooldown_updates, ignore_staggered = FALSE) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 10873e398e5905..9abc10c86b448a 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -71,11 +71,11 @@ /mob/living/simple_animal/hostile/megafauna/colossus/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT) //we don't want this guy to float, messes up his animations. - spiral_shots = new /datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/colossus() - random_shots = new /datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe/colossus() - shotgun_blast = new /datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/colossus() - dir_shots = new /datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating/colossus() - colossus_final = new /datum/action/cooldown/mob_cooldown/projectile_attack/colossus_final() + spiral_shots = new(src) + random_shots = new(src) + shotgun_blast = new(src) + dir_shots = new(src) + colossus_final = new(src) spiral_shots.Grant(src) random_shots.Grant(src) shotgun_blast.Grant(src) @@ -87,10 +87,10 @@ /mob/living/simple_animal/hostile/megafauna/colossus/Destroy() RemoveElement(/datum/element/projectile_shield) - QDEL_NULL(spiral_shots) - QDEL_NULL(random_shots) - QDEL_NULL(shotgun_blast) - QDEL_NULL(dir_shots) + spiral_shots = null + random_shots = null + shotgun_blast = null + dir_shots = null return ..() /mob/living/simple_animal/hostile/megafauna/colossus/OpenFire() @@ -512,7 +512,13 @@ if(..() && !ready_to_deploy) SSpoints_of_interest.make_point_of_interest(src) ready_to_deploy = TRUE - notify_ghosts("An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.", ghost_sound = 'sound/effects/ghost2.ogg', source = src, action = NOTIFY_PLAY, header = "Anomalous crystal activated") + notify_ghosts( + "An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.", + ghost_sound = 'sound/effects/ghost2.ogg', + source = src, + action = NOTIFY_PLAY, + header = "Anomalous crystal activated", + ) /obj/machinery/anomalous_crystal/helpers/attack_ghost(mob/dead/observer/user) . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm index aac1964cbf2fd6..dc49d71f796085 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm @@ -62,12 +62,12 @@ Difficulty: Extremely Hard /mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Initialize(mapload) . = ..() - frost_orbs = new /datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/shrapnel() - hard_frost_orbs = new /datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/shrapnel/strong() - snowball_machine_gun = new /datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire() - hard_snowball_machine_gun = new /datum/action/cooldown/mob_cooldown/direct_and_aoe() - ice_shotgun = new /datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/pattern() - hard_ice_shotgun = new /datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/pattern/circular() + frost_orbs = new(src) + hard_frost_orbs = new(src) + snowball_machine_gun = new(src) + hard_snowball_machine_gun = new(src) + ice_shotgun = new(src) + hard_ice_shotgun = new(src) frost_orbs.Grant(src) hard_frost_orbs.Grant(src) snowball_machine_gun.Grant(src) @@ -83,12 +83,12 @@ Difficulty: Extremely Hard AddComponent(/datum/component/boss_music, 'sound/lavaland/bdm_boss.ogg', 167 SECONDS) /mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Destroy() - QDEL_NULL(frost_orbs) - QDEL_NULL(hard_frost_orbs) - QDEL_NULL(snowball_machine_gun) - QDEL_NULL(hard_snowball_machine_gun) - QDEL_NULL(ice_shotgun) - QDEL_NULL(hard_ice_shotgun) + frost_orbs = null + hard_frost_orbs = null + snowball_machine_gun = null + hard_snowball_machine_gun = null + ice_shotgun = null + hard_ice_shotgun = null return ..() /mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/OpenFire() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index 5008d4b1748ed0..6132d1740deae5 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -80,10 +80,10 @@ /mob/living/simple_animal/hostile/megafauna/dragon/Initialize(mapload) . = ..() - fire_cone = new /datum/action/cooldown/mob_cooldown/fire_breath/cone() - meteors = new /datum/action/cooldown/mob_cooldown/meteors() - mass_fire = new /datum/action/cooldown/mob_cooldown/fire_breath/mass_fire() - lava_swoop = new /datum/action/cooldown/mob_cooldown/lava_swoop() + fire_cone = new(src) + meteors = new(src) + mass_fire = new(src) + lava_swoop = new(src) fire_cone.Grant(src) meteors.Grant(src) mass_fire.Grant(src) @@ -95,10 +95,10 @@ AddElement(/datum/element/change_force_on_death, move_force = MOVE_FORCE_DEFAULT) /mob/living/simple_animal/hostile/megafauna/dragon/Destroy() - QDEL_NULL(fire_cone) - QDEL_NULL(meteors) - QDEL_NULL(mass_fire) - QDEL_NULL(lava_swoop) + fire_cone = null + meteors = null + mass_fire = null + lava_swoop = null return ..() /mob/living/simple_animal/hostile/megafauna/dragon/OpenFire() diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm index 881a6cf17d69ae..798fd51d692085 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm @@ -29,9 +29,7 @@ /mob/living/simple_animal/hostile/asteroid/elite/Initialize(mapload) . = ..() AddComponent(/datum/component/seethrough_mob) - for(var/action_type in attack_action_types) - var/datum/action/innate/elite_attack/attack_action = new action_type() - attack_action.Grant(src) + grant_actions_by_list(attack_action_types) //Prevents elites from attacking members of their faction (can't hurt themselves either) and lets them mine rock with an attack despite not being able to smash walls. /mob/living/simple_animal/hostile/asteroid/elite/AttackingTarget(atom/attacked_target) @@ -214,7 +212,13 @@ While using this makes the system rely on OnFire, it still gives options for tim if(boosted) mychild.key = elitemind.key mychild.sentience_act() - notify_ghosts("\A [mychild] has been awakened in \the [get_area(src)]!", source = mychild, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Lavaland Elite awakened") + notify_ghosts( + "\A [mychild] has been awakened in \the [get_area(src)]!", + source = mychild, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Lavaland Elite awakened", + ) mychild.log_message("has been awakened by [key_name(activator)]!", LOG_GAME, color="#960000") icon_state = "tumor_popped" RegisterSignal(mychild, COMSIG_QDELETING, PROC_REF(onEliteLoss)) @@ -228,7 +232,13 @@ While using this makes the system rely on OnFire, it still gives options for tim if(boosted) mychild.maxHealth = mychild.maxHealth * 2 mychild.health = mychild.maxHealth - notify_ghosts("\A [mychild] has been challenged in \the [get_area(src)]!", source = mychild, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Lavaland Elite challenged") + notify_ghosts( + "\A [mychild] has been challenged in \the [get_area(src)]!", + source = mychild, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Lavaland Elite challenged", + ) mychild.log_message("has been challenged by [key_name(activator)]!", LOG_GAME, color="#960000") /obj/structure/elite_tumor/Initialize(mapload) diff --git a/code/modules/mob/living/simple_animal/hostile/ooze.dm b/code/modules/mob/living/simple_animal/hostile/ooze.dm index d4f86d3905d06e..714e3f1b600667 100644 --- a/code/modules/mob/living/simple_animal/hostile/ooze.dm +++ b/code/modules/mob/living/simple_animal/hostile/ooze.dm @@ -41,6 +41,8 @@ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) AddElement(/datum/element/content_barfer) + grant_actions_by_list(get_innate_actions()) + /mob/living/simple_animal/hostile/ooze/attacked_by(obj/item/I, mob/living/user) if(!eat_atom(I, TRUE)) return ..() @@ -71,6 +73,10 @@ if(ooze_nutrition <= 0) adjustBruteLoss(0.25 * seconds_per_tick) +/// Returns an applicable list of actions to grant to the mob. Will return a list or null. +/mob/living/simple_animal/hostile/ooze/proc/get_innate_actions() + return null + ///Does ooze_nutrition + supplied amount and clamps it within 0 and 500 /mob/living/simple_animal/hostile/ooze/proc/adjust_ooze_nutrition(amount) ooze_nutrition = clamp(ooze_nutrition + amount, 0, 500) @@ -106,23 +112,20 @@ armour_penetration = 15 obj_damage = 20 death_message = "collapses into a pile of goo!" - ///The ability to give yourself a metabolic speed boost which raises heat - var/datum/action/cooldown/metabolicboost/boost ///The ability to consume mobs var/datum/action/consume/consume ///Initializes the mobs abilities and gives them to the mob /mob/living/simple_animal/hostile/ooze/gelatinous/Initialize(mapload) . = ..() - boost = new - boost.Grant(src) consume = new consume.Grant(src) -/mob/living/simple_animal/hostile/ooze/gelatinous/Destroy() - . = ..() - QDEL_NULL(boost) - QDEL_NULL(consume) +/mob/living/simple_animal/hostile/ooze/gelatinous/get_innate_actions() + var/static/list/innate_actions = list( + /datum/action/cooldown/metabolicboost, + ) + return innate_actions ///If this mob gets resisted by something, its trying to escape consumption. /mob/living/simple_animal/hostile/ooze/gelatinous/container_resist_act(mob/living/user) @@ -284,20 +287,19 @@ obj_damage = 15 death_message = "deflates and spills its vital juices!" edible_food_types = MEAT | VEGETABLES - ghost_controllable = TRUE //SKYRAT EDIT ADDITION - These guys can be helpful... maybe players will be helpful. -/mob/living/simple_animal/hostile/ooze/grapes/Initialize(mapload) - . = ..() - var/datum/action/cooldown/globules/glob_shooter = new(src) - glob_shooter.Grant(src) - var/datum/action/cooldown/gel_cocoon/gel_cocoon = new(src) - gel_cocoon.Grant(src) +/mob/living/simple_animal/hostile/ooze/grapes/get_innate_actions() + var/static/list/innate_actions = list( + /datum/action/cooldown/globules, + /datum/action/cooldown/gel_cocoon, + ) + return innate_actions /mob/living/simple_animal/hostile/ooze/grapes/add_cell_sample() AddElement(/datum/element/swabable, CELL_LINE_TABLE_GRAPE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) -///Ability that allows the owner to fire healing globules at mobs, targetting specific limbs. +///Ability that allows the owner to fire healing globules at mobs, targeting specific limbs. /datum/action/cooldown/globules name = "Fire Mending globule" desc = "Fires a mending globule at someone, healing a specific limb of theirs." diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm deleted file mode 100644 index 24503f89bfdf14..00000000000000 --- a/code/modules/mob/living/simple_animal/hostile/pirate.dm +++ /dev/null @@ -1,91 +0,0 @@ -/mob/living/simple_animal/hostile/pirate - name = "Pirate" - desc = "Does what he wants cause a pirate is free." - icon = 'icons/mob/simple/simple_human.dmi' - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID - sentience_type = SENTIENCE_HUMANOID - speak_chance = 0 - turns_per_move = 5 - response_help_continuous = "pushes" - response_help_simple = "push" - speed = 0 - maxHealth = 100 - health = 100 - harm_intent_damage = 5 - melee_damage_lower = 10 - melee_damage_upper = 10 - attack_verb_continuous = "punches" - attack_verb_simple = "punch" - attack_sound = 'sound/weapons/punch1.ogg' - combat_mode = TRUE - atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) - unsuitable_atmos_damage = 7.5 - speak_emote = list("yarrs") - loot = list(/obj/effect/mob_spawn/corpse/human/pirate) - del_on_death = TRUE - faction = list(FACTION_PIRATE) - /// Path of the mob spawner we base the mob's visuals off of. - var/mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate - /// Path of the held item we give to the mob's visuals. - var/held_item - -/mob/living/simple_animal/hostile/pirate/Initialize(mapload) - . = ..() - apply_dynamic_human_appearance(src, mob_spawn_path = mob_spawner, r_hand = held_item) - -/mob/living/simple_animal/hostile/pirate/melee - name = "Pirate Swashbuckler" - melee_damage_lower = 30 - melee_damage_upper = 30 - armour_penetration = 35 - attack_verb_continuous = "slashes" - attack_verb_simple = "slash" - attack_sound = 'sound/weapons/blade1.ogg' - attack_vis_effect = ATTACK_EFFECT_SLASH - loot = list(/obj/effect/mob_spawn/corpse/human/pirate/melee) - light_range = 2 - light_power = 2.5 - light_color = COLOR_SOFT_RED - footstep_type = FOOTSTEP_MOB_SHOE - loot = list( - /obj/effect/mob_spawn/corpse/human/pirate/melee, - /obj/item/melee/energy/sword/pirate, - ) - mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/melee - held_item = /obj/item/melee/energy/sword/pirate - -/mob/living/simple_animal/hostile/pirate/melee/space - name = "Space Pirate Swashbuckler" - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - speed = 1 - mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/melee/space - -/mob/living/simple_animal/hostile/pirate/melee/space/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) - -/mob/living/simple_animal/hostile/pirate/ranged - name = "Pirate Gunner" - projectilesound = 'sound/weapons/laser.ogg' - ranged = 1 - rapid = 2 - rapid_fire_delay = 6 - retreat_distance = 5 - minimum_distance = 5 - projectiletype = /obj/projectile/beam/laser - loot = list(/obj/effect/mob_spawn/corpse/human/pirate/ranged) - mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/ranged - held_item = /obj/item/gun/energy/laser - -/mob/living/simple_animal/hostile/pirate/ranged/space - name = "Space Pirate Gunner" - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - speed = 1 - mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/ranged/space - held_item = /obj/item/gun/energy/e_gun/lethal - -/mob/living/simple_animal/hostile/pirate/ranged/space/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/trader.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/trader.dm deleted file mode 100644 index 5be6fc9575d8fd..00000000000000 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/trader.dm +++ /dev/null @@ -1,501 +0,0 @@ -#define ITEM_REJECTED_PHRASE "ITEM_REJECTED_PHRASE" -#define ITEM_SELLING_CANCELED_PHRASE "ITEM_SELLING_CANCELED_PHRASE" -#define ITEM_SELLING_ACCEPTED_PHRASE "ITEM_SELLING_ACCEPTED_PHRASE" -#define INTERESTED_PHRASE "INTERESTED_PHRASE" -#define BUY_PHRASE "BUY_PHRASE" -#define NO_CASH_PHRASE "NO_CASH_PHRASE" -#define NO_STOCK_PHRASE "NO_STOCK_PHRASE" -#define NOT_WILLING_TO_BUY_PHRASE "NOT_WILLING_TO_BUY_PHRASE" -#define ITEM_IS_WORTHLESS_PHRASE "ITEM_IS_WORTHLESS_PHRASE" -#define TRADER_HAS_ENOUGH_ITEM_PHRASE "TRADER_HAS_ENOUGH_ITEM_PHRASE" -#define TRADER_LORE_PHRASE "TRADER_LORE_PHRASE" -#define TRADER_NOT_BUYING_ANYTHING "TRADER_NOT_BUYING_ANYTHING" -#define TRADER_NOT_SELLING_ANYTHING "TRADER_NOT_SELLING_ANYTHING" - -#define TRADER_PRODUCT_INFO_PRICE 1 -#define TRADER_PRODUCT_INFO_QUANTITY 2 -//Only valid for wanted_items -#define TRADER_PRODUCT_INFO_PRICE_MOD_DESCRIPTION 3 - -/** - * # Trader - * - * A mob that has some dialogue options with radials, allows for selling items and buying em' - * - */ -/mob/living/simple_animal/hostile/retaliate/trader - name = "Trader" - desc = "Come buy some!" - icon = 'icons/mob/simple/traders.dmi' - icon_state = "faceless" - maxHealth = 200 - health = 200 - melee_damage_lower = 10 - melee_damage_upper = 10 - attack_verb_continuous = "punches" - attack_verb_simple = "punch" - attack_sound = 'sound/weapons/punch1.ogg' - del_on_death = TRUE - loot = list(/obj/effect/mob_spawn/corpse/human) - atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) - unsuitable_atmos_damage = 2.5 - casingtype = /obj/item/ammo_casing/shotgun/buckshot - wander = FALSE - ranged = TRUE - combat_mode = TRUE - move_resist = MOVE_FORCE_STRONG - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID - sentience_type = SENTIENCE_HUMANOID - speed = 0 - stat_attack = HARD_CRIT - robust_searching = TRUE - check_friendly_fire = TRUE - interaction_flags_atom = INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND|INTERACT_ATOM_ATTACK_HAND|INTERACT_ATOM_NO_FINGERPRINT_INTERACT - ///Sound used when item sold/bought - var/sell_sound = 'sound/effects/cashregister.ogg' - /** - * Format; list(TYPEPATH = list(PRICE, QUANTITY)) - * Associated list of items the NPC sells with how much they cost and the quantity available before a restock - * This list is filled by Initialize(), if you want to change the starting products, modify initial_products() - * * - */ - var/list/products - /** - * A list of wanted items that the trader would wish to buy, each typepath has a assigned value, quantity and additional flavor text - * - * CHILDREN OF TYPEPATHS INCLUDED IN WANTED_ITEMS WILL BE TREATED AS THE PARENT IF NO ENTRY EXISTS FOR THE CHILDREN - * - * As an additional note; if you include multiple children of a typepath; the typepath with the most children should be placed after all other typepaths - * Bad; list(/obj/item/milk = list(100, 1, ""), /obj/item/milk/small = list(50, 2, "")) - * Good; list(/obj/item/milk/small = list(50, 2, ""), /obj/item/milk = list(100, 1, "")) - * This is mainly because sell_item() uses a istype(item_being_sold, item_in_entry) to determine what parent should the child be automatically considered as - * If /obj/item/milk/small/spooky was being sold; /obj/item/milk/small would be the first to check against rather than /obj/item/milk - * - * Format; list(TYPEPATH = list(PRICE, QUANTITY, ADDITIONAL_DESCRIPTION)) - * Associated list of items able to be sold to the NPC with the money given for them. - * The price given should be the "base" price; any price manipulation based on variables should be done with apply_sell_price_mods() - * ADDITIONAL_DESCRIPTION is any additional text added to explain how the variables of the item effect the price; if it's stack based, it's final price depends how much is in the stack - * EX; /obj/item/stack/sheet/mineral/diamond = list(500, INFINITY, ", per 100 cm3 sheet of diamond") - * This list is filled by Initialize(), if you want to change the starting wanted items, modify initial_wanteds() - */ - var/list/wanted_items - ///Associated list of defines matched with list of phrases; phrase to be said is dealt by return_trader_phrase() - var/list/say_phrases = list( - ITEM_REJECTED_PHRASE = list( - "Sorry, I'm not a fan of anything you're showing me. Give me something better and we'll talk." - ), - ITEM_SELLING_CANCELED_PHRASE = list( - "What a shame, tell me if you changed your mind." - ), - ITEM_SELLING_ACCEPTED_PHRASE = list( - "Pleasure doing business with you." - ), - INTERESTED_PHRASE = list( - "Hey, you've got an item that interests me, I'd like to buy it, I'll give you some cash for it, deal?" - ), - BUY_PHRASE = list( - "Pleasure doing business with you." - ), - NO_CASH_PHRASE = list( - "Sorry adventurer, I can't give credit! Come back when you're a little mmmmm... richer!" - ), - NO_STOCK_PHRASE = list( - "Sorry adventurer, but that item is not in stock at the moment." - ), - NOT_WILLING_TO_BUY_PHRASE = list( - "I don't want to buy that item for the time being, check back another time." - ), - ITEM_IS_WORTHLESS_PHRASE = list( - "This item seems to be worthless on a closer look, I won't buy this." - ), - TRADER_HAS_ENOUGH_ITEM_PHRASE = list( - "I already bought enough of this for the time being." - ), - TRADER_LORE_PHRASE = list( - "Hello! I am the test trader.", - "Oooooooo~!" - ), - TRADER_NOT_BUYING_ANYTHING = list( - "I'm currently buying nothing at the moment." - ), - TRADER_NOT_SELLING_ANYTHING = list( - "I'm currently selling nothing at the moment." - ), - ) - ///The name of the currency that is used when buying or selling items - var/currency_name = "credits" - -///Initializes the products and item demands of the trader -/mob/living/simple_animal/hostile/retaliate/trader/Initialize(mapload) - . = ..() - restock_products() - renew_item_demands() - -///Returns a list of the starting price/quanity/fluff text about the product listings; products = initial(products) doesn't work so this exists mainly for restock_products() -/mob/living/simple_animal/hostile/retaliate/trader/proc/initial_products() - return list(/obj/item/food/burger/ghost = list(200, INFINITY), - ) - -///Returns a list of the starting price/quanity/fluff text about the wanted items; wanted_items = initial(wanted_items) doesn't work so this exists mainly for renew_item_demands() -/mob/living/simple_animal/hostile/retaliate/trader/proc/initial_wanteds() - return list(/obj/item/ectoplasm = list(100, INFINITY, ""), - ) - -/** - * Depending on the passed parameter/override, returns a randomly picked string out of a list - * - * Do note when overriding this argument, you will need to ensure pick(the list) doesn't get supplied with a list of zero length - * Arguments: - * * say_text - (String) a define that matches the key of a entry in say_phrases - */ -/mob/living/simple_animal/hostile/retaliate/trader/proc/return_trader_phrase(say_text) - if(!length(say_phrases[say_text])) - return - return pick(say_phrases[say_text]) - //return (length(say_phrases[say_text]) ? pick(say_phrases[say_text]) : "") - -///Sets up the radials for the user and calls procs related to the actions the user wants to take -/mob/living/simple_animal/hostile/retaliate/trader/interact(mob/user) - if(user == target) - return FALSE - var/list/npc_options = list() - if(products.len) - npc_options["Buy"] = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_buy") - if(length(say_phrases[TRADER_LORE_PHRASE])) - npc_options["Talk"] = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_talk") - if(wanted_items.len) - npc_options["Sell"] = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_sell") - if(!npc_options.len) - return FALSE - var/npc_result = show_radial_menu(user, src, npc_options, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE) - switch(npc_result) - if("Buy") - buy_item(user) - if("Sell") - try_sell(user) - if("Talk") - discuss(user) - face_atom(user) - return TRUE - -/** - * Checks if the user is ok to use the radial - * - * Checks if the user is not a mob or is incapacitated or not adjacent to the source of the radial, in those cases returns FALSE, otherwise returns TRUE - * Arguments: - * * user - (Mob REF) The mob checking the menu - */ -/mob/living/simple_animal/hostile/retaliate/trader/proc/check_menu(mob/user) - if(!istype(user)) - return FALSE - if(user.incapacitated() || !user.Adjacent(src)) - return FALSE - return TRUE - -///Talk about what items are being sold/wanted by the trader and in what quantity or lore -/mob/living/simple_animal/hostile/retaliate/trader/proc/discuss(mob/user) - var/list/npc_options = list( - "Lore" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_lore"), - "Selling?" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_selling"), - "Buying?" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_buying"), - ) - var/pick = show_radial_menu(user, src, npc_options, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE) - switch(pick) - if("Lore") - say(return_trader_phrase(TRADER_LORE_PHRASE)) - if("Buying?") - trader_buys_what(user) - if("Selling?") - trader_sells_what(user) - -///Displays to the user what the trader is willing to buy and how much until a restock happens -/mob/living/simple_animal/hostile/retaliate/trader/proc/trader_buys_what(mob/user) - if(!wanted_items.len) - say(return_trader_phrase(TRADER_NOT_BUYING_ANYTHING)) - return - var/list/product_info - to_chat(user, span_green("I'm willing to buy the following; ")) - for(var/obj/item/thing as anything in wanted_items) - product_info = wanted_items[thing] - var/tern_op_result = (product_info[TRADER_PRODUCT_INFO_QUANTITY] == INFINITY ? "as many as I can." : "[product_info[TRADER_PRODUCT_INFO_QUANTITY]]") //Coder friendly string concat - if(product_info[TRADER_PRODUCT_INFO_QUANTITY] <= 0) //Zero demand - to_chat(user, span_notice("[span_red("(DOESN'T WANT MORE)")] [initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [currency_name][product_info[TRADER_PRODUCT_INFO_PRICE_MOD_DESCRIPTION]]; willing to buy [span_red("[tern_op_result]")] more.")) - else - to_chat(user, span_notice("[initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [currency_name][product_info[TRADER_PRODUCT_INFO_PRICE_MOD_DESCRIPTION]]; willing to buy [span_green("[tern_op_result]")]")) - -///Displays to the user what the trader is selling and how much is in stock -/mob/living/simple_animal/hostile/retaliate/trader/proc/trader_sells_what(mob/user) - if(!products.len) - say(return_trader_phrase(TRADER_NOT_SELLING_ANYTHING)) - return - var/list/product_info - to_chat(user, span_green("I'm currently selling the following; ")) - for(var/obj/item/thing as anything in products) - product_info = products[thing] - var/tern_op_result = (product_info[TRADER_PRODUCT_INFO_QUANTITY] == INFINITY ? "an infinite amount" : "[product_info[TRADER_PRODUCT_INFO_QUANTITY]]") //Coder friendly string concat - if(product_info[TRADER_PRODUCT_INFO_QUANTITY] <= 0) //Out of stock - to_chat(user, span_notice("[span_red("(OUT OF STOCK)")] [initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [currency_name]; [span_red("[tern_op_result]")] left in stock")) - else - to_chat(user, span_notice("[initial(thing.name)] for [product_info[TRADER_PRODUCT_INFO_PRICE]] [currency_name]; [span_green("[tern_op_result]")] left in stock")) - -/** - * Generates a radial of the items the NPC sells and lets the user try to buy one - * Arguments: - * * user - (Mob REF) The mob trying to buy something - */ -/mob/living/simple_animal/hostile/retaliate/trader/proc/buy_item(mob/user) - if(!LAZYLEN(products)) - return - - var/list/display_names = list() - var/list/items = list() - var/list/product_info - for(var/obj/item/thing as anything in products) - display_names["[initial(thing.name)]"] = thing - var/image/item_image = image(icon = initial(thing.icon), icon_state = initial(thing.icon_state)) - product_info = products[thing] - if(product_info[TRADER_PRODUCT_INFO_QUANTITY] <= 0) //out of stock - item_image.overlays += image(icon = 'icons/hud/radial.dmi', icon_state = "radial_center") - items += list("[initial(thing.name)]" = item_image) - var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE) - if(!pick) - return - var/obj/item/item_to_buy = display_names[pick] - face_atom(user) - product_info = products[item_to_buy] - if(!product_info[TRADER_PRODUCT_INFO_QUANTITY]) - say("[initial(item_to_buy.name)] appears to be out of stock.") - return - say("It will cost you [product_info[TRADER_PRODUCT_INFO_PRICE]] [currency_name] to buy \the [initial(item_to_buy.name)]. Are you sure you want to buy it?") - var/list/npc_options = list( - "Yes" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_yes"), - "No" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_no") - ) - var/buyer_will_buy = show_radial_menu(user, src, npc_options, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE) - if(buyer_will_buy != "Yes") - return - face_atom(user) - if(!spend_buyer_offhand_money(user, product_info[TRADER_PRODUCT_INFO_PRICE])) - say(return_trader_phrase(NO_CASH_PHRASE)) - return - item_to_buy = new item_to_buy(get_turf(user)) - user.put_in_hands(item_to_buy) - playsound(src, sell_sound, 50, TRUE) - product_info[TRADER_PRODUCT_INFO_QUANTITY] -= 1 - say(return_trader_phrase(BUY_PHRASE)) - -///Calculates the value of money in the hand of the buyer and spends it if it's sufficient -/mob/living/simple_animal/hostile/retaliate/trader/proc/spend_buyer_offhand_money(mob/user, the_cost) - var/value = 0 - var/obj/item/holochip/cash = user.is_holding_item_of_type(/obj/item/holochip) - if(cash) - value += cash.credits - if((value >= the_cost) && cash) - return cash.spend(the_cost) - return FALSE //Purchase unsuccessful - -/** - * Tries to call sell_item on one of the user's held items, if fail gives a chat message - * - * Gets both items in the user's hands, and then tries to call sell_item on them, if both fail, he gives a chat message - * Arguments: - * * user - (Mob REF) The mob trying to sell something - */ -/mob/living/simple_animal/hostile/retaliate/trader/proc/try_sell(mob/user) - var/sold_item = FALSE - for(var/obj/item/an_item in user.held_items) - if(sell_item(user, an_item)) - sold_item = TRUE - break - if(!sold_item) - say(return_trader_phrase(ITEM_REJECTED_PHRASE)) - -/** - * Checks if an item is in the list of wanted items and if it is after a Yes/No radial returns generate_cash with the value of the item for the NPC - * Arguments: - * * user - (Mob REF) The mob trying to sell something - * * selling - (Item REF) The item being sold - */ -/mob/living/simple_animal/hostile/retaliate/trader/proc/sell_item(mob/user, obj/item/selling) - var/cost - if(!selling) - return FALSE - var/list/product_info - //Keep track of the typepath; rather mundane but it's required for correctly modifying the wanted_items - //should a product be sellable because even if it doesn't have a entry because it's a child of a parent that is present on the list - var/typepath_for_product_info - if(selling.type in wanted_items) - product_info = wanted_items[selling.type] - typepath_for_product_info = selling.type - else //Assume wanted_items is setup in the correct way; read wanted_items documentation for more info - for(var/typepath in wanted_items) - if(istype(selling, typepath)) - product_info = wanted_items[typepath] - typepath_for_product_info = typepath - break - - if(!product_info) //Nothing interesting to sell - return FALSE - if(product_info[TRADER_PRODUCT_INFO_QUANTITY] <= 0) - say(return_trader_phrase(TRADER_HAS_ENOUGH_ITEM_PHRASE)) - return FALSE - cost = apply_sell_price_mods(selling, product_info[TRADER_PRODUCT_INFO_PRICE]) - if(cost <= 0) - say(return_trader_phrase(ITEM_IS_WORTHLESS_PHRASE)) - return FALSE - say(return_trader_phrase(INTERESTED_PHRASE)) - say("You will receive [cost] [currency_name] for the [selling].") - var/list/npc_options = list( - "Yes" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_yes"), - "No" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_no"), - ) - face_atom(user) - var/npc_result = show_radial_menu(user, src, npc_options, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE) - if(npc_result != "Yes") - say(return_trader_phrase(ITEM_SELLING_CANCELED_PHRASE)) - return TRUE - say(return_trader_phrase(ITEM_SELLING_ACCEPTED_PHRASE)) - playsound(src, sell_sound, 50, TRUE) - log_econ("[selling] has been sold to [src] (typepath used for product info; [typepath_for_product_info]) by [user] for [cost] cash.") - exchange_sold_items(selling, cost, typepath_for_product_info) - generate_cash(cost, user) - return TRUE - -/** - * Handles modifying/deleting the items to ensure that a proper amount is converted into cash; put into it's own proc to make the children of this not override a 30+ line sell_item() - * - * Arguments: - * * selling - (Item REF) this is the item being sold - * * value_exchanged_for - (Number) the "value", useful for a scenario where you want to remove enough items equal to the value - * * original_typepath - (Typepath) For scenarios where a children of a parent is being sold but we want to modify the parent's product information - */ -/mob/living/simple_animal/hostile/retaliate/trader/proc/exchange_sold_items(obj/item/selling, value_exchanged_for, original_typepath) - var/list/product_info = wanted_items[original_typepath] - if(isstack(selling)) - var/obj/item/stack/the_stack = selling - var/actually_sold = min(the_stack.amount, product_info[TRADER_PRODUCT_INFO_QUANTITY]) - the_stack.use(actually_sold) - product_info[TRADER_PRODUCT_INFO_QUANTITY] -= (actually_sold) - else - qdel(selling) - product_info[TRADER_PRODUCT_INFO_QUANTITY] -= 1 - -/** - * Modifies the 'base' price of a item based on certain variables - * - * Arguments: - * * Reference to the item; this is the item being sold - * * Original cost; the original cost of the item, to be manipulated depending on the variables of the item, one example is using item.amount if it's a stack - */ -/mob/living/simple_animal/hostile/retaliate/trader/proc/apply_sell_price_mods(obj/item/selling, original_cost) - if(isstack(selling)) - var/obj/item/stack/stackoverflow = selling - original_cost *= stackoverflow.amount - return original_cost - -/** - * Creates an item equal to the value set by the proc and puts it in the user's hands if possible - * Arguments: - * * value - A number; The amount of cash that will be on the holochip - * * user - Reference to a mob; The mob we put the holochip in hands of - */ -/mob/living/simple_animal/hostile/retaliate/trader/proc/generate_cash(value, mob/user) - var/obj/item/holochip/chip = new /obj/item/holochip(get_turf(user), value) - user.put_in_hands(chip) - -///Sets quantity of all products to initial(quanity); this proc is currently not called anywhere on the base class of traders -/mob/living/simple_animal/hostile/retaliate/trader/proc/restock_products() - products = initial_products() - -///Sets quantity of all wanted_items to initial(quanity); this proc is currently not called anywhere on the base class of traders -/mob/living/simple_animal/hostile/retaliate/trader/proc/renew_item_demands() - wanted_items = initial_wanteds() - -/mob/living/simple_animal/hostile/retaliate/trader/mrbones - name = "Mr. Bones" - desc = "A skeleton merchant, he seems very humerus." - speak_emote = list("rattles") - speech_span = SPAN_SANS - sell_sound = 'sound/voice/hiss2.ogg' - mob_biotypes = MOB_UNDEAD|MOB_HUMANOID - icon_state = "mrbones" - gender = MALE - loot = list(/obj/effect/decal/remains/human) - - say_phrases = list( - ITEM_REJECTED_PHRASE = list( - "Sorry, I'm not a fan of anything you're showing me. Give me something better and we'll talk." - ), - ITEM_SELLING_CANCELED_PHRASE = list( - "What a shame, tell me if you changed your mind." - ), - ITEM_SELLING_ACCEPTED_PHRASE = list( - "Pleasure doing business with you." - ), - INTERESTED_PHRASE = list( - "Hey, you've got an item that interests me, I'd like to buy it, I'll give you some cash for it, deal?" - ), - BUY_PHRASE = list( - "Bone appetit!" - ), - NO_CASH_PHRASE = list( - "Sorry adventurer, I can't give credit! Come back when you're a little mmmmm... richer!" - ), - NO_STOCK_PHRASE = list( - "Sorry adventurer, but that item is not in stock at the moment." - ), - NOT_WILLING_TO_BUY_PHRASE = list( - "I don't want to buy that item for the time being, check back another time." - ), - ITEM_IS_WORTHLESS_PHRASE = list( - "This item seems to be worthless on a closer look, I won't buy this." - ), - TRADER_HAS_ENOUGH_ITEM_PHRASE = list( - "I already bought enough of this for the time being." - ), - TRADER_LORE_PHRASE = list( - "Hello, I am Mr. Bones!", - "The ride never ends!", - "I'd really like a refreshing carton of milk!", - "I'm willing to play big prices for BONES! Need materials to make merch, eh?", - "It's a beautiful day outside. Birds are singing, Flowers are blooming... On days like these, kids like you... Should be buying my wares!" - ), - TRADER_NOT_BUYING_ANYTHING = list( - "I'm currently buying nothing at the moment." - ), - TRADER_NOT_SELLING_ANYTHING = list( - "I'm currently selling nothing at the moment." - ), - ) - -/mob/living/simple_animal/hostile/retaliate/trader/mrbones/initial_products() - return list( - /obj/item/clothing/head/helmet/skull = list(150, INFINITY), - /obj/item/clothing/mask/bandana/skull/black = list(50, INFINITY), - /obj/item/food/cookie/sugar/spookyskull = list(10, INFINITY), - /obj/item/instrument/trombone/spectral = list(10000, INFINITY), - /obj/item/shovel/serrated = list(150, INFINITY), - ) - -/mob/living/simple_animal/hostile/retaliate/trader/mrbones/initial_wanteds() - return list( - /obj/item/reagent_containers/condiment/milk = list(1000, INFINITY, ""), - /obj/item/stack/sheet/bone = list(420, INFINITY, ", per sheet of bone"), - ) - -#undef ITEM_REJECTED_PHRASE -#undef ITEM_SELLING_CANCELED_PHRASE -#undef ITEM_SELLING_ACCEPTED_PHRASE -#undef INTERESTED_PHRASE -#undef BUY_PHRASE -#undef NO_CASH_PHRASE -#undef NO_STOCK_PHRASE -#undef NOT_WILLING_TO_BUY_PHRASE -#undef ITEM_IS_WORTHLESS_PHRASE -#undef TRADER_HAS_ENOUGH_ITEM_PHRASE -#undef TRADER_LORE_PHRASE -#undef TRADER_NOT_BUYING_ANYTHING -#undef TRADER_NOT_SELLING_ANYTHING -#undef TRADER_PRODUCT_INFO_PRICE -#undef TRADER_PRODUCT_INFO_QUANTITY -#undef TRADER_PRODUCT_INFO_PRICE_MOD_DESCRIPTION diff --git a/code/modules/mob/living/simple_animal/hostile/vatbeast.dm b/code/modules/mob/living/simple_animal/hostile/vatbeast.dm index 7c6edeb88da4ad..a0fe73b32bfe0e 100644 --- a/code/modules/mob/living/simple_animal/hostile/vatbeast.dm +++ b/code/modules/mob/living/simple_animal/hostile/vatbeast.dm @@ -28,8 +28,7 @@ /mob/living/simple_animal/hostile/vatbeast/Initialize(mapload) . = ..() - var/datum/action/cooldown/tentacle_slap/slapper = new(src) - slapper.Grant(src) + GRANT_ACTION(/datum/action/cooldown/tentacle_slap) add_cell_sample() AddComponent(/datum/component/tameable, list(/obj/item/food/fries, /obj/item/food/cheesyfries, /obj/item/food/cornchips, /obj/item/food/carrotfries), tame_chance = 30, bonus_tame_chance = 0, after_tame = CALLBACK(src, PROC_REF(tamed))) diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm deleted file mode 100644 index d2957effd3cf95..00000000000000 --- a/code/modules/mob/living/simple_animal/hostile/wizard.dm +++ /dev/null @@ -1,83 +0,0 @@ -/mob/living/simple_animal/hostile/wizard - name = "Space Wizard" - desc = "EI NATH?" - icon = 'icons/mob/simple/simple_human.dmi' - icon_state = "wizard" - icon_living = "wizard" - icon_dead = "wizard_dead" - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID - sentience_type = SENTIENCE_HUMANOID - speak_chance = 0 - turns_per_move = 3 - speed = 0 - maxHealth = 100 - health = 100 - harm_intent_damage = 5 - melee_damage_lower = 5 - melee_damage_upper = 5 - attack_verb_continuous = "punches" - attack_verb_simple = "punch" - attack_sound = 'sound/weapons/punch1.ogg' - combat_mode = TRUE - atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) - unsuitable_atmos_damage = 7.5 - faction = list(ROLE_WIZARD) - status_flags = CANPUSH - footstep_type = FOOTSTEP_MOB_SHOE - - retreat_distance = 3 //out of fireball range - minimum_distance = 3 - del_on_death = 1 - loot = list( - /obj/effect/mob_spawn/corpse/human/wizard, - /obj/item/staff, - ) - - var/next_cast = 0 - var/datum/action/cooldown/spell/pointed/projectile/fireball/fireball - var/datum/action/cooldown/spell/teleport/radius_turf/blink/blink - var/datum/action/cooldown/spell/aoe/magic_missile/magic_missile - -/mob/living/simple_animal/hostile/wizard/Initialize(mapload) - . = ..() - apply_dynamic_human_appearance(src, mob_spawn_path = /obj/effect/mob_spawn/corpse/human/wizard, r_hand = /obj/item/staff) - var/obj/item/implant/exile/exiled = new /obj/item/implant/exile(src) - exiled.implant(src) - - fireball = new(src) - fireball.spell_requirements &= ~(SPELL_REQUIRES_HUMAN|SPELL_REQUIRES_WIZARD_GARB|SPELL_REQUIRES_MIND) - fireball.Grant(src) - - magic_missile = new(src) - magic_missile.spell_requirements &= ~(SPELL_REQUIRES_HUMAN|SPELL_REQUIRES_WIZARD_GARB|SPELL_REQUIRES_MIND) - magic_missile.Grant(src) - - blink = new(src) - blink.spell_requirements &= ~(SPELL_REQUIRES_HUMAN|SPELL_REQUIRES_WIZARD_GARB|SPELL_REQUIRES_MIND) - blink.outer_tele_radius = 3 - blink.Grant(src) - -/mob/living/simple_animal/hostile/wizard/Destroy() - QDEL_NULL(fireball) - QDEL_NULL(magic_missile) - QDEL_NULL(blink) - return ..() - -/mob/living/simple_animal/hostile/wizard/handle_automated_action() - . = ..() - if(target && next_cast < world.time) - if((get_dir(src, target) in list(SOUTH, EAST, WEST, NORTH)) && fireball.can_cast_spell(feedback = FALSE)) - setDir(get_dir(src, target)) - fireball.Trigger(null, target) - next_cast = world.time + 1 SECONDS - return - - if(magic_missile.IsAvailable()) - magic_missile.Trigger(null, target) - next_cast = world.time + 1 SECONDS - return - - if(blink.IsAvailable()) // Spam Blink when you can - blink.Trigger(null, src) - next_cast = world.time + 1 SECONDS - return diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm deleted file mode 100644 index dbb795e91c5692..00000000000000 --- a/code/modules/mob/living/simple_animal/shade.dm +++ /dev/null @@ -1,71 +0,0 @@ -/mob/living/simple_animal/shade - name = "Shade" - real_name = "Shade" - desc = "A bound spirit." - gender = PLURAL - icon = 'icons/mob/nonhuman-player/cult.dmi' - icon_state = "shade_cult" - icon_living = "shade_cult" - mob_biotypes = MOB_SPIRIT - maxHealth = 40 - health = 40 - speak_emote = list("hisses") - emote_hear = list("wails.","screeches.") - response_help_continuous = "puts their hand through" - response_help_simple = "put your hand through" - response_disarm_continuous = "flails at" - response_disarm_simple = "flail at" - response_harm_continuous = "punches" - response_harm_simple = "punch" - speak_chance = 1 - melee_damage_lower = 5 - melee_damage_upper = 12 - attack_verb_continuous = "metaphysically strikes" - attack_verb_simple = "metaphysically strike" - minbodytemp = 0 - maxbodytemp = INFINITY - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - speed = -1 //they don't have to lug a body made of runed metal around - stop_automated_movement = 1 - faction = list(FACTION_CULT) - status_flags = CANPUSH - loot = list(/obj/item/ectoplasm) - del_on_death = TRUE - initial_language_holder = /datum/language_holder/construct - -/mob/living/simple_animal/shade/Initialize(mapload) - . = ..() - AddElement(/datum/element/simple_flying) - add_traits(list(TRAIT_HEALS_FROM_CULT_PYLONS, TRAIT_SPACEWALK, TRAIT_VENTCRAWLER_ALWAYS), INNATE_TRAIT) - -/mob/living/simple_animal/shade/death() - if(death_message == initial(death_message)) - death_message = "lets out a contented sigh as [p_their()] form unwinds." - ..() - -/mob/living/simple_animal/shade/can_suicide() - if(istype(loc, /obj/item/soulstone)) //do not suicide inside the soulstone - return FALSE - return ..() - -/mob/living/simple_animal/shade/attack_animal(mob/living/simple_animal/user, list/modifiers) - if(isconstruct(user)) - var/mob/living/simple_animal/hostile/construct/doll = user - if(!doll.can_repair) - return - if(health < maxHealth) - adjustHealth(-25) - Beam(user,icon_state="sendbeam", time = 4) - user.visible_message(span_danger("[user] heals \the [src]."), \ - span_cult("You heal [src], leaving [src] at [health]/[maxHealth] health.")) - else - to_chat(user, span_cult("You cannot heal [src], as [p_theyre()] unharmed!")) - else if(src != user) - return ..() - -/mob/living/simple_animal/shade/attackby(obj/item/item, mob/user, params) //Marker -Agouri - if(istype(item, /obj/item/soulstone)) - var/obj/item/soulstone/stone = item - stone.capture_shade(src, user) - else - . = ..() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 4c382a59b2f64e..ed304e276b0fda 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -133,9 +133,6 @@ ///Played when someone punches the creature. var/attacked_sound = SFX_PUNCH - ///If the creature has, and can use, hands. - var/dextrous = FALSE - ///The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever), AI_Z_OFF (Temporarily off due to nonpresence of players). var/AIStatus = AI_ON ///once we have become sentient, we can never go back. @@ -176,10 +173,6 @@ if(!loc) stack_trace("Simple animal being instantiated in nullspace") update_simplemob_varspeed() - if(dextrous) - AddElement(/datum/element/dextrous, hud_type = hud_type) - AddComponent(/datum/component/personal_crafting) - add_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP), ROUNDSTART_TRAIT) ADD_TRAIT(src, TRAIT_NOFIRE_SPREAD, ROUNDSTART_TRAIT) if(length(weather_immunities)) add_traits(weather_immunities, ROUNDSTART_TRAIT) diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm index 9e858d4f02d261..a485b8342ca310 100644 --- a/code/modules/mob/living/simple_animal/slime/powers.dm +++ b/code/modules/mob/living/simple_animal/slime/powers.dm @@ -164,8 +164,7 @@ amount_grown = 0 for(var/datum/action/innate/slime/evolve/E in actions) E.Remove(src) - var/datum/action/innate/slime/reproduce/reproduce_action = new - reproduce_action.Grant(src) + GRANT_ACTION(/datum/action/innate/slime/reproduce) regenerate_icons() update_name() else @@ -184,54 +183,62 @@ /mob/living/simple_animal/slime/verb/Reproduce() set category = "Slime" - set desc = "This will make you split into four Slimes." + set desc = "This will make you split into four slimes." - if(stat) - to_chat(src, "I must be conscious to do this...") + if(stat != CONSCIOUS) + balloon_alert(src, "need to be conscious to split!") return - if(is_adult) - if(amount_grown >= SLIME_EVOLUTION_THRESHOLD) - if(stat) - to_chat(src, "I must be conscious to do this...") - return - - var/list/babies = list() - var/new_nutrition = round(nutrition * 0.9) - var/new_powerlevel = round(powerlevel / 4) - var/turf/drop_loc = drop_location() - - for(var/i in 1 to 4) - var/child_colour - if(mutation_chance >= 100) - child_colour = SLIME_TYPE_RAINBOW - else if(prob(mutation_chance)) - child_colour = slime_mutation[rand(1,4)] - else - child_colour = colour - var/mob/living/simple_animal/slime/M - M = new(drop_loc, child_colour) - if(ckey) - M.set_nutrition(new_nutrition) //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature! - M.powerlevel = new_powerlevel - if(i != 1) - step_away(M,src) - M.set_friends(Friends) - babies += M - M.mutation_chance = clamp(mutation_chance+(rand(5,-5)),0,100) - SSblackbox.record_feedback("tally", "slime_babies_born", 1, M.colour) - - var/mob/living/simple_animal/slime/new_slime = pick(babies) - new_slime.set_combat_mode(TRUE) - if(src.mind) - src.mind.transfer_to(new_slime) - else - new_slime.key = src.key - qdel(src) + if(!isopenturf(loc)) + balloon_alert(src, "can't reproduce here!") + + if(!is_adult) + balloon_alert(src, "not old enough to reproduce!") + return + + if(amount_grown < SLIME_EVOLUTION_THRESHOLD) + to_chat(src, "I need to grow myself more before I can reproduce...") + return + + var/list/babies = list() + var/new_nutrition = round(nutrition * 0.9) + var/new_powerlevel = round(powerlevel / 4) + var/turf/drop_loc = drop_location() + + for(var/i in 1 to 4) + var/child_colour + + if(mutation_chance >= 100) + child_colour = SLIME_TYPE_RAINBOW + else if(prob(mutation_chance)) + child_colour = slime_mutation[rand(1,4)] else - to_chat(src, "I am not ready to reproduce yet...") + child_colour = colour + + var/mob/living/simple_animal/slime/baby + baby = new(drop_loc, child_colour) + + if(ckey) + baby.set_nutrition(new_nutrition) //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature! + + baby.powerlevel = new_powerlevel + if(i != 1) + step_away(baby, src) + + baby.set_friends(Friends) + babies += baby + baby.mutation_chance = clamp(mutation_chance+(rand(5,-5)),0,100) + SSblackbox.record_feedback("tally", "slime_babies_born", 1, baby.colour) + + var/mob/living/simple_animal/slime/new_slime = pick(babies) // slime that the OG slime will move into. + new_slime.set_combat_mode(TRUE) + + if(isnull(src.mind)) + new_slime.key = src.key else - to_chat(src, "I am not old enough to reproduce yet...") + src.mind.transfer_to(new_slime) + + qdel(src) /datum/action/innate/slime/reproduce name = "Reproduce" @@ -239,8 +246,8 @@ needs_growth = GROWTH_NEEDED /datum/action/innate/slime/reproduce/Activate() - var/mob/living/simple_animal/slime/S = owner - S.Reproduce() + var/mob/living/simple_animal/slime/slime_owner = owner + slime_owner.Reproduce() #undef SIZE_DOESNT_MATTER #undef BABIES_ONLY diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index e5ddcf1f0ae77c..ec8f0f629f1452 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -28,7 +28,7 @@ if(client) stack_trace("Mob with client has been deleted.") else if(ckey) - stack_trace("Mob without client but with associated ckey has been deleted.") + stack_trace("Mob without client but with associated ckey, [ckey], has been deleted.") remove_from_mob_list() remove_from_dead_mob_list() @@ -46,7 +46,7 @@ qdel(hud_used) QDEL_LIST(client_colours) - ghostize() //False, since we're deleting it currently + ghostize(can_reenter_corpse = FALSE) //False, since we're deleting it currently if(mind?.current == src) //Let's just be safe yeah? This will occasionally be cleared, but not always. Can't do it with ghostize without changing behavior mind.set_current(null) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 6808728a833b79..2c2f8519e25153 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -20,7 +20,7 @@ // we never want to hide a turf because it's not lit // We can rely on the lighting plane to handle that for us see_in_dark = 1e6 - // A list of factions that this mob is currently in, for hostile mob targetting, amongst other things + // A list of factions that this mob is currently in, for hostile mob targeting, amongst other things faction = list(FACTION_NEUTRAL) /// The current client inhabiting this mob. Managed by login/logout /// This exists so we can do cleanup in logout for occasions where a client was transfere rather then destroyed diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 5f52e79aaab09c..6b89495887682e 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -251,10 +251,8 @@ * * source The source of the notification * * alert_overlay The alert overlay to show in the alert message * * action What action to take upon the ghost interacting with the notification, defaults to NOTIFY_JUMP - * * flashwindow Flash the byond client window * * ignore_key Ignore keys if they're in the GLOB.poll_ignore list * * header The header of the notifiaction - * * notify_suiciders If it should notify suiciders (who do not qualify for many ghost roles) * * notify_volume How loud the sound should be to spook the user */ /proc/notify_ghosts( @@ -264,24 +262,30 @@ atom/source, mutable_appearance/alert_overlay, action = NOTIFY_JUMP, - flashwindow = TRUE, - ignore_mapload = TRUE, + notify_flags = NOTIFY_CATEGORY_DEFAULT, ignore_key, header = "", - notify_suiciders = TRUE, notify_volume = 100 ) - if(ignore_mapload && SSatoms.initialized != INITIALIZATION_INNEW_REGULAR) //don't notify for objects created during a map load + if(notify_flags & GHOST_NOTIFY_IGNORE_MAPLOAD && SSatoms.initialized != INITIALIZATION_INNEW_REGULAR) //don't notify for objects created during a map load return + if(source) + if(isnull(alert_overlay)) + alert_overlay = get_small_overlay(source) + + alert_overlay.appearance_flags |= TILE_BOUND + alert_overlay.layer = FLOAT_LAYER + alert_overlay.plane = FLOAT_PLANE + for(var/mob/dead/observer/ghost in GLOB.player_list) - if(!notify_suiciders && HAS_TRAIT(ghost, TRAIT_SUICIDED)) + if(!(notify_flags & GHOST_NOTIFY_NOTIFY_SUICIDERS) && HAS_TRAIT(ghost, TRAIT_SUICIDED)) continue if(ignore_key && (ghost.ckey in GLOB.poll_ignore[ignore_key])) continue - if(flashwindow) + if(notify_flags & GHOST_NOTIFY_FLASH_WINDOW) window_flash(ghost.client) if(ghost_sound) @@ -299,10 +303,10 @@ var/atom/movable/screen/alert/notify_action/toast = ghost.throw_alert( category = "[REF(source)]_notify_action", type = /atom/movable/screen/alert/notify_action, - new_master = source, ) toast.action = action - toast.desc = "Click to [action]." + toast.add_overlay(alert_overlay) + toast.desc = "[message] -- Click to [action]." toast.name = header toast.target = source @@ -560,3 +564,21 @@ raw_lines += recent_speech[key] return raw_lines + +/// Takes in an associated list (key `/datum/action` typepaths, value is the AI blackboard key) and handles granting the action and adding it to the mob's AI controller blackboard. +/// This is only useful in instances where you don't want to store the reference to the action on a variable on the mob. +/// You can set the value to null if you don't want to add it to the blackboard (like in player controlled instances). Is also safe with null AI controllers. +/// Assumes that the action will be initialized and held in the mob itself, which is typically standard. +/mob/proc/grant_actions_by_list(list/input) + if(length(input) <= 0) + return + + for(var/action in input) + var/datum/action/ability = new action(src) + ability.Grant(src) + + var/blackboard_key = input[action] + if(isnull(blackboard_key)) + continue + + ai_controller?.set_blackboard_key(blackboard_key, ability) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 1caf5e9f1eaa9a..790f9312ea1701 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -376,7 +376,7 @@ if(!MP) return FALSE //Sanity, this should never happen. - if(ispath(MP, /mob/living/simple_animal/hostile/construct) || ispath(MP, /mob/living/basic/construct)) + if(ispath(MP, /mob/living/basic/construct)) return FALSE //Verbs do not appear for players. //Good mobs! @@ -390,7 +390,7 @@ return TRUE if(ispath(MP, /mob/living/basic/mushroom)) return TRUE - if(ispath(MP, /mob/living/simple_animal/shade)) + if(ispath(MP, /mob/living/basic/shade)) return TRUE if(ispath(MP, /mob/living/basic/killer_tomato)) return TRUE diff --git a/code/modules/mob_spawn/corpses/mob_corpses.dm b/code/modules/mob_spawn/corpses/mob_corpses.dm index 476c3f70a84912..f83dc13f1eded0 100644 --- a/code/modules/mob_spawn/corpses/mob_corpses.dm +++ b/code/modules/mob_spawn/corpses/mob_corpses.dm @@ -221,6 +221,21 @@ facial_haircolor = COLOR_WHITE skin_tone = "caucasian1" +/obj/effect/mob_spawn/corpse/human/wizard/red + outfit = /datum/outfit/wizardcorpse/red + +/obj/effect/mob_spawn/corpse/human/wizard/yellow + outfit = /datum/outfit/wizardcorpse/yellow + +/obj/effect/mob_spawn/corpse/human/wizard/black + outfit = /datum/outfit/wizardcorpse/black + +/obj/effect/mob_spawn/corpse/human/wizard/marisa + outfit = /datum/outfit/wizardcorpse/marisa + +/obj/effect/mob_spawn/corpse/human/wizard/tape + outfit = /datum/outfit/wizardcorpse/tape + /datum/outfit/wizardcorpse name = "Space Wizard Corpse" uniform = /obj/item/clothing/under/color/lightpurple @@ -228,6 +243,27 @@ shoes = /obj/item/clothing/shoes/sandal/magic head = /obj/item/clothing/head/wizard +/datum/outfit/wizardcorpse/red + suit = /obj/item/clothing/suit/wizrobe/red + head = /obj/item/clothing/head/wizard/red + +/datum/outfit/wizardcorpse/yellow + suit = /obj/item/clothing/suit/wizrobe/yellow + head = /obj/item/clothing/head/wizard/yellow + +/datum/outfit/wizardcorpse/black + suit = /obj/item/clothing/suit/wizrobe/black + head = /obj/item/clothing/head/wizard/black + +/datum/outfit/wizardcorpse/marisa + suit = /obj/item/clothing/suit/wizrobe/marisa + head = /obj/item/clothing/head/wizard/marisa + shoes = /obj/item/clothing/shoes/sneakers/marisa + +/datum/outfit/wizardcorpse/tape + suit = /obj/item/clothing/suit/wizrobe/tape + head = /obj/item/clothing/head/wizard/tape + /obj/effect/mob_spawn/corpse/human/wizard/dark name = "Dark Wizard Corpse" outfit = /datum/outfit/wizardcorpse/dark diff --git a/code/modules/mob_spawn/ghost_roles/golem_roles.dm b/code/modules/mob_spawn/ghost_roles/golem_roles.dm index 9c2f344bf4bf17..1fa23698e4a01d 100644 --- a/code/modules/mob_spawn/ghost_roles/golem_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/golem_roles.dm @@ -23,7 +23,13 @@ . = ..() var/area/init_area = get_area(src) if(!mapload && init_area) - notify_ghosts("\A golem shell has been completed in \the [init_area.name].", source = src, action = NOTIFY_PLAY, flashwindow = FALSE, ignore_key = POLL_IGNORE_GOLEM) + notify_ghosts( + "\A golem shell has been completed in \the [init_area.name].", + source = src, + action = NOTIFY_PLAY, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + ignore_key = POLL_IGNORE_GOLEM, + ) /obj/effect/mob_spawn/ghost_role/human/golem/name_mob(mob/living/spawned_mob, forced_name) if(forced_name || !iscarbon(spawned_mob)) diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm index 4eb5aafc17f59c..2c6548705760a1 100644 --- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm @@ -266,7 +266,13 @@ eggshell.egg = src src.forceMove(eggshell) if(spawner_area) - notify_ghosts("An ash walker egg is ready to hatch in \the [spawner_area.name].", source = src, action = NOTIFY_PLAY, flashwindow = FALSE, ignore_key = POLL_IGNORE_ASHWALKER) + notify_ghosts( + "An ash walker egg is ready to hatch in \the [spawner_area.name].", + source = src, + action = NOTIFY_PLAY, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + ignore_key = POLL_IGNORE_ASHWALKER, + ) /datum/outfit/ashwalker name = "Ash Walker" diff --git a/code/modules/mob_spawn/ghost_roles/spider_roles.dm b/code/modules/mob_spawn/ghost_roles/spider_roles.dm index fb3d470f5aa800..4dada2a2468a72 100644 --- a/code/modules/mob_spawn/ghost_roles/spider_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/spider_roles.dm @@ -36,6 +36,10 @@ if(100 to INFINITY) . += span_info("These eggs are plump, teeming with life. Any moment now...") +/obj/structure/spider/eggcluster/abnormal + name = "abnormal egg cluster" + color = rgb(0, 148, 211) + /obj/structure/spider/eggcluster/enriched name = "enriched egg cluster" color = rgb(148, 0, 211) @@ -103,7 +107,16 @@ amount_grown += rand(5, 15) * seconds_per_tick if(amount_grown >= 100 && !ready) ready = TRUE - notify_ghosts("[src] is ready to hatch!", null, enter_link = "(Click to play)", source = src, action = NOTIFY_ORBIT, ignore_key = POLL_IGNORE_SPIDER, flashwindow = flash_window) + var/notify_flags_to_pass = NOTIFY_CATEGORY_NOFLASH + if(flash_window) + notify_flags_to_pass &= GHOST_NOTIFY_FLASH_WINDOW + notify_ghosts( + "[src] is ready to hatch!", + source = src, + action = NOTIFY_PLAY, + ignore_key = POLL_IGNORE_SPIDER, + notify_flags = notify_flags_to_pass, + ) STOP_PROCESSING(SSobj, src) /obj/effect/mob_spawn/ghost_role/spider/Topic(href, href_list) @@ -134,6 +147,16 @@ var/datum/antagonist/spider/spider_antag = new granted_datum(directive) spawned_mob.mind.add_antag_datum(spider_antag) +/obj/effect/mob_spawn/ghost_role/spider/abnormal + name = "abnormal egg cluster" + color = rgb(0, 148, 211) + cluster_type = /obj/structure/spider/eggcluster/abnormal + potentialspawns = list( + /mob/living/basic/spider/growing/spiderling/tank, + /mob/living/basic/spider/growing/spiderling/breacher, + ) + flash_window = TRUE + /obj/effect/mob_spawn/ghost_role/spider/enriched name = "enriched egg cluster" color = rgb(148, 0, 211) @@ -168,7 +191,7 @@ directive = "Ensure the survival of the spider species and overtake whatever structure you find yourself in." cluster_type = /obj/structure/spider/eggcluster/midwife potentialspawns = list( - /mob/living/basic/spider/giant/midwife, // We don't want the event to end instantly because of a 2 hp spiderling dying + /mob/living/basic/spider/growing/spiderling/midwife, // We don't want the event to end instantly because broodmothers got a bad spawn ) flash_window = TRUE diff --git a/code/modules/mob_spawn/ghost_roles/venus_human_trap.dm b/code/modules/mob_spawn/ghost_roles/venus_human_trap.dm index 254cfcfbdab2ed..1a1fd623e0d19e 100644 --- a/code/modules/mob_spawn/ghost_roles/venus_human_trap.dm +++ b/code/modules/mob_spawn/ghost_roles/venus_human_trap.dm @@ -33,7 +33,12 @@ /// Called when the attached flower bud has borne fruit (ie. is ready) /obj/effect/mob_spawn/ghost_role/venus_human_trap/proc/bear_fruit() ready = TRUE - notify_ghosts("[src] has borne fruit!", source = src, action = NOTIFY_PLAY, ignore_key = POLL_IGNORE_VENUSHUMANTRAP) + notify_ghosts( + "[src] has borne fruit!", + source = src, + action = NOTIFY_PLAY, + ignore_key = POLL_IGNORE_VENUSHUMANTRAP, + ) /obj/effect/mob_spawn/ghost_role/venus_human_trap/allow_spawn(mob/user, silent = FALSE) . = ..() diff --git a/code/modules/mod/mod_paint.dm b/code/modules/mod/mod_paint.dm index ee162b2d9819ab..351859e5f2bf97 100644 --- a/code/modules/mod/mod_paint.dm +++ b/code/modules/mod/mod_paint.dm @@ -144,8 +144,9 @@ balloon_alert(user, "no alternate skins!") return var/list/skins = list() - for(var/mod_skin in mod.theme.skins) - skins[mod_skin] = image(icon = mod.icon, icon_state = "[mod_skin]-control") + for(var/mod_skin_name in mod.theme.skins) + var/list/mod_skin = mod.theme.skins[mod_skin_name] + skins[mod_skin_name] = image(icon = mod_skin[MOD_ICON_OVERRIDE] || mod.icon, icon_state = "[mod_skin_name]-control") var/pick = show_radial_menu(user, mod, skins, custom_check = CALLBACK(src, PROC_REF(check_menu), mod, user), require_near = TRUE) if(!pick) balloon_alert(user, "no skin picked!") diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index 9adaaf4f14680e..c8611ab7bd0a92 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -702,8 +702,6 @@ slowdown_inactive = 1 slowdown_active = 0.5 allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/reagent_containers/spray/pepper, /obj/item/restraints/handcuffs, /obj/item/assembly/flash, @@ -765,8 +763,6 @@ slowdown_inactive = 0.75 slowdown_active = 0.25 allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/reagent_containers/spray/pepper, /obj/item/restraints/handcuffs, /obj/item/assembly/flash, @@ -832,8 +828,6 @@ slowdown_inactive = 0.75 slowdown_active = 0.25 allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/restraints/handcuffs, /obj/item/assembly/flash, /obj/item/melee/baton, @@ -958,8 +952,6 @@ resistance_flags = FIRE_PROOF inbuilt_modules = list(/obj/item/mod/module/armor_booster) allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/restraints/handcuffs, /obj/item/assembly/flash, /obj/item/melee/baton, @@ -1051,8 +1043,6 @@ ui_theme = "syndicate" inbuilt_modules = list(/obj/item/mod/module/armor_booster) allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/restraints/handcuffs, /obj/item/assembly/flash, /obj/item/melee/baton, @@ -1120,8 +1110,6 @@ slot_flags = ITEM_SLOT_BELT inbuilt_modules = list(/obj/item/mod/module/infiltrator, /obj/item/mod/module/storage/belt, /obj/item/mod/module/demoralizer) allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/restraints/handcuffs, /obj/item/assembly/flash, /obj/item/melee/baton, @@ -1185,8 +1173,6 @@ slowdown_active = -0.5 inbuilt_modules = list(/obj/item/mod/module/quick_carry/advanced, /obj/item/mod/module/organ_thrower) allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/assembly/flash, /obj/item/healthanalyzer, /obj/item/melee/baton, @@ -1329,8 +1315,6 @@ inbuilt_modules = list(/obj/item/mod/module/welding/camera_vision, /obj/item/mod/module/hacker, /obj/item/mod/module/weapon_recall, /obj/item/mod/module/adrenaline_boost, /obj/item/mod/module/energy_net) allowed_suit_storage = list( /obj/item/gun, - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, ) @@ -1454,8 +1438,6 @@ slowdown_inactive = 0.5 slowdown_active = 0 allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/restraints/handcuffs, /obj/item/assembly/flash, /obj/item/melee/baton, @@ -1540,8 +1522,6 @@ siemens_coefficient = 0 complexity_max = DEFAULT_MAX_COMPLEXITY + 10 allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/restraints/handcuffs, /obj/item/assembly/flash, /obj/item/melee/baton, @@ -1604,8 +1584,6 @@ slowdown_inactive = 0.5 slowdown_active = 0 allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, /obj/item/restraints/handcuffs, /obj/item/assembly/flash, /obj/item/melee/baton, diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index f8daa9bab544f3..3e4b89e6a52ccb 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -216,6 +216,7 @@ /obj/item/mod/module/pathfinder, /obj/item/mod/module/flashlight, /obj/item/mod/module/dna_lock, + /obj/item/mod/module/hat_stabilizer/syndicate, ) default_pins = list( /obj/item/mod/module/armor_booster, @@ -234,6 +235,7 @@ /obj/item/mod/module/jump_jet, /obj/item/mod/module/flashlight, /obj/item/mod/module/dna_lock, + /obj/item/mod/module/hat_stabilizer/syndicate, ) default_pins = list( /obj/item/mod/module/armor_booster, @@ -253,6 +255,7 @@ /obj/item/mod/module/jetpack/advanced, /obj/item/mod/module/jump_jet, /obj/item/mod/module/flashlight, + /obj/item/mod/module/hat_stabilizer/syndicate, ) default_pins = list( /obj/item/mod/module/armor_booster, @@ -287,6 +290,7 @@ /obj/item/mod/module/jetpack/advanced, /obj/item/mod/module/jump_jet, /obj/item/mod/module/flashlight, + /obj/item/mod/module/hat_stabilizer/syndicate, ) default_pins = list( /obj/item/mod/module/armor_booster, @@ -303,6 +307,7 @@ /obj/item/mod/module/jetpack/advanced, /obj/item/mod/module/jump_jet, /obj/item/mod/module/flashlight, + /obj/item/mod/module/hat_stabilizer/syndicate, /obj/item/mod/module/flamethrower, ) default_pins = list( @@ -321,6 +326,7 @@ /obj/item/mod/module/magnetic_harness, /obj/item/mod/module/quick_carry, /obj/item/mod/module/visor/diaghud, + /obj/item/mod/module/hat_stabilizer/syndicate, ) @@ -335,7 +341,8 @@ /obj/item/mod/module/injector, /obj/item/mod/module/surgical_processor/preloaded, /obj/item/mod/module/storage/syndicate, - /obj/item/mod/module/tether + /obj/item/mod/module/hat_stabilizer/syndicate, + /obj/item/mod/module/tether, ) /obj/item/mod/control/pre_equipped/enchanted diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 6d47a5b60ba3ba..58857b7730c445 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -751,6 +751,15 @@ return mod.core.add_charge(power_per_step) +/obj/item/mod/module/hat_stabilizer/syndicate + name = "MOD elite hat stabilizer module" + desc = "A simple set of deployable stands, directly atop one's head; \ + these will deploy under a hat to keep it from falling off, allowing them to be worn atop the sealed helmet. \ + You still need to take the hat off your head while the helmet deploys, though. This is a must-have for \ + Syndicate Operatives and Agents alike, enabling them to continue to style on the opposition even while in their MODsuit." + complexity = 0 + removable = FALSE + /// Module that shoves garbage inside its material container when the user crosses it, and eject the recycled material with MMB. /obj/item/mod/module/recycler name = "MOD recycler module" diff --git a/code/modules/modular_computers/computers/item/laptop_presets.dm b/code/modules/modular_computers/computers/item/laptop_presets.dm index 1eebf9f2387756..4239a33dfd781b 100644 --- a/code/modules/modular_computers/computers/item/laptop_presets.dm +++ b/code/modules/modular_computers/computers/item/laptop_presets.dm @@ -3,3 +3,9 @@ starting_programs = list( /datum/computer_file/program/chatclient, ) + +//Used for Mafia testing purposes. +/obj/item/modular_computer/laptop/preset/mafia + starting_programs = list( + /datum/computer_file/program/mafia, + ) diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm index e2f1b354eda283..4ccdfe8ec213db 100644 --- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm @@ -47,6 +47,7 @@ name = "head of security PDA" greyscale_config = /datum/greyscale_config/tablet/head greyscale_colors = "#EA3232#0000CC" + inserted_item = /obj/item/pen/red/security starting_programs = list( /datum/computer_file/program/crew_manifest, /datum/computer_file/program/status, @@ -122,6 +123,7 @@ /obj/item/modular_computer/pda/security name = "security PDA" greyscale_colors = "#EA3232#0000cc" + inserted_item = /obj/item/pen/red/security starting_programs = list( /datum/computer_file/program/records/security, /datum/computer_file/program/crew_manifest, @@ -131,6 +133,7 @@ /obj/item/modular_computer/pda/detective name = "detective PDA" greyscale_colors = "#805A2F#990202" + inserted_item = /obj/item/pen/red/security starting_programs = list( /datum/computer_file/program/records/security, /datum/computer_file/program/crew_manifest, @@ -141,6 +144,7 @@ name = "warden PDA" greyscale_config = /datum/greyscale_config/tablet/stripe_double greyscale_colors = "#EA3232#0000CC#363636" + inserted_item = /obj/item/pen/red/security starting_programs = list( /datum/computer_file/program/records/security, /datum/computer_file/program/crew_manifest, diff --git a/code/modules/modular_computers/file_system/programs/mafia_ntos.dm b/code/modules/modular_computers/file_system/programs/mafia_ntos.dm index 7bd5b81a240314..bbcdd39d32c61f 100644 --- a/code/modules/modular_computers/file_system/programs/mafia_ntos.dm +++ b/code/modules/modular_computers/file_system/programs/mafia_ntos.dm @@ -16,11 +16,11 @@ /datum/computer_file/program/mafia/Destroy(force) var/datum/mafia_controller/game = GLOB.mafia_game if(!game) - return + return ..() UnregisterSignal(game, COMSIG_MAFIA_GAME_END) - var/datum/mafia_role/pda_role = game.player_role_lookup[computer] + var/datum/mafia_role/pda_role = game.get_role_player(computer) if(!pda_role) - return + return ..() game.send_message(span_notice("[pda_role.body] has deleted the game from their PDA, and therefore has left the game.")) pda_role.kill(game) return ..() @@ -60,7 +60,7 @@ SIGNAL_HANDLER RegisterSignal(game, COMSIG_MAFIA_GAME_END, PROC_REF(on_game_end)) ui_header = "mafia.gif" - if(game.player_role_lookup[computer]) + if(game.get_role_player(computer)) alert_pending = TRUE computer.alert_call(src, "Mafia game started!") diff --git a/code/modules/modular_computers/file_system/programs/notepad.dm b/code/modules/modular_computers/file_system/programs/notepad.dm index 01afaa08c19e07..c0232fe3888ae6 100644 --- a/code/modules/modular_computers/file_system/programs/notepad.dm +++ b/code/modules/modular_computers/file_system/programs/notepad.dm @@ -7,7 +7,7 @@ size = 2 tgui_id = "NtosNotepad" program_icon = "book" - usage_flags = PROGRAM_TABLET + usage_flags = PROGRAM_ALL var/written_note = "Congratulations on your station upgrading to the new NtOS and Thinktronic based collaboration effort, \ bringing you the best in electronics and software since 2467!\n\ diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index e5f293232239ae..49358223e3508b 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -109,6 +109,9 @@ /datum/movespeed_modifier/average_web multiplicative_slowdown = 1.2 +/datum/movespeed_modifier/below_average_web + multiplicative_slowdown = 2.5 + /datum/movespeed_modifier/slow_web multiplicative_slowdown = 5 diff --git a/code/modules/movespeed/modifiers/status_effects.dm b/code/modules/movespeed/modifiers/status_effects.dm index 65245880ef42ba..4768f66a544f4f 100644 --- a/code/modules/movespeed/modifiers/status_effects.dm +++ b/code/modules/movespeed/modifiers/status_effects.dm @@ -53,3 +53,6 @@ /datum/movespeed_modifier/status_effect/midas_blight/gold multiplicative_slowdown = 2 + +/datum/movespeed_modifier/status_effect/guardian_shield + multiplicative_slowdown = 1 diff --git a/code/modules/pai/card.dm b/code/modules/pai/card.dm index a652b745c9e502..2fc3d2d0ca4c7b 100644 --- a/code/modules/pai/card.dm +++ b/code/modules/pai/card.dm @@ -26,7 +26,6 @@ if(!pai.encrypt_mod) to_chat(user, span_alert("Encryption Key ports not configured.")) return - user.set_machine(src) pai.radio.attackby(used, user, params) to_chat(user, span_notice("You insert [used] into the [src].")) return @@ -35,7 +34,6 @@ /obj/item/pai_card/attack_self(mob/user) if(!in_range(src, user)) return - user.set_machine(src) ui_interact(user) /obj/item/pai_card/Destroy() @@ -234,7 +232,17 @@ playsound(src, 'sound/machines/ping.ogg', 20, TRUE) balloon_alert(user, "pAI assistance requested") var/mutable_appearance/alert_overlay = mutable_appearance('icons/obj/aicards.dmi', "pai") - notify_ghosts("[user] is requesting a pAI companion! Use the pAI button to submit yourself as one.", source = user, alert_overlay = alert_overlay, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "pAI Request!", ignore_key = POLL_IGNORE_PAI) + + notify_ghosts( + "[user] is requesting a pAI companion! Use the pAI button to submit yourself as one.", + source = user, + alert_overlay = alert_overlay, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "pAI Request!", + ignore_key = POLL_IGNORE_PAI, + ) + addtimer(VARSET_CALLBACK(src, request_spam, FALSE), PAI_SPAM_TIME, TIMER_UNIQUE | TIMER_STOPPABLE | TIMER_CLIENT_TIME | TIMER_DELETE_ME) return TRUE diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 05606ac3a2ef1c..69af56d341902f 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -400,3 +400,44 @@ . = ..() icon_state = "[initial(icon_state)][HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE) ? "_out" : null]" inhand_icon_state = initial(inhand_icon_state) //since transforming component switches the icon. + +//The Security holopen +/obj/item/pen/red/security + name = "security pen" + desc = "This is a red ink pen exclusively provided to members of the Security Department. Its opposite end features a built-in holographic projector designed for issuing arrest prompts to individuals." + icon_state = "pen_sec" + COOLDOWN_DECLARE(holosign_cooldown) + +/obj/item/pen/red/security/examine(mob/user) + . = ..() + . += span_notice("To initiate the surrender prompt, simply click on an individual within your proximity.") + +//Code from the medical penlight +/obj/item/pen/red/security/afterattack(atom/target, mob/living/user, proximity) + . = ..() + if(!COOLDOWN_FINISHED(src, holosign_cooldown)) + balloon_alert(user, "not ready!") + return + + var/target_turf = get_turf(target) + var/mob/living/living_target = locate(/mob/living) in target_turf + + if(!living_target || (living_target == user)) + return + + living_target.apply_status_effect(/datum/status_effect/surrender_timed) + to_chat(living_target, span_userdanger("[user] requests your immediate surrender! You are given 30 seconds to comply!")) + new /obj/effect/temp_visual/security_holosign(target_turf, user) //produce a holographic glow + COOLDOWN_START(src, holosign_cooldown, 30 SECONDS) + +/obj/effect/temp_visual/security_holosign + name = "security holosign" + desc = "A small holographic glow that indicates you're under arrest." + icon_state = "sec_holo" + duration = 60 + +/obj/effect/temp_visual/security_holosign/Initialize(mapload, creator) + . = ..() + playsound(loc, 'sound/machines/chime.ogg', 50, FALSE) //make some noise! + if(creator) + visible_message(span_danger("[creator] created a security hologram!")) diff --git a/code/modules/plumbing/plumbers/bottler.dm b/code/modules/plumbing/plumbers/bottler.dm index fe56282746f97f..eab1811ec6c5ce 100644 --- a/code/modules/plumbing/plumbers/bottler.dm +++ b/code/modules/plumbing/plumbers/bottler.dm @@ -79,11 +79,16 @@ return PROCESS_KILL ///see if machine has enough to fill, is anchored down and has any inputspot objects to pick from - if(reagents.total_volume + 0.01 >= wanted_amount && anchored && length(inputspot.contents)) + if(reagents.total_volume >= wanted_amount && anchored && length(inputspot.contents)) use_power(active_power_usage * seconds_per_tick) var/obj/AM = pick(inputspot.contents)///pick a reagent_container that could be used - if((is_reagent_container(AM) && !istype(AM, /obj/item/reagent_containers/hypospray/medipen)) || istype(AM, /obj/item/ammo_casing/shotgun/dart)) - var/obj/item/reagent_containers/B = AM + //allowed containers + var/static/list/allowed_containers = list( + /obj/item/reagent_containers/cup, + /obj/item/ammo_casing/shotgun/dart, + ) + if(is_type_in_list(AM, allowed_containers)) + var/obj/item/B = AM ///see if it would overflow else inject if((B.reagents.total_volume + wanted_amount) <= B.reagents.maximum_volume) reagents.trans_to(B, wanted_amount, transferred_by = src) @@ -91,10 +96,8 @@ return ///glass was full so we move it away AM.forceMove(badspot) - if(istype(AM, /obj/item/slime_extract)) ///slime extracts need inject + else if(istype(AM, /obj/item/slime_extract)) ///slime extracts need inject AM.forceMove(goodspot) reagents.trans_to(AM, wanted_amount, transferred_by = src, methods = INJECT) - return - if(istype(AM, /obj/item/slimecross/industrial)) ///no need to move slimecross industrial things + else if(istype(AM, /obj/item/slimecross/industrial)) ///no need to move slimecross industrial things reagents.trans_to(AM, wanted_amount, transferred_by = src, methods = INJECT) - return diff --git a/code/modules/plumbing/plumbers/filter.dm b/code/modules/plumbing/plumbers/filter.dm index 4e4a282bd1dcd7..633f70830f016b 100644 --- a/code/modules/plumbing/plumbers/filter.dm +++ b/code/modules/plumbing/plumbers/filter.dm @@ -38,11 +38,12 @@ switch(action) if("add") var/which = params["which"] - var/selected_reagent = tgui_input_list(usr, "Select [which] reagent", "Reagent", GLOB.chemical_name_list) + + var/selected_reagent = tgui_input_list(usr, "Select [which] reagent", "Reagent", GLOB.name2reagent) if(!selected_reagent) return TRUE - var/chem_id = get_chem_id(selected_reagent) + var/datum/reagent/chem_id = GLOB.name2reagent[selected_reagent] if(!chem_id) return TRUE diff --git a/code/modules/plumbing/plumbers/iv_drip.dm b/code/modules/plumbing/plumbers/iv_drip.dm new file mode 100644 index 00000000000000..1db36c137e6d71 --- /dev/null +++ b/code/modules/plumbing/plumbers/iv_drip.dm @@ -0,0 +1,41 @@ +///modified IV that can be anchored and takes plumbing in- and output +/obj/machinery/iv_drip/plumbing + name = "automated IV drip" + desc = "A modified IV drip with plumbing connects. Reagents received from the connect are injected directly into their bloodstream, blood that is drawn goes to the internal storage and then into the ducting." + icon_state = "plumb" + base_icon_state = "plumb" + density = TRUE + use_internal_storage = TRUE + +/obj/machinery/iv_drip/plumbing/Initialize(mapload) + . = ..() + AddComponent(/datum/component/plumbing/iv_drip, anchored) + AddComponent(/datum/component/simple_rotation) + +/obj/machinery/iv_drip/plumbing/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) + if(attached) + context[SCREENTIP_CONTEXT_RMB] = "Take needle out" + else if(reagent_container && !use_internal_storage) + context[SCREENTIP_CONTEXT_RMB] = "Eject container" + else if(!inject_only) + context[SCREENTIP_CONTEXT_RMB] = "Change direction" + + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/iv_drip/plumbing/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) + to_chat(user, span_notice("You start furiously plunging [name].")) + if(do_after(user, 30, target = src)) + to_chat(user, span_notice("You finish plunging the [name].")) + reagents.expose(get_turf(src), TOUCH) //splash on the floor + reagents.clear_reagents() + +/obj/machinery/iv_drip/plumbing/can_use_alt_click(mob/user) + return FALSE //Alt click is used for rotation + +/obj/machinery/iv_drip/plumbing/wrench_act(mob/living/user, obj/item/tool) + . = ..() + if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/machinery/iv_drip/plumbing/deconstruct(disassembled = TRUE) + qdel(src) diff --git a/code/modules/plumbing/plumbers/pill_press.dm b/code/modules/plumbing/plumbers/pill_press.dm index 5061723acc7edb..6c309b525b95d6 100644 --- a/code/modules/plumbing/plumbers/pill_press.dm +++ b/code/modules/plumbing/plumbers/pill_press.dm @@ -84,7 +84,7 @@ return //shift & check to account for floating point inaccuracies - if(reagents.total_volume + 0.01 >= current_volume) + if(reagents.total_volume >= current_volume) var/obj/item/reagent_containers/container = locate(packaging_type) container = new container(src) var/suffix diff --git a/code/modules/plumbing/plumbers/reaction_chamber.dm b/code/modules/plumbing/plumbers/reaction_chamber.dm index d41c502ecf9242..98cc1806374e25 100644 --- a/code/modules/plumbing/plumbers/reaction_chamber.dm +++ b/code/modules/plumbing/plumbers/reaction_chamber.dm @@ -3,6 +3,9 @@ /// coefficient to convert temperature to joules. same lvl as acclimator #define HEATER_COEFFICIENT 0.05 +/// maximum number of attempts the reaction chamber will make to balance the ph(More means better results but higher tick usage) +#define MAX_PH_ADJUSTMENTS 3 + /obj/machinery/plumbing/reaction_chamber name = "mixing chamber" desc = "Keeps chemicals separated until given conditions are met." @@ -43,7 +46,7 @@ /obj/machinery/plumbing/reaction_chamber/proc/on_reagent_change(datum/reagents/holder, ...) SIGNAL_HANDLER - if(!holder.total_volume && emptying) //we were emptying, but now we aren't + if(holder.total_volume <= CHEMICAL_VOLUME_ROUNDING && emptying) //we were emptying, but now we aren't emptying = FALSE holder.flags |= NO_REACT return NONE @@ -104,32 +107,34 @@ switch(action) if("add") - var/selected_reagent = tgui_input_list(ui.user, "Select reagent", "Reagent", GLOB.chemical_name_list) + var/selected_reagent = tgui_input_list(ui.user, "Select reagent", "Reagent", GLOB.name2reagent) if(!selected_reagent) - return TRUE + return FALSE - var/input_reagent = get_chem_id(selected_reagent) + var/datum/reagent/input_reagent = GLOB.name2reagent[selected_reagent] if(!input_reagent) - return TRUE + return FALSE if(!required_reagents.Find(input_reagent)) var/input_amount = text2num(params["amount"]) - if(input_amount) + if(!isnull(input_amount)) required_reagents[input_reagent] = input_amount - - return TRUE + return TRUE + return FALSE if("remove") var/reagent = get_chem_id(params["chem"]) if(reagent) required_reagents.Remove(reagent) - return TRUE + return TRUE + return FALSE if("temperature") var/target = text2num(params["target"]) - if(target != null) + if(!isnull(target)) target_temperature = clamp(target, 0, 1000) - return TRUE + return TRUE + return FALSE var/result = handle_ui_act(action, params, ui, state) if(isnull(result)) @@ -170,7 +175,8 @@ return ..() /obj/machinery/plumbing/reaction_chamber/chem/handle_reagents(seconds_per_tick) - while(reagents.ph < acidic_limit || reagents.ph > alkaline_limit) + var/ph_balance_attempts = 0 + while(ph_balance_attempts < MAX_PH_ADJUSTMENTS && (reagents.ph < acidic_limit || reagents.ph > alkaline_limit)) //no power if(machine_stat & NOPOWER) return @@ -190,13 +196,16 @@ return //transfer buffer and handle reactions - var/ph_change = (reagents.ph > alkaline_limit ? (reagents.ph - alkaline_limit) : (acidic_limit - reagents.ph)) - var/buffer_amount = ((ph_change * reagents.total_volume) / (BUFFER_IONIZING_STRENGTH * num_of_reagents)) - if(!buffer.trans_to(reagents, buffer_amount * seconds_per_tick)) + var/ph_change = max((reagents.ph > alkaline_limit ? (reagents.ph - alkaline_limit) : (acidic_limit - reagents.ph)), 0.25) + if(ph_change <= 0.7) //make big jumps towards the end so we can end our work quickly + ph_change *= 2 + var/buffer_amount = ((ph_change * reagents.total_volume) / (BUFFER_IONIZING_STRENGTH * num_of_reagents)) * seconds_per_tick + if(!buffer.trans_to(reagents, buffer_amount)) return - //some power for accurate ph balancing - use_power(active_power_usage * 0.03 * buffer_amount * seconds_per_tick) + //some power for accurate ph balancing & keep track of attempts made + use_power(active_power_usage * 0.03 * buffer_amount) + ph_balance_attempts += 1 /obj/machinery/plumbing/reaction_chamber/chem/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -215,11 +224,11 @@ switch(action) if("acidic") - acidic_limit = clamp(round(text2num(params["target"])), 0, alkaline_limit) + acidic_limit = clamp(round(text2num(params["target"])), CHEMICAL_MIN_PH, alkaline_limit - 1) if("alkaline") - alkaline_limit = clamp(round(text2num(params["target"])), acidic_limit + 0.01, 14) + alkaline_limit = clamp(round(text2num(params["target"])), acidic_limit + 1, CHEMICAL_MAX_PH) else return FALSE - #undef HEATER_COEFFICIENT +#undef MAX_PH_ADJUSTMENTS diff --git a/code/modules/plumbing/plumbers/synthesizer.dm b/code/modules/plumbing/plumbers/synthesizer.dm index 3dddd648e6165d..0e9cb0c1b1125e 100644 --- a/code/modules/plumbing/plumbers/synthesizer.dm +++ b/code/modules/plumbing/plumbers/synthesizer.dm @@ -2,7 +2,6 @@ /obj/machinery/plumbing/synthesizer name = "chemical synthesizer" desc = "Produces a single chemical at a given volume. Must be plumbed. Most effective when working in unison with other chemical synthesizers, heaters and filters." - icon_state = "synthesizer" icon = 'icons/obj/pipes_n_cables/hydrochem/plumbers.dmi' active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 @@ -52,10 +51,13 @@ /obj/machinery/plumbing/synthesizer/process(seconds_per_tick) if(machine_stat & NOPOWER || !reagent_id || !amount) return - if(reagents.total_volume >= amount*seconds_per_tick*0.5) //otherwise we get leftovers, and we need this to be precise + + //otherwise we get leftovers, and we need this to be precise + if(reagents.total_volume >= amount) return - reagents.add_reagent(reagent_id, amount*seconds_per_tick*0.5) - use_power(active_power_usage * amount * seconds_per_tick * 0.5) + reagents.add_reagent(reagent_id, amount) + + use_power(active_power_usage) /obj/machinery/plumbing/synthesizer/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -63,8 +65,13 @@ ui = new(user, src, "ChemSynthesizer", name) ui.open() +/obj/machinery/plumbing/synthesizer/ui_static_data(mob/user) + . = ..() + .["possible_amounts"] = possible_amounts + /obj/machinery/plumbing/synthesizer/ui_data(mob/user) - var/list/data = list() + . = list() + .["amount"] = amount var/is_hallucinating = FALSE if(isliving(user)) @@ -72,36 +79,35 @@ is_hallucinating = !!living_user.has_status_effect(/datum/status_effect/hallucination) var/list/chemicals = list() - for(var/A in dispensable_reagents) - var/datum/reagent/R = GLOB.chemical_reagents_list[A] - if(R) - var/chemname = R.name + for(var/reagentID in dispensable_reagents) + var/datum/reagent/reagent = GLOB.chemical_reagents_list[reagentID] + if(reagent) + var/chemname = reagent.name if(is_hallucinating && prob(5)) chemname = "[pick_list_replacements("hallucination.json", "chemicals")]" - chemicals.Add(list(list("title" = chemname, "id" = ckey(R.name)))) - data["chemicals"] = chemicals - data["amount"] = amount - data["possible_amounts"] = possible_amounts + chemicals += list(list("title" = chemname, "id" = reagent.name)) + .["chemicals"] = chemicals - data["current_reagent"] = ckey(initial(reagent_id.name)) - return data + .["current_reagent"] = initial(reagent_id.name) /obj/machinery/plumbing/synthesizer/ui_act(action, params) . = ..() if(.) return - . = TRUE + switch(action) if("amount") var/new_amount = text2num(params["target"]) if(new_amount in possible_amounts) amount = new_amount . = TRUE + if("select") var/new_reagent = GLOB.name2reagent[params["reagent"]] if(new_reagent in dispensable_reagents) reagent_id = new_reagent . = TRUE + update_appearance() reagents.clear_reagents() diff --git a/code/modules/research/xenobiology/vatgrowing/vatgrower.dm b/code/modules/plumbing/plumbers/vatgrower.dm similarity index 100% rename from code/modules/research/xenobiology/vatgrowing/vatgrower.dm rename to code/modules/plumbing/plumbers/vatgrower.dm diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm index 974c2e66737949..af48e9c5944f86 100644 --- a/code/modules/power/rtg.dm +++ b/code/modules/power/rtg.dm @@ -71,7 +71,7 @@ visible_message(span_danger("\The [src] lets out a shower of sparks as it starts to lose stability!"),\ span_hear("You hear a loud electrical crack!")) playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) - tesla_zap(src, 5, power_gen * 20) + tesla_zap(source = src, zap_range = 5, power = power_gen * 20) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(explosion), src, 2, 3, 4, null, 8), 10 SECONDS) // Not a normal explosion. /obj/machinery/power/rtg/abductor/bullet_act(obj/projectile/Proj) diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index ac6eb376ac3d43..75dfc4b5c5bc6c 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -123,7 +123,7 @@ if(isliving(mover)) shock(mover) return - if(ismachinery(mover) || isstructure(mover) || ismecha(mover)) + if(ismachinery(mover) || isstructure(mover) || isvehicle(mover)) bump_field(mover) return diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 3e36ff3c393a83..e31162005fa564 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -58,7 +58,13 @@ var/area/area = get_area(src) if(area) var/mutable_appearance/alert_overlay = mutable_appearance('icons/effects/cult/effects.dmi', "ghostalertsie") - notify_ghosts("Nar'Sie has risen in [area]. Reach out to the Geometer to be given a new shell for your soul.", source = src, alert_overlay = alert_overlay, action = NOTIFY_PLAY) + notify_ghosts( + "Nar'Sie has risen in [area]. Reach out to the Geometer to be given a new shell for your soul.", + source = src, + alert_overlay = alert_overlay, + action = NOTIFY_PLAY, + ) + narsie_spawn_animation() GLOB.cult_narsie = src @@ -218,21 +224,25 @@ ///First crew last second win check and flufftext for [/proc/begin_the_end()] /proc/narsie_end_begin_check() if(QDELETED(GLOB.cult_narsie)) // uno - priority_announce("Status report? We detected an anomaly, but it disappeared almost immediately.","Central Command Higher Dimensional Affairs", 'sound/misc/notice1.ogg') + priority_announce("Status report? We detected an anomaly, but it disappeared almost immediately.","[command_name()] Higher Dimensional Affairs", 'sound/misc/notice1.ogg') GLOB.cult_narsie = null addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), CULT_FAILURE_NARSIE_KILLED), 2 SECONDS) return - priority_announce("An acausal dimensional event has been detected in your sector. Event has been flagged EXTINCTION-CLASS. Directing all available assets toward simulating solutions. SOLUTION ETA: 60 SECONDS.","Central Command Higher Dimensional Affairs", 'sound/misc/airraid.ogg') + priority_announce( + text = "An acausal dimensional event has been detected in your sector. Event has been flagged EXTINCTION-CLASS. Directing all available assets toward simulating solutions. SOLUTION ETA: 60 SECONDS.", + title = "[command_name()] Higher Dimensional Affairs", + sound = 'sound/misc/airraid.ogg', + ) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(narsie_end_second_check)), 50 SECONDS) ///Second crew last second win check and flufftext for [/proc/begin_the_end()] /proc/narsie_end_second_check() if(QDELETED(GLOB.cult_narsie)) // dos - priority_announce("Simulations aborted, sensors report that the acasual event is normalizing. Good work, crew.","Central Command Higher Dimensional Affairs", 'sound/misc/notice1.ogg') + priority_announce("Simulations aborted, sensors report that the acasual event is normalizing. Good work, crew.","[command_name()] Higher Dimensional Affairs", 'sound/misc/notice1.ogg') GLOB.cult_narsie = null addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), CULT_FAILURE_NARSIE_KILLED), 2 SECONDS) return - priority_announce("Simulations on acausal dimensional event complete. Deploying solution package now. Deployment ETA: ONE MINUTE. ","Central Command Higher Dimensional Affairs") + priority_announce("Simulations on acausal dimensional event complete. Deploying solution package now. Deployment ETA: ONE MINUTE. ","[command_name()] Higher Dimensional Affairs") addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(narsie_start_destroy_station)), 5 SECONDS) ///security level and shuttle lockdowns for [/proc/begin_the_end()] @@ -245,7 +255,7 @@ ///Third crew last second win check and flufftext for [/proc/begin_the_end()] /proc/narsie_apocalypse() if(QDELETED(GLOB.cult_narsie)) // tres - priority_announce("Normalization detected! Abort the solution package!","Central Command Higher Dimensional Affairs", 'sound/misc/notice1.ogg') + priority_announce("Normalization detected! Abort the solution package!","[command_name()] Higher Dimensional Affairs", 'sound/misc/notice1.ogg') SSshuttle.clearHostileEnvironment(GLOB.cult_narsie) GLOB.cult_narsie = null addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(narsie_last_second_win)), 2 SECONDS) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 44d318d3467c81..fc2836a4e6dd40 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -80,10 +80,10 @@ ghost_notification_message, source = src, action = NOTIFY_ORBIT, - flashwindow = FALSE, + notify_flags = NOTIFY_CATEGORY_DEFAULT, ghost_sound = 'sound/machines/warning-buzzer.ogg', header = ghost_notification_message, - notify_volume = 75 + notify_volume = 75, ) diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 3f02447ddbcae6..38e692ef49990a 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -535,7 +535,12 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) final_countdown = TRUE SEND_GLOBAL_SIGNAL(COMSIG_MAIN_SM_DELAMINATING, final_countdown) // SKYRAT EDIT ADDITION - DELAM_SCRAM - notify_ghosts("[src] has begun the delamination process!", source = src, header = "Meltdown Incoming") + notify_ghosts( + "[src] has begun the delamination process!", + source = src, + header = "Meltdown Incoming", + notify_flags = NOTIFY_CATEGORY_DEFAULT, + ) var/datum/sm_delam/last_delamination_strategy = delamination_strategy var/list/count_down_messages = delamination_strategy.count_down_messages() diff --git a/code/modules/power/supermatter/supermatter_delamination/delamination_effects.dm b/code/modules/power/supermatter/supermatter_delamination/delamination_effects.dm index 21b91725d3639e..cbe3f3dab036c9 100644 --- a/code/modules/power/supermatter/supermatter_delamination/delamination_effects.dm +++ b/code/modules/power/supermatter/supermatter_delamination/delamination_effects.dm @@ -131,8 +131,13 @@ // say goodbye to that shuttle of yours if(SSshuttle.emergency.mode != SHUTTLE_ESCAPE) - priority_announce("Fatal error occurred in emergency shuttle uplink during transit. Unable to reestablish connection.", - "Emergency Shuttle Uplink Alert", ANNOUNCER_SHUTTLE) // SKYRAT EDIT CHANGE - Announcer Sounds + priority_announce( + text = "Fatal error occurred in emergency shuttle uplink during transit. Unable to reestablish connection.", + title = "Shuttle Failure", + sound = ANNOUNCER_SHUTTLE, // SKYRAT EDIT CHANGE - Announcer Sounds - ORIGINAL: sound = 'sound/misc/announce_dig.ogg', + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "grey", + ) else // except if you are on it already, then you are safe c: minor_announce("ERROR: Corruption detected in navigation protocols. Connection with Transponder #XCC-P5831-ES13 lost. \ diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm index 48facb18f029c4..972c98d4862c4e 100644 --- a/code/modules/power/tesla/coil.dm +++ b/code/modules/power/tesla/coil.dm @@ -116,7 +116,7 @@ power = min(surplus(), power) //Take the smaller of the two add_load(power) playsound(src.loc, 'sound/magic/lightningshock.ogg', zap_sound_volume, TRUE, zap_sound_range) - tesla_zap(src, 10, power, 1e3, zap_flags) + tesla_zap(source = src, zap_range = 10, power = power, cutoff = 1e3, zap_flags = zap_flags) zap_buckle_check(power) /obj/machinery/power/energy_accumulator/grounding_rod diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 9298e46512e0d6..3e0f3baef0d13c 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -76,7 +76,7 @@ pixel_y = 0 shocked_things.Cut(1, shocked_things.len / 1.3) var/list/shocking_info = list() - tesla_zap(src, 3, TESLA_DEFAULT_POWER, shocked_targets = shocking_info) + tesla_zap(source = src, zap_range = 3, power = TESLA_DEFAULT_POWER, shocked_targets = shocking_info) pixel_x = -32 pixel_y = -32 @@ -84,7 +84,7 @@ var/range = rand(1, clamp(orbiting_balls.len, 2, 3)) var/list/temp_shock = list() //We zap off the main ball instead of ourselves to make things looks proper - tesla_zap(src, range, TESLA_MINI_POWER/7*range, shocked_targets = temp_shock) + tesla_zap(source = src, zap_range = range, power = TESLA_MINI_POWER / 7 * range, shocked_targets = temp_shock) shocking_info += temp_shock shocked_things += shocking_info @@ -334,7 +334,7 @@ var/mob/living/closest_mob = closest_atom ADD_TRAIT(closest_mob, TRAIT_BEING_SHOCKED, WAS_SHOCKED) addtimer(TRAIT_CALLBACK_REMOVE(closest_mob, TRAIT_BEING_SHOCKED, WAS_SHOCKED), 1 SECONDS) - var/shock_damage = (zap_flags & ZAP_MOB_DAMAGE) ? (min(round(power/2.4e5), 90) + rand(-5, 5)) : 0 + var/shock_damage = (zap_flags & ZAP_MOB_DAMAGE) ? (min(round(power / 600), 90) + rand(-5, 5)) : 0 closest_mob.electrocute_act(shock_damage, source, 1, SHOCK_TESLA | ((zap_flags & ZAP_MOB_STUN) ? NONE : SHOCK_NOSTUN)) if(issilicon(closest_mob)) var/mob/living/silicon/S = closest_mob @@ -350,11 +350,11 @@ if(prob(20))//I know I know var/list/shocked_copy = shocked_targets.Copy() - tesla_zap(closest_atom, next_range, power * 0.5, zap_flags, shocked_copy)//Normally I'd copy here so grounding rods work properly, but it fucks with movement - tesla_zap(closest_atom, next_range, power * 0.5, zap_flags, shocked_targets) + tesla_zap(source = closest_atom, zap_range = next_range, power = power * 0.5, cutoff = cutoff, zap_flags = zap_flags, shocked_targets = shocked_copy) + tesla_zap(source = closest_atom, zap_range = next_range, power = power * 0.5, cutoff = cutoff, zap_flags = zap_flags, shocked_targets = shocked_targets) shocked_targets += shocked_copy else - tesla_zap(closest_atom, next_range, power, zap_flags, shocked_targets) + tesla_zap(source = closest_atom, zap_range = next_range, power = power, cutoff = cutoff, zap_flags = zap_flags, shocked_targets = shocked_targets) #undef BIKE #undef COIL diff --git a/code/modules/procedural_mapping/mapGenerator.dm b/code/modules/procedural_mapping/mapGenerator.dm index 4a79ad4c3059a7..8408e1d97b7a93 100644 --- a/code/modules/procedural_mapping/mapGenerator.dm +++ b/code/modules/procedural_mapping/mapGenerator.dm @@ -1,10 +1,12 @@ +///This type is responsible for any map generation behavior that is done in areas, override this to allow for +///area-specific map generation. This generation is ran by areas in initialize. /datum/map_generator - //Map information - var/list/map = list() + ///Map information, such as the start and end turfs of the map generation. + var/list/turf/map = list() - //mapGeneratorModule information - var/list/modules = list() + ///The map generator modules that we will generate and sync to. + var/list/datum/map_generator_module/modules = list() var/buildmode_name = "Undocumented" @@ -14,6 +16,18 @@ buildmode_name = copytext_char("[type]", 20) // / d a t u m / m a p g e n e r a t o r / = 20 characters. initialiseModules() +/datum/map_generator/Destroy(force, ...) + . = ..() + QDEL_LIST(modules) + +///This proc will be ran by areas on Initialize, and provides the areas turfs as argument to allow for generation. +/datum/map_generator/proc/generate_terrain(list/turfs, area/generate_in) + return + +/// Populate terrain with flora, fauna, features and basically everything that isn't a turf. +/datum/map_generator/proc/populate_terrain(list/turfs, area/generate_in) + return + //Defines the region the map represents, sets map //Returns the map /datum/map_generator/proc/defineRegion(turf/Start, turf/End, replace = 0) @@ -22,7 +36,7 @@ if(replace) undefineRegion() - map |= block(Start,End) + map |= block(Start, End) return map @@ -56,7 +70,7 @@ theRadius = max(radius/max((2*abs(sphereMagic-i)),1),1) - map |= circle_range(locate(centerX,centerY,i),theRadius) + map |= circle_range(locate(centerX, centerY, i),theRadius) return map @@ -87,7 +101,7 @@ syncModules() if(!modules || !modules.len) return - for(var/datum/map_generator_module/mod in modules) + for(var/datum/map_generator_module/mod as anything in modules) INVOKE_ASYNC(mod, TYPE_PROC_REF(/datum/map_generator_module, generate)) @@ -98,7 +112,7 @@ syncModules() if(!modules || !modules.len) return - for(var/datum/map_generator_module/mod in modules) + for(var/datum/map_generator_module/mod as anything in modules) INVOKE_ASYNC(mod, TYPE_PROC_REF(/datum/map_generator_module, place), T) @@ -113,7 +127,7 @@ //Sync mapGeneratorModule(s) to mapGenerator /datum/map_generator/proc/syncModules() - for(var/datum/map_generator_module/mod in modules) + for(var/datum/map_generator_module/mod as anything in modules) mod.sync(src) @@ -127,12 +141,12 @@ set category = "Debug" var/datum/map_generator/nature/N = new() - var/startInput = input(usr,"Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text|null + var/startInput = input(usr, "Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text|null if (isnull(startInput)) return - var/endInput = input(usr,"End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[mob ? mob.z : 1]") as text|null + var/endInput = input(usr, "End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[mob ? mob.z : 1]") as text|null if (isnull(endInput)) return @@ -158,9 +172,18 @@ to_chat(src, "End Coords: [endCoords[1]] - [endCoords[2]] - [endCoords[3]]") return - var/list/clusters = list("None"=CLUSTER_CHECK_NONE,"All"=CLUSTER_CHECK_ALL,"Sames"=CLUSTER_CHECK_SAMES,"Differents"=CLUSTER_CHECK_DIFFERENTS, \ - "Same turfs"=CLUSTER_CHECK_SAME_TURFS, "Same atoms"=CLUSTER_CHECK_SAME_ATOMS, "Different turfs"=CLUSTER_CHECK_DIFFERENT_TURFS, \ - "Different atoms"=CLUSTER_CHECK_DIFFERENT_ATOMS, "All turfs"=CLUSTER_CHECK_ALL_TURFS,"All atoms"=CLUSTER_CHECK_ALL_ATOMS) + var/static/list/clusters = list( + "None" = CLUSTER_CHECK_NONE, + "All" = CLUSTER_CHECK_ALL, + "Sames" = CLUSTER_CHECK_SAMES, + "Differents" = CLUSTER_CHECK_DIFFERENTS, + "Same turfs" = CLUSTER_CHECK_SAME_TURFS, + "Same atoms" = CLUSTER_CHECK_SAME_ATOMS, + "Different turfs" = CLUSTER_CHECK_DIFFERENT_TURFS, + "Different atoms" = CLUSTER_CHECK_DIFFERENT_ATOMS, + "All turfs" = CLUSTER_CHECK_ALL_TURFS, + "All atoms" = CLUSTER_CHECK_ALL_ATOMS, + ) var/moduleClusters = input("Cluster Flags (Cancel to leave unchanged from defaults)","Map Gen Settings") as null|anything in clusters //null for default @@ -175,7 +198,7 @@ theCluster = CLUSTER_CHECK_NONE if(theCluster) - for(var/datum/map_generator_module/M in N.modules) + for(var/datum/map_generator_module/M as anything in N.modules) M.clusterCheckFlags = theCluster diff --git a/code/modules/procedural_mapping/mapGeneratorModule.dm b/code/modules/procedural_mapping/mapGeneratorModule.dm index d5742fdb85ab09..aa3f0f0e93cc8c 100644 --- a/code/modules/procedural_mapping/mapGeneratorModule.dm +++ b/code/modules/procedural_mapping/mapGeneratorModule.dm @@ -8,6 +8,9 @@ var/clusterCheckFlags = CLUSTER_CHECK_SAME_ATOMS var/allowAtomsOnSpace = FALSE +/datum/map_generator_module/Destroy(force, ...) + mother = null + return ..() //Syncs the module up with its mother /datum/map_generator_module/proc/sync(datum/map_generator/mum) diff --git a/code/modules/projectiles/ammunition/ballistic/rifle.dm b/code/modules/projectiles/ammunition/ballistic/rifle.dm index 3e545dc106077c..8e06a0e10b5af5 100644 --- a/code/modules/projectiles/ammunition/ballistic/rifle.dm +++ b/code/modules/projectiles/ammunition/ballistic/rifle.dm @@ -49,3 +49,27 @@ name = "40mm rubber shell" desc = "A cased rubber slug. The big brother of the beanbag slug, this thing will knock someone out in one. Doesn't do so great against anyone in armor." projectile_type = /obj/projectile/bullet/shotgun_beanbag/a40mm + +/obj/item/ammo_casing/rebar + name = "sharpened iron rod" + desc = "A Sharpened Iron rod. It's Pointy!" + caliber = CALIBER_REBAR + icon_state = "rod_sharp" + base_icon_state = "rod_sharp" + projectile_type = /obj/projectile/bullet/rebar + +/obj/item/ammo_casing/rebar/Initialize(mapload) + . = ..() + AddElement(/datum/element/caseless, TRUE) + +/obj/item/ammo_casing/rebar/update_icon_state() + . = ..() + icon_state = "[base_icon_state]" + +/obj/item/ammo_casing/rebar/syndie + name = "Jagged iron rod" + desc = "An Iron rod, with notches cut into it. You really dont want this stuck in you." + caliber = CALIBER_REBAR_SYNDIE + icon_state = "rod_jagged" + base_icon_state = "rod_jagged" + projectile_type = /obj/projectile/bullet/rebarsyndie diff --git a/code/modules/projectiles/boxes_magazines/internal/rifle.dm b/code/modules/projectiles/boxes_magazines/internal/rifle.dm index 83133186c9ddcd..5fdc182ccff985 100644 --- a/code/modules/projectiles/boxes_magazines/internal/rifle.dm +++ b/code/modules/projectiles/boxes_magazines/internal/rifle.dm @@ -28,3 +28,24 @@ max_ammo = 1 caliber = CALIBER_HARPOON ammo_type = /obj/item/ammo_casing/harpoon + +/obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/normal + name = "single round magazine" + max_ammo = 1 + caliber = CALIBER_REBAR + ammo_type = /obj/item/ammo_casing/rebar + +/obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/force + name = "two round magazine" + max_ammo = 2 + caliber = CALIBER_REBAR_FORCED + ammo_type = /obj/item/ammo_casing/rebar + +/obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/syndie + max_ammo = 3 + caliber = CALIBER_REBAR_SYNDIE + ammo_type = /obj/item/ammo_casing/rebar/syndie + +/obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/syndie/normal + caliber = CALIBER_REBAR_SYNDIE_NORMAL + ammo_type = /obj/item/ammo_casing/rebar diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index f87f473ae459bb..2b943a5f6db633 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -139,11 +139,17 @@ desc = "A modernized 7 round revolver manufactured by Waffle Co. Uses .357 ammo." icon_state = "revolversyndie" +/obj/item/gun/ballistic/revolver/syndicate/nuclear + pin = /obj/item/firing_pin/implant/pindicate + /obj/item/gun/ballistic/revolver/syndicate/cowboy desc = "A classic revolver, refurbished for modern use. Uses .357 ammo." //There's already a cowboy sprite in there! icon_state = "lucky" +/obj/item/gun/ballistic/revolver/syndicate/cowboy/nuclear + pin = /obj/item/firing_pin/implant/pindicate + /obj/item/gun/ballistic/revolver/mateba name = "\improper Unica 6 auto-revolver" desc = "A retro high-powered autorevolver typically used by officers of the New Russia military. Uses .357 ammo." diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm index 67c70352ff3069..a7a1206db1f7b0 100644 --- a/code/modules/projectiles/guns/ballistic/rifle.dm +++ b/code/modules/projectiles/guns/ballistic/rifle.dm @@ -25,6 +25,7 @@ return drop_bolt(user) + /obj/item/gun/ballistic/rifle/can_shoot() if (bolt_locked) return FALSE @@ -169,6 +170,91 @@ if(.) name = "\improper Obrez Moderna" // wear it loud and proud +/obj/item/gun/ballistic/rifle/rebarxbow + name = "Heated Rebar Crossbow" + desc = "Made from an inducer, iron rods, and some wire, this crossbow fires sharpened iron rods, made from the plentiful iron rods found stationwide. \ + Only holds one rod in the magazine - you can craft the crossbow with a crowbar to try and force a second rod in, but risks a misfire, or worse..." + icon = 'icons/obj/weapons/guns/ballistic.dmi' + icon_state = "rebarxbow" + inhand_icon_state = "rebarxbow" + worn_icon_state = "rebarxbow" + rack_sound = 'sound/weapons/gun/sniper/rack.ogg' + must_hold_to_load = TRUE + mag_display = FALSE + empty_indicator = TRUE + bolt_type = BOLT_TYPE_LOCKING + semi_auto = FALSE + internal_magazine = TRUE + can_modify_ammo = FALSE + slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_SUITSTORE + bolt_wording = "bowstring" + magazine_wording = "rod" + cartridge_wording = "rod" + misfire_probability = 25 + weapon_weight = WEAPON_HEAVY + initial_caliber = CALIBER_REBAR + accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/normal + fire_sound = 'sound/items/syringeproj.ogg' + can_be_sawn_off = FALSE + tac_reloads = FALSE + var/draw_time = 3 SECONDS + SET_BASE_PIXEL(0, 0) + +/obj/item/gun/ballistic/rifle/rebarxbow/rack(mob/user = null) + if (bolt_locked) + drop_bolt(user) + return + balloon_alert(user, "bowstring loosened") + playsound(src, rack_sound, rack_sound_volume, rack_sound_vary) + handle_chamber(empty_chamber = FALSE, from_firing = FALSE, chamber_next_round = FALSE) + bolt_locked = TRUE + update_appearance() + +/obj/item/gun/ballistic/rifle/rebarxbow/drop_bolt(mob/user = null) + if(!do_after(user, draw_time, target = src)) + return + playsound(src, bolt_drop_sound, bolt_drop_sound_volume, FALSE) + balloon_alert(user, "bowstring drawn") + chamber_round() + bolt_locked = FALSE + update_appearance() + +/obj/item/gun/ballistic/rifle/rebarxbow/can_shoot() + if (bolt_locked) + return FALSE + return ..() + +/obj/item/gun/ballistic/rifle/rebarxbow/examine(mob/user) + . = ..() + . += "The crossbow is [bolt_locked ? "not ready" : "ready"] to fire." + +/obj/item/gun/ballistic/rifle/rebarxbow/forced + name = "Stressed Rebar Crossbow" + desc = "Some idiot decided that they would risk shooting themselves in the face if it meant they could have a bit more ammo in this crossbow. Hopefully, it was worth it." + // Feel free to add a recipe to allow you to change it back if you would like, I just wasn't sure if you could have two recipes for the same thing. + can_misfire = TRUE + misfire_probability = 25 + accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/force + +/obj/item/gun/ballistic/rifle/rebarxbow/syndie + name = "Syndicate Rebar Crossbow" + desc = "The syndicate liked the bootleg rebar crossbow NT engineers made, so they showed what it could be if properly developed. \ + Holds three shots without a chance of exploding, and features a built in scope. Normally uses special syndicate jagged iron bars, but can be wrenched to shoot inferior normal ones." + icon_state = "rebarxbowsyndie" + inhand_icon_state = "rebarxbowsyndie" + worn_icon_state = "rebarxbowsyndie" + w_class = WEIGHT_CLASS_NORMAL + can_modify_ammo = TRUE + initial_caliber = CALIBER_REBAR_SYNDIE + alternative_caliber = CALIBER_REBAR_SYNDIE_NORMAL + alternative_ammo_misfires = FALSE + draw_time = 1 + accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/syndie + +/obj/item/gun/ballistic/rifle/rebarxbow/syndie/Initialize(mapload) + . = ..() + AddComponent(/datum/component/scope, range_modifier = 2) //enough range to at least be useful for stealth + /obj/item/gun/ballistic/rifle/boltaction/pipegun name = "pipegun" desc = "An excellent weapon for flushing out tunnel rats and enemy assistants, but its rifling leaves much to be desired." diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index e43f6defeb34e5..e0130f9f16a8e7 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -40,11 +40,10 @@ desc = "A modified laser gun which can shoot far faster, but each shot is far less damaging." icon_state = "laser_carbine" ammo_type = list(/obj/item/ammo_casing/energy/lasergun/carbine) - var/allow_akimbo = FALSE /obj/item/gun/energy/laser/carbine/Initialize(mapload) . = ..() - AddComponent(/datum/component/automatic_fire, 0.15 SECONDS, allow_akimbo = allow_akimbo) + AddComponent(/datum/component/automatic_fire, 0.15 SECONDS, allow_akimbo = FALSE) /obj/item/gun/energy/laser/carbine/practice name = "practice laser carbine" @@ -53,7 +52,6 @@ clumsy_check = FALSE item_flags = NONE gun_flags = NOT_A_REAL_GUN - allow_akimbo = TRUE /obj/item/gun/energy/laser/retro/old name ="laser gun" diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm index 4db8e626bda2e6..582ee474f4db16 100644 --- a/code/modules/projectiles/guns/energy/pulse.dm +++ b/code/modules/projectiles/guns/energy/pulse.dm @@ -26,7 +26,13 @@ message_admins("A pulse rifle prize has been created at [ADMIN_VERBOSEJMP(T)]") log_game("A pulse rifle prize has been created at [AREACOORD(T)]") - notify_ghosts("Someone won a pulse rifle as a prize!", source = src, action = NOTIFY_ORBIT, header = "Pulse rifle prize") + notify_ghosts( + "Someone won a pulse rifle as a prize!", + source = src, + action = NOTIFY_ORBIT, + header = "Pulse rifle prize", + notify_flags = NOTIFY_CATEGORY_DEFAULT, + ) /obj/item/gun/energy/pulse/loyalpin pin = /obj/item/firing_pin/implant/mindshield diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm index 45763feff043b6..5437a7096da5b0 100644 --- a/code/modules/projectiles/pins.dm +++ b/code/modules/projectiles/pins.dm @@ -30,19 +30,19 @@ if(proximity_flag) if(isgun(target)) . |= AFTERATTACK_PROCESSED_ITEM - var/obj/item/gun/targetted_gun = target - var/obj/item/firing_pin/old_pin = targetted_gun.pin + var/obj/item/gun/targeted_gun = target + var/obj/item/firing_pin/old_pin = targeted_gun.pin if(old_pin?.pin_removable && (force_replace || old_pin.pin_hot_swappable)) if(Adjacent(user)) user.put_in_hands(old_pin) else - old_pin.forceMove(targetted_gun.drop_location()) + old_pin.forceMove(targeted_gun.drop_location()) old_pin.gun_remove(user) - if(!targetted_gun.pin) + if(!targeted_gun.pin) if(!user.temporarilyRemoveItemFromInventory(src)) return . - if(gun_insert(user, targetted_gun)) + if(gun_insert(user, targeted_gun)) if(old_pin) balloon_alert(user, "swapped firing pin") else diff --git a/code/modules/projectiles/projectile/bullets/rifle.dm b/code/modules/projectiles/projectile/bullets/rifle.dm index 4cb7bd543b481d..de7e59facc3cf3 100644 --- a/code/modules/projectiles/projectile/bullets/rifle.dm +++ b/code/modules/projectiles/projectile/bullets/rifle.dm @@ -47,3 +47,32 @@ embedding = list(embed_chance=100, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10) wound_falloff_tile = -5 shrapnel_type = /obj/item/ammo_casing/harpoon + +// Rebar (Rebar Crossbow) +/obj/projectile/bullet/rebar + name = "rebar" + icon_state = "rebar" + damage = 30 + speed = 0.4 + dismemberment = 1 //because a 1 in 100 chance to just blow someones arm off is enough to be cool but also not enough to be reliable + armour_penetration = 10 + wound_bonus = -20 + bare_wound_bonus = 20 + embedding = list(embed_chance=60, fall_chance=2, jostle_chance=2, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=3, jostle_pain_mult=2, rip_time=10) + embed_falloff_tile = -5 + wound_falloff_tile = -2 + shrapnel_type = /obj/item/stack/rods + +/obj/projectile/bullet/rebarsyndie + name = "rebar" + icon_state = "rebar" + damage = 35 + speed = 0.4 + dismemberment = 2 //It's a budget sniper rifle. + armour_penetration = 20 //A bit better versus armor. Gets past anti laser armor or a vest, but doesnt wound proc on sec armor. + wound_bonus = 10 + bare_wound_bonus = 10 + embedding = list(embed_chance=80, fall_chance=1, jostle_chance=3, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=3, jostle_pain_mult=2, rip_time=14) + embed_falloff_tile = -3 + shrapnel_type = /obj/item/stack/rods + diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 85016dc93aaff2..9bdd5a145ead2b 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -71,7 +71,6 @@ /obj/projectile/bullet/pellet icon_state = "pellet" damage_falloff_tile = -0.45 - stamina_falloff_tile = -0.25 /obj/projectile/bullet/pellet/shotgun_buckshot name = "buckshot pellet" @@ -87,6 +86,7 @@ sharpness = NONE embedding = null speed = 1.2 + stamina_falloff_tile = -0.25 ricochets_max = 4 ricochet_chance = 120 ricochet_decay_chance = 0.9 diff --git a/code/modules/projectiles/projectile/energy/tesla.dm b/code/modules/projectiles/projectile/energy/tesla.dm index 65b9ba0162e123..9dfe043a015655 100644 --- a/code/modules/projectiles/projectile/energy/tesla.dm +++ b/code/modules/projectiles/projectile/energy/tesla.dm @@ -5,24 +5,24 @@ damage = 10 //A worse lasergun var/zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN var/zap_range = 3 - var/power = 4e6 + var/power = 1e4 /obj/projectile/energy/tesla/on_hit(atom/target, blocked = 0, pierce_hit) . = ..() - tesla_zap(src, zap_range, power, zap_flags) + tesla_zap(source = src, zap_range = zap_range, power = power, cutoff = 1e3, zap_flags = zap_flags) qdel(src) /obj/projectile/energy/tesla/process() . = ..() //Many coders have given their blood for this speed - tesla_zap(src, zap_range, power, zap_flags) + tesla_zap(source = src, zap_range = zap_range, power = power, cutoff = 1e3, zap_flags = zap_flags) /obj/projectile/energy/tesla/revolver name = "energy orb" /obj/projectile/energy/tesla/cannon name = "tesla orb" - power = 8e6 + power = 2e4 damage = 15 //Mech man big /obj/projectile/energy/tesla_cannon diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index 7b2d546b668f8b..2f3214d5d90aba 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -481,7 +481,7 @@ speed = 0.3 /// The power of the zap itself when it electrocutes someone - var/zap_power = 8e6 + var/zap_power = 2e4 /// The range of the zap itself when it electrocutes someone var/zap_range = 15 /// The flags of the zap itself when it electrocutes someone @@ -496,14 +496,14 @@ /obj/projectile/magic/aoe/lightning/on_hit(atom/target, blocked = 0, pierce_hit) . = ..() - tesla_zap(src, zap_range, zap_power, zap_flags) + tesla_zap(source = src, zap_range = zap_range, power = zap_power, cutoff = 1e3, zap_flags = zap_flags) /obj/projectile/magic/aoe/lightning/Destroy() QDEL_NULL(chain) return ..() /obj/projectile/magic/aoe/lightning/no_zap - zap_power = 4e6 + zap_power = 1e4 zap_range = 4 zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN diff --git a/code/modules/reagents/chemistry/equilibrium.dm b/code/modules/reagents/chemistry/equilibrium.dm index f46c636c50f59b..073eaf69e5ae17 100644 --- a/code/modules/reagents/chemistry/equilibrium.dm +++ b/code/modules/reagents/chemistry/equilibrium.dm @@ -324,11 +324,11 @@ //keep limited if(delta_chem_factor > step_target_vol) delta_chem_factor = step_target_vol - else if (delta_chem_factor < CHEMICAL_QUANTISATION_LEVEL) - delta_chem_factor = CHEMICAL_QUANTISATION_LEVEL + else if (delta_chem_factor < CHEMICAL_VOLUME_ROUNDING) + delta_chem_factor = CHEMICAL_VOLUME_ROUNDING //Normalise to multiproducts delta_chem_factor /= product_ratio - //delta_chem_factor = round(delta_chem_factor, CHEMICAL_QUANTISATION_LEVEL) // Might not be needed - left here incase testmerge shows that it does. Remove before full commit. + delta_chem_factor = round(delta_chem_factor, CHEMICAL_VOLUME_ROUNDING) // Might not be needed - left here incase testmerge shows that it does. Remove before full commit. //Calculate how much product to make and how much reactant to remove factors.. for(var/reagent in reaction.required_reagents) diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 0d0b62a6686c39..f948bdffebbb6d 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -93,11 +93,6 @@ if(SEND_SIGNAL(src, COMSIG_REAGENTS_PRE_ADD_REAGENT, reagent_type, amount, reagtemp, data, no_react) & COMPONENT_CANCEL_REAGENT_ADD) return FALSE - // Prevents small amount problems, as well as zero and below zero amounts. - amount = FLOOR(amount, CHEMICAL_QUANTISATION_LEVEL) - if(amount <= 0) - return FALSE - var/datum/reagent/glob_reagent = GLOB.chemical_reagents_list[reagent_type] if(!glob_reagent) stack_trace("[my_atom] attempted to add a reagent called '[reagent_type]' which doesn't exist. ([usr])") @@ -110,8 +105,8 @@ //Split up the reagent if it's in a mob var/has_split = FALSE if(!ignore_splitting && (flags & REAGENT_HOLDER_ALIVE)) //Stomachs are a pain - they will constantly call on_mob_add unless we split on addition to stomachs, but we also want to make sure we don't double split - var/adjusted_vol = FLOOR(process_mob_reagent_purity(glob_reagent, amount, added_purity), CHEMICAL_QUANTISATION_LEVEL) - if(adjusted_vol <= 0) //If we're inverse or FALSE cancel addition + var/adjusted_vol = process_mob_reagent_purity(glob_reagent, amount, added_purity) + if(!adjusted_vol) //If we're inverse or FALSE cancel addition return amount /* We return true here because of #63301 The only cases where this will be false or 0 if its an inverse chem, an impure chem of 0 purity (highly unlikely if even possible), or if glob_reagent is null (which shouldn't happen at all as there's a check for that a few lines up), @@ -123,9 +118,10 @@ update_total() var/cached_total = total_volume if(cached_total + amount > maximum_volume) - amount = FLOOR(maximum_volume - cached_total, CHEMICAL_QUANTISATION_LEVEL) //Doesnt fit in. Make it disappear. shouldn't happen. Will happen. - if(amount <= 0) - return FALSE + amount = maximum_volume - cached_total //Doesnt fit in. Make it disappear. shouldn't happen. Will happen. + amount = round(amount, CHEMICAL_QUANTISATION_LEVEL) + if(amount <= 0) + return FALSE var/cached_temp = chem_temp var/list/cached_reagents = reagent_list @@ -143,8 +139,8 @@ added_ph = iter_reagent.ph iter_reagent.purity = ((iter_reagent.creation_purity * iter_reagent.volume) + (added_purity * amount)) /(iter_reagent.volume + amount) //This should add the purity to the product iter_reagent.creation_purity = iter_reagent.purity - iter_reagent.ph = ((iter_reagent.ph*(iter_reagent.volume))+(added_ph*amount))/(iter_reagent.volume+amount) - iter_reagent.volume = FLOOR(iter_reagent.volume + amount, CHEMICAL_QUANTISATION_LEVEL) + iter_reagent.ph = ((iter_reagent.ph * (iter_reagent.volume)) + (added_ph * amount)) / (iter_reagent.volume + amount) + iter_reagent.volume += amount update_total() iter_reagent.on_merge(data, amount) @@ -219,21 +215,23 @@ stack_trace("non finite amount passed to remove reagent [amount] [reagent_type]") return FALSE - // Prevents small amount problems, as well as zero and below zero amounts. - amount = FLOOR(amount, CHEMICAL_QUANTISATION_LEVEL) + amount = round(amount, CHEMICAL_QUANTISATION_LEVEL) if(amount <= 0) return FALSE var/list/cached_reagents = reagent_list for(var/datum/reagent/cached_reagent as anything in cached_reagents) if(cached_reagent.type == reagent_type) - cached_reagent.volume = FLOOR(max(cached_reagent.volume - amount, 0), CHEMICAL_QUANTISATION_LEVEL) + cached_reagent.volume -= amount + update_total() if(!safety)//So it does not handle reactions when it need not to handle_reactions() + SEND_SIGNAL(src, COMSIG_REAGENTS_REM_REAGENT, QDELING(cached_reagent) ? reagent_type : cached_reagent, amount) return TRUE + return FALSE /** @@ -247,7 +245,7 @@ stack_trace("non finite amount passed to remove any reagent [amount]") return FALSE - amount = FLOOR(amount, CHEMICAL_QUANTISATION_LEVEL) + amount = round(amount, CHEMICAL_QUANTISATION_LEVEL) if(amount <= 0) return FALSE @@ -274,7 +272,6 @@ current_list_element++ total_removed += remove_amt - update_total() handle_reactions() return total_removed //this should be amount unless the loop is prematurely broken, in which case it'll be lower. It shouldn't ever go OVER amount. @@ -295,8 +292,7 @@ stack_trace("non finite amount passed to remove all reagents [amount]") return FALSE - // Prevents small amount problems, as well as zero and below zero amounts. - amount = FLOOR(amount, CHEMICAL_QUANTISATION_LEVEL) + amount = round(amount, CHEMICAL_QUANTISATION_LEVEL) if(amount <= 0) return FALSE @@ -306,12 +302,12 @@ var/removed_amount = 0 for(var/datum/reagent/reagent as anything in cached_reagents) - remove_amount = FLOOR(reagent.volume * part, CHEMICAL_QUANTISATION_LEVEL) + remove_amount = reagent.volume * part remove_reagent(reagent.type, remove_amount) removed_amount += remove_amount handle_reactions() - return removed_amount + return round(removed_amount, CHEMICAL_VOLUME_ROUNDING) /** * Removes all reagent of X type @@ -330,8 +326,7 @@ stack_trace("non finite amount passed to remove all type reagent [amount] [reagent_type]") return FALSE - // Prevents small amount problems, as well as zero and below zero amounts. - amount = FLOOR(amount, CHEMICAL_QUANTISATION_LEVEL) + amount = round(amount, CHEMICAL_QUANTISATION_LEVEL) if(amount <= 0) return FALSE @@ -531,7 +526,7 @@ var/mob/living/carbon/eater = target var/obj/item/organ/internal/stomach/belly = eater.get_organ_slot(ORGAN_SLOT_STOMACH) if(!belly) - var/expel_amount = FLOOR(amount, CHEMICAL_QUANTISATION_LEVEL) + var/expel_amount = round(amount, CHEMICAL_QUANTISATION_LEVEL) if(expel_amount > 0 ) eater.expel_ingested(my_atom, expel_amount) return @@ -546,9 +541,9 @@ var/cached_amount = amount // Prevents small amount problems, as well as zero and below zero amounts. - amount = FLOOR(min(amount, total_volume, target_holder.maximum_volume - target_holder.total_volume), CHEMICAL_QUANTISATION_LEVEL) + amount = round(min(amount, total_volume, target_holder.maximum_volume - target_holder.total_volume), CHEMICAL_QUANTISATION_LEVEL) if(amount <= 0) - return FALSE + return //Set up new reagents to inherit the old ongoing reactions if(!no_react) @@ -602,7 +597,8 @@ if(!no_react) target_holder.handle_reactions() src.handle_reactions() - return FLOOR(total_transfered_amount, CHEMICAL_QUANTISATION_LEVEL) + + return round(total_transfered_amount, CHEMICAL_VOLUME_ROUNDING) /** * Transfer a specific reagent id to the target object @@ -638,7 +634,7 @@ return // Prevents small amount problems, as well as zero and below zero amounts. - amount = FLOOR(min(amount, available_volume, holder.maximum_volume - holder.total_volume), CHEMICAL_QUANTISATION_LEVEL) + amount = round(min(amount, available_volume, holder.maximum_volume - holder.total_volume), CHEMICAL_QUANTISATION_LEVEL) if(amount <= 0) return @@ -694,7 +690,7 @@ target_holder = target.reagents // Prevents small amount problems, as well as zero and below zero amounts. - amount = FLOOR(min(amount, total_volume, target_holder.maximum_volume - target_holder.total_volume), CHEMICAL_QUANTISATION_LEVEL) + amount = round(min(amount, total_volume, target_holder.maximum_volume - target_holder.total_volume), CHEMICAL_QUANTISATION_LEVEL) if(amount <= 0) return @@ -721,7 +717,7 @@ target_holder.update_total() target_holder.handle_reactions() - return FLOOR(total_transfered_amount, CHEMICAL_QUANTISATION_LEVEL) + return round(total_transfered_amount, CHEMICAL_VOLUME_ROUNDING) /** * Multiplies the reagents inside this holder by a specific amount @@ -809,7 +805,7 @@ var/datum/reagent/toxin/toxin = reagent var/amount = toxin.volume if(belly) - amount = FLOOR(amount + belly.reagents.get_reagent_amount(toxin.type), CHEMICAL_QUANTISATION_LEVEL) + amount += belly.reagents.get_reagent_amount(toxin.type) if(amount <= liver_tolerance) owner.reagents.remove_reagent(toxin.type, toxin.metabolization_rate * owner.metabolism_efficiency * seconds_per_tick) @@ -1174,9 +1170,6 @@ /datum/reagents/proc/finish_reacting() STOP_PROCESSING(SSreagents, src) is_reacting = FALSE - //Cap off values - for(var/datum/reagent/reagent as anything in reagent_list) - reagent.volume = FLOOR(reagent.volume, CHEMICAL_QUANTISATION_LEVEL)//To prevent runaways. LAZYNULL(previous_reagent_list) //reset it to 0 - because any change will be different now. update_total() if(!QDELING(src)) @@ -1276,9 +1269,9 @@ var/datum/cached_my_atom = my_atom var/multiplier = INFINITY for(var/reagent in cached_required_reagents) - multiplier = FLOOR(min(multiplier, get_reagent_amount(reagent) / cached_required_reagents[reagent]), CHEMICAL_QUANTISATION_LEVEL) + multiplier = round(min(multiplier, get_reagent_amount(reagent) / cached_required_reagents[reagent])) - if(multiplier == 0)//Incase we're missing reagents - usually from on_reaction being called in an equlibrium when the results.len == 0 handlier catches a misflagged reaction + if(!multiplier)//Incase we're missing reagents - usually from on_reaction being called in an equlibrium when the results.len == 0 handlier catches a misflagged reaction return FALSE var/sum_purity = 0 for(var/_reagent in cached_required_reagents)//this is not an object @@ -1329,6 +1322,7 @@ var/chem_index = 1 var/num_reagents = length(cached_reagents) var/total_ph = 0 + var/reagent_volume = 0 . = 0 //responsible for removing reagents and computing total ph & volume @@ -1336,9 +1330,10 @@ while(chem_index <= num_reagents) var/datum/reagent/reagent = cached_reagents[chem_index] chem_index += 1 + reagent_volume = round(reagent.volume, CHEMICAL_QUANTISATION_LEVEL) //round to this many decimal places //remove very small amounts of reagents - if((reagent.volume <= 0.05 && !is_reacting) || reagent.volume <= CHEMICAL_QUANTISATION_LEVEL) + if((reagent_volume <= 0.05 && !is_reacting) || reagent_volume <= CHEMICAL_QUANTISATION_LEVEL) //end metabolization if(isliving(my_atom)) if(reagent.metabolizing) @@ -1357,11 +1352,14 @@ continue //compute volume & ph like we would normally - . += reagent.volume - total_ph += (reagent.ph * reagent.volume) + . += reagent_volume + total_ph += (reagent.ph * reagent_volume) + + //reasign rounded value + reagent.volume = reagent_volume - //assign the final values - total_volume = . + //assign the final values, rounding up can sometimes cause overflow so bring it down + total_volume = min(round(., CHEMICAL_VOLUME_ROUNDING), maximum_volume) if(!.) ph = CHEMICAL_NORMAL_PH else @@ -1414,7 +1412,7 @@ /// Is this holder full or not /datum/reagents/proc/holder_full() - return total_volume + 0.01 >= maximum_volume + return total_volume >= maximum_volume /** * Get the amount of this reagent or the sum of all its subtypes if specified @@ -1433,7 +1431,7 @@ if((!include_subtypes && cached_reagent.type == reagent) || (include_subtypes && ispath(cached_reagent.type, reagent))) total_amount += cached_reagent.volume - return FLOOR(total_amount, CHEMICAL_QUANTISATION_LEVEL) + return round(total_amount, CHEMICAL_VOLUME_ROUNDING) /** * Gets the sum of volumes of all reagent type paths present in the list @@ -1445,8 +1443,9 @@ var/total_amount = 0 for(var/datum/reagent/cached_reagent as anything in cached_reagents) if(cached_reagent.type in reagents) - total_amount += FLOOR(cached_reagent.volume, CHEMICAL_QUANTISATION_LEVEL) - return total_amount + total_amount += cached_reagent.volume + + return round(total_amount, CHEMICAL_VOLUME_ROUNDING) /** * Get the purity of this reagent @@ -1462,6 +1461,7 @@ for(var/datum/reagent/cached_reagent as anything in cached_reagents) if(cached_reagent.type == reagent) return round(cached_reagent.purity, 0.01) + return 0 /** @@ -1663,7 +1663,7 @@ for(var/reagent_type in external_list) var/list/qualities = external_list[reagent_type] - data += "[reagent_type] ([FLOOR(qualities[REAGENT_TRANSFER_AMOUNT], CHEMICAL_QUANTISATION_LEVEL)]u, [qualities[REAGENT_PURITY]] purity)" + data += "[reagent_type] ([round(qualities[REAGENT_TRANSFER_AMOUNT], CHEMICAL_QUANTISATION_LEVEL)]u, [qualities[REAGENT_PURITY]] purity)" return english_list(data) @@ -1675,7 +1675,7 @@ var/list/data = list() for(var/datum/reagent/reagent as anything in reagent_list) - data += "[reagent.type] ([FLOOR(reagent.volume, CHEMICAL_QUANTISATION_LEVEL)]u, [reagent.purity] purity)" + data += "[reagent.type] ([round(reagent.volume, CHEMICAL_QUANTISATION_LEVEL)]u, [reagent.purity] purity)" return english_list(data) @@ -1849,7 +1849,7 @@ to_chat(user, "Could not find reagent!") ui_reagent_id = null else - data["reagent_mode_reagent"] = list("name" = reagent.name, "id" = reagent.type, "desc" = reagent.description, "reagentCol" = reagent.color, "pH" = reagent.ph, "pHCol" = convert_ph_to_readable_color(reagent.ph), "metaRate" = (reagent.metabolization_rate/2), "OD" = reagent.overdose_threshold) + data["reagent_mode_reagent"] = list("name" = reagent.name, "id" = reagent.type, "desc" = reagent.description, "reagentCol" = reagent.color, "pH" = reagent.ph, "pHCol" = convert_ph_to_readable_color(reagent.ph), "metaRate" = reagent.metabolization_rate, "OD" = reagent.overdose_threshold) data["reagent_mode_reagent"]["addictions"] = list() data["reagent_mode_reagent"]["addictions"] = parse_addictions(reagent) diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index a3ed883551f30b..b677a8c02c9669 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -1,16 +1,3 @@ -/proc/translate_legacy_chem_id(id) - switch (id) - if ("sacid") - return "sulfuricacid" - if ("facid") - return "fluorosulfuricacid" - if ("co2") - return "carbondioxide" - if ("mine_salve") - return "minerssalve" - else - return ckey(id) - /obj/machinery/chem_dispenser name = "chem dispenser" desc = "Creates and dispenses chemicals." @@ -23,21 +10,57 @@ circuit = /obj/item/circuitboard/machine/chem_dispenser processing_flags = NONE + /// The cell used to dispense reagents var/obj/item/stock_parts/cell/cell + /// Efficiency used when converting cell power to reagents var/powerefficiency = 0.1 + /// The current amount this machine is dispensing var/amount = 30 + /// The rate at which this machine recharges the power cell var/recharge_amount = 10 + /// Keep track of the intervals made during recharges var/recharge_counter = 0 + /// The temperature reagents are dispensed into the beaker var/dispensed_temperature = DEFAULT_REAGENT_TEMPERATURE - ///If the UI has the pH meter shown + /// If the UI has the pH meter shown var/show_ph = TRUE + /// The overlay used to display the beaker on the machine var/mutable_appearance/beaker_overlay + /// Icon to display when the machine is powered var/working_state = "dispenser_working" + /// Icon to display when the machine is not powered var/nopower_state = "dispenser_nopower" + /// Should we display the open panel overlay when the panel is opened with a screwdriver var/has_panel_overlay = TRUE + /// The actual beaker inserted into this machine var/obj/item/reagent_containers/beaker = null - //dispensable_reagents is copypasted in plumbing synthesizers. Please update accordingly. (I didn't make it global because that would limit custom chem dispensers) - var/list/dispensable_reagents = list( + /// Dispensable_reagents is copypasted in plumbing synthesizers. Please update accordingly. (I didn't make it global because that would limit custom chem dispensers) + var/list/dispensable_reagents = list() + /// These become available once the manipulator has been upgraded to tier 2 (nano) // SKYRAT EDIT CHANGE - ORIGINAL: /// These become available once the manipulator has been upgraded to tier 4 (femto) + var/list/upgrade_reagents = list() + // SKYRAT EDIT ADDITION BEGIN + /// These become available once the manipulator has been upgraded to tier 3 (pico) + var/list/upgrade2_reagents = list() + /// These become available once the manipulator has been upgraded to tier 4 (femto) + var/list/upgrade3_reagents = list() + // SKYRAT EDIT ADDITION END + /// These become available once the machine has been emaged + var/list/emagged_reagents = list() + /// Starting purity of the created reagents + var/base_reagent_purity = 1 + /// Records the reagents dispensed by the user if this list is not null + var/list/recording_recipe + /// Saves all the recipes recorded by the machine + var/list/saved_recipes = list() + // SKYRAT EDIT ADDITION BEGIN + /// Used for custom transfer amounts + var/list/transferAmounts = list() + /// The custom transfer amount + var/customTransferAmount + // SKYRAT EDIT ADDITION END + + /// The default list of dispensable_reagents + var/static/list/default_dispensable_reagents = list( /datum/reagent/aluminium, /datum/reagent/bromine, /datum/reagent/carbon, @@ -64,10 +87,11 @@ /datum/reagent/water, /datum/reagent/fuel, ) - //these become available once the manipulator has been upgraded to tier 4 (femto) - //SKYRAT EDIT REMOVAL BEGIN - Skyrat-SS13/Skyrat-tg#1931 + + //SKYRAT EDIT CHANGE BEGIN - ORIGINAL /* - var/list/upgrade_reagents = list( + /// The default list of reagents upgrade_reagents + var/static/list/default_upgrade_reagents = list( /datum/reagent/acetone, /datum/reagent/ammonia, /datum/reagent/ash, @@ -75,7 +99,8 @@ /datum/reagent/fuel/oil, /datum/reagent/saltpetre ) - var/list/emagged_reagents = list( + /// The default list of reagents emagged_reagents + var/static/list/default_emagged_reagents = list( /datum/reagent/toxin/carpotoxin, /datum/reagent/medicine/mine_salve, /datum/reagent/medicine/morphine, @@ -83,26 +108,24 @@ /datum/reagent/toxin ) */ - //SKYRAT EDIT REMOVAL END - //SKYRAT EDIT ADDITION BEGIN - Skyrat-SS13/Skyrat-tg#1931 - var/list/upgrade_reagents = list( + var/static/list/default_upgrade_reagents = list( /datum/reagent/fuel/oil, /datum/reagent/ammonia, /datum/reagent/ash ) - var/list/upgrade_reagents2 = list( + var/static/list/default_upgrade2_reagents = list( /datum/reagent/acetone, /datum/reagent/phenol, /datum/reagent/diethylamine ) - var/list/upgrade_reagents3 = list( + var/static/list/default_upgrade3_reagents = list( /datum/reagent/medicine/mine_salve, /datum/reagent/toxin ) - var/list/emagged_reagents = list( + var/static/list/default_emagged_reagents = list( /datum/reagent/drug/space_drugs, /datum/reagent/toxin/plasma, /datum/reagent/consumable/frostoil, @@ -110,38 +133,42 @@ /datum/reagent/toxin/histamine, /datum/reagent/medicine/morphine ) - //SKYRAT EDIT ADDITION END - /// Starting purity of the created reagents - var/base_reagent_purity = 1 - - var/list/recording_recipe - - var/list/saved_recipes = list() - //SKYRAT EDIT BEGIN - CHEMISTRY QOL - var/list/transferAmounts = list() - var/customTransferAmount - //SKYRAT EDIT END + //SKYRAT EDIT CHANGE END /obj/machinery/chem_dispenser/Initialize(mapload) . = ..() - dispensable_reagents = sort_list(dispensable_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) - if(emagged_reagents) - emagged_reagents = sort_list(emagged_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) + if(dispensable_reagents != null && !dispensable_reagents.len) + dispensable_reagents = default_dispensable_reagents + if(dispensable_reagents) + dispensable_reagents = sort_list(dispensable_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) + + if(upgrade_reagents != null && !upgrade_reagents.len) + upgrade_reagents = default_upgrade_reagents if(upgrade_reagents) upgrade_reagents = sort_list(upgrade_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) - //SKYRAT EDIT ADDITION BEGIN - Skyrat-SS13/Skyrat-tg#1931 - if(upgrade_reagents2) - upgrade_reagents2 = sort_list(upgrade_reagents2, GLOBAL_PROC_REF(cmp_reagents_asc)) - if(upgrade_reagents3) - upgrade_reagents3 = sort_list(upgrade_reagents3, GLOBAL_PROC_REF(cmp_reagents_asc)) + //SKYRAT EDIT ADDITION BEGIN + if(upgrade2_reagents != null && !upgrade2_reagents.len) + upgrade2_reagents = default_upgrade2_reagents + if(upgrade2_reagents) + upgrade2_reagents = sort_list(upgrade2_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) + if(upgrade3_reagents != null && !upgrade3_reagents.len) + upgrade3_reagents = default_upgrade3_reagents + if(upgrade3_reagents) + upgrade3_reagents = sort_list(upgrade3_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) //SKYRAT EDIT ADDITION END + + if(emagged_reagents != null && !emagged_reagents.len) + emagged_reagents = default_emagged_reagents + if(emagged_reagents) + emagged_reagents = sort_list(emagged_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) + if(is_operational) begin_processing() update_appearance() /obj/machinery/chem_dispenser/Destroy() + cell = null QDEL_NULL(beaker) - QDEL_NULL(cell) return ..() /obj/machinery/chem_dispenser/examine(mob/user) @@ -151,17 +178,15 @@ if(in_range(user, src) || isobserver(user)) . += "The status display reads:\n\ Recharging [recharge_amount] power units per interval.\n\ - Power efficiency increased by [round((powerefficiency*1000)-100, 1)]%." + Power efficiency increased by [round((powerefficiency * 1000) -100, 1)]%.
" . += span_notice("Use RMB to eject a stored beaker.") - /obj/machinery/chem_dispenser/on_set_is_operational(old_value) if(old_value) //Turned off end_processing() else //Turned on begin_processing() - /obj/machinery/chem_dispenser/process(seconds_per_tick) if (recharge_counter >= 8) var/usedpower = cell.give(recharge_amount) @@ -194,7 +219,6 @@ beaker_overlay = display_beaker() . += beaker_overlay - /obj/machinery/chem_dispenser/emag_act(mob/user, obj/item/card/emag/emag_card) if(obj_flags & EMAGGED) balloon_alert(user, "already emagged!") @@ -205,12 +229,10 @@ return TRUE /obj/machinery/chem_dispenser/ex_act(severity, target) - if(severity <= EXPLODE_LIGHT) - return FALSE - return ..() + return severity <= EXPLODE_LIGHT ? FALSE : ..() /obj/machinery/chem_dispenser/contents_explosion(severity, target) - ..() + . = ..() if(!beaker) return @@ -232,45 +254,25 @@ ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "ChemDispenser", name) + ui.open() - var/is_hallucinating = FALSE - if(isliving(user)) - var/mob/living/living_user = user - is_hallucinating = !!living_user.has_status_effect(/datum/status_effect/hallucination) - - if(is_hallucinating) - ui.set_autoupdate(FALSE) //to not ruin the immersion by constantly changing the fake chemicals + var/is_hallucinating = FALSE + if(isliving(user)) + var/mob/living/living_user = user + is_hallucinating = !!living_user.has_status_effect(/datum/status_effect/hallucination) + ui.set_autoupdate(!is_hallucinating) //to not ruin the immersion by constantly changing the fake chemicals - ui.open() +/obj/machinery/chem_dispenser/ui_static_data(mob/user) + . = ..() + .["showpH"] = show_ph /obj/machinery/chem_dispenser/ui_data(mob/user) - var/data = list() - data["amount"] = amount - data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI. - data["maxEnergy"] = cell.maxcharge * powerefficiency - data["isBeakerLoaded"] = beaker ? 1 : 0 - data["showpH"] = show_ph - - var/beakerContents[0] - var/beakerCurrentVolume = 0 - if(beaker && beaker.reagents && beaker.reagents.reagent_list.len) - for(var/datum/reagent/R in beaker.reagents.reagent_list) - beakerContents.Add(list(list("name" = R.name, "volume" = round(R.volume, 0.01), "pH" = R.ph, "purity" = R.purity))) // list in a list because Byond merges the first list... - beakerCurrentVolume += R.volume - data["beakerContents"] = beakerContents - - if (beaker) - data["beakerCurrentVolume"] = round(beakerCurrentVolume, 0.01) - data["beakerMaxVolume"] = beaker.volume - data["beakerTransferAmounts"] = beaker.possible_transfer_amounts - data["beakerCurrentpH"] = round(beaker.reagents.ph, 0.01) - else - data["beakerCurrentVolume"] = null - data["beakerMaxVolume"] = null - data["beakerTransferAmounts"] = null - data["beakerCurrentpH"] = null + . = list() + .["amount"] = amount + .["energy"] = cell.charge ? cell.charge * powerefficiency : 0 //To prevent NaN in the UI. + .["maxEnergy"] = cell.maxcharge * powerefficiency - var/chemicals[0] + var/list/chemicals = list() var/is_hallucinating = FALSE if(isliving(user)) var/mob/living/living_user = user @@ -282,23 +284,37 @@ var/chemname = temp.name if(is_hallucinating && prob(5)) chemname = "[pick_list_replacements("hallucination.json", "chemicals")]" - chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name), "pH" = temp.ph, "pHCol" = convert_ph_to_readable_color(temp.ph)))) - data["chemicals"] = chemicals - data["recipes"] = saved_recipes + chemicals += list(list("title" = chemname, "id" = temp.name, "pH" = temp.ph, "pHCol" = convert_ph_to_readable_color(temp.ph))) + .["chemicals"] = chemicals + .["recipes"] = saved_recipes - data["recordingRecipe"] = recording_recipe - data["recipeReagents"] = list() + .["recordingRecipe"] = recording_recipe + .["recipeReagents"] = list() if(beaker?.reagents.ui_reaction_id) var/datum/chemical_reaction/reaction = get_chemical_reaction(beaker.reagents.ui_reaction_id) for(var/_reagent in reaction.required_reagents) var/datum/reagent/reagent = find_reagent_object_from_type(_reagent) - data["recipeReagents"] += ckey(reagent.name) - return data - -/obj/machinery/chem_dispenser/ui_act(action, params) + .["recipeReagents"] += reagent.name + + var/list/beaker_data = null + if(!QDELETED(beaker)) + beaker_data = list() + beaker_data["maxVolume"] = beaker.volume + beaker_data["transferAmounts"] = beaker.possible_transfer_amounts + beaker_data["pH"] = round(beaker.reagents.ph, 0.01) + beaker_data["currentVolume"] = round(beaker.reagents.total_volume, 0.01) + var/list/beakerContents = list() + if(beaker && beaker.reagents && beaker.reagents.reagent_list.len) + for(var/datum/reagent/reagent in beaker.reagents.reagent_list) + beakerContents += list(list("name" = reagent.name, "volume" = round(reagent.volume, 0.01))) // list in a list because Byond merges the first list... + beaker_data["contents"] = beakerContents + .["beaker"] = beaker_data + +/obj/machinery/chem_dispenser/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return + switch(action) if("amount") if(!is_operational || QDELETED(beaker)) @@ -307,7 +323,8 @@ if(target in beaker.possible_transfer_amounts) amount = target work_animation() - . = TRUE + return TRUE + if("dispense") if(!is_operational || QDELETED(cell)) return @@ -318,7 +335,7 @@ var/datum/reagents/holder = beaker.reagents var/to_dispense = max(0, min(amount, holder.maximum_volume - holder.total_volume)) - if(!cell?.use(to_dispense / powerefficiency)) + if(!cell.use(to_dispense / powerefficiency)) say("Not enough energy to complete operation!") return holder.add_reagent(reagent, to_dispense, reagtemp = dispensed_temperature, added_purity = base_reagent_purity) @@ -326,7 +343,8 @@ work_animation() else recording_recipe[reagent_name] += amount - . = TRUE + return TRUE + if("remove") if(!is_operational || recording_recipe) return @@ -334,10 +352,12 @@ if(beaker && (amount in beaker.possible_transfer_amounts)) beaker.reagents.remove_all(amount) work_animation() - . = TRUE + return TRUE + if("eject") - replace_beaker(usr) - . = TRUE + replace_beaker(ui.user) + return TRUE + if("dispense_recipe") if(!is_operational || QDELETED(cell)) return @@ -346,7 +366,7 @@ if(!LAZYLEN(chemicals_to_dispense)) return for(var/key in chemicals_to_dispense) - var/reagent = GLOB.name2reagent[translate_legacy_chem_id(key)] + var/reagent = GLOB.name2reagent[key] var/dispense_amount = chemicals_to_dispense[key] if(!dispensable_reagents.Find(reagent)) return @@ -358,50 +378,49 @@ var/to_dispense = max(0, min(dispense_amount, holder.maximum_volume - holder.total_volume)) if(!to_dispense) continue - if(!cell?.use(to_dispense / powerefficiency)) + if(!cell.use(to_dispense / powerefficiency)) say("Not enough energy to complete operation!") return holder.add_reagent(reagent, to_dispense, reagtemp = dispensed_temperature, added_purity = base_reagent_purity) work_animation() else recording_recipe[key] += dispense_amount - . = TRUE + return TRUE + if("clear_recipes") - if(!is_operational) - return - var/yesno = tgui_alert(usr, "Clear all recipes?",, list("Yes","No")) - if(yesno == "Yes") + if(is_operational && tgui_alert(ui.user, "Clear all recipes?", "Clear?", list("Yes", "No")) == "Yes") saved_recipes = list() - . = TRUE + return TRUE + if("record_recipe") - if(!is_operational) - return - recording_recipe = list() - . = TRUE + if(is_operational) + recording_recipe = list() + return TRUE + if("save_recording") if(!is_operational) return - var/name = tgui_input_text(usr, "What do you want to name this recipe?", "Recipe Name", MAX_NAME_LEN) - if(!usr.can_perform_action(src, ALLOW_SILICON_REACH)) + var/name = tgui_input_text(ui.user, "What do you want to name this recipe?", "Recipe Name", MAX_NAME_LEN) + if(!ui.user.can_perform_action(src, ALLOW_SILICON_REACH)) return - if(saved_recipes[name] && tgui_alert(usr, "\"[name]\" already exists, do you want to overwrite it?",, list("Yes", "No")) == "No") + if(saved_recipes[name] && tgui_alert(ui.user, "\"[name]\" already exists, do you want to overwrite it?",, list("Yes", "No")) == "No") return if(name && recording_recipe) for(var/reagent in recording_recipe) - var/reagent_id = GLOB.name2reagent[translate_legacy_chem_id(reagent)] + var/reagent_id = GLOB.name2reagent[reagent] if(!dispensable_reagents.Find(reagent_id)) visible_message(span_warning("[src] buzzes."), span_hear("You hear a faint buzz.")) - to_chat(usr, span_warning("[src] cannot find [reagent]!")) + to_chat(ui.user, span_warning("[src] cannot find [reagent]!")) playsound(src, 'sound/machines/buzz-two.ogg', 50, TRUE) return saved_recipes[name] = recording_recipe recording_recipe = null - . = TRUE + return TRUE + if("cancel_recording") - if(!is_operational) - return - recording_recipe = null - . = TRUE + if(is_operational) + recording_recipe = null + return TRUE //SKYRAT EDIT ADDITION BEGIN - CHEMISTRY QOL if("custom_amount") if(!beaker) @@ -411,22 +430,30 @@ transferAmounts -= customTransferAmount customTransferAmount = clamp(input(usr, "Please enter your desired transfer amount.", "Transfer amount", 0) as num|null, 0, beaker.volume) transferAmounts += customTransferAmount + return TRUE //SKYRAT EDIT ADDITION END + if("reaction_lookup") if(beaker) - beaker.reagents.ui_interact(usr) + beaker.reagents.ui_interact(ui.user) /obj/machinery/chem_dispenser/wrench_act(mob/living/user, obj/item/tool) . = ..() - default_unfasten_wrench(user, tool) - return TOOL_ACT_TOOLTYPE_SUCCESS + if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) + return TOOL_ACT_TOOLTYPE_SUCCESS -/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/living/user, params) - if(default_deconstruction_screwdriver(user, icon_state, icon_state, I)) +/obj/machinery/chem_dispenser/screwdriver_act(mob/living/user, obj/item/tool) + . = ..() + if(default_deconstruction_screwdriver(user, icon_state, icon_state, tool)) update_appearance() - return - if(default_deconstruction_crowbar(I)) - return + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/machinery/chem_dispenser/crowbar_act(mob/living/user, obj/item/tool) + . = ..() + if(default_deconstruction_crowbar(tool)) + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/living/user, params) if(is_reagent_container(I) && !(I.item_flags & ABSTRACT) && I.is_open_container()) var/obj/item/reagent_containers/B = I //SKYRAT EDIT BEGIN - CHEMISTRY QOL @@ -496,14 +523,14 @@ dispensable_reagents -= upgrade_reagents if (servo.tier > 2) - dispensable_reagents |= upgrade_reagents2 + dispensable_reagents |= upgrade2_reagents else - dispensable_reagents -= upgrade_reagents2 + dispensable_reagents -= upgrade2_reagents if (servo.tier > 3) - dispensable_reagents |= upgrade_reagents3 + dispensable_reagents |= upgrade3_reagents else - dispensable_reagents -= upgrade_reagents3 + dispensable_reagents -= upgrade3_reagents //SKYRAT EDIT END parts_rating += servo.tier powerefficiency = round(newpowereff, 0.01) @@ -559,7 +586,8 @@ nopower_state = null pass_flags = PASSTABLE show_ph = FALSE - dispensable_reagents = list( + /// The default list of reagents dispensable by the soda dispenser + var/static/list/drinks_dispensable_reagents = list( /datum/reagent/consumable/coffee, /datum/reagent/consumable/space_cola, /datum/reagent/consumable/cream, @@ -586,24 +614,26 @@ /datum/reagent/consumable/tonic, /datum/reagent/water, ) - //SKYRAT EDIT ADDITION BEGIN - Skyrat-SS13/Skyrat-tg#2429 - upgrade_reagents = list( + //SKYRAT EDIT ADDITION BEGIN + var/static/list/drink_upgrade_reagents = list( /datum/reagent/consumable/applejuice, /datum/reagent/consumable/pumpkinjuice, /datum/reagent/consumable/vanilla ) - upgrade_reagents2 = list( + var/static/list/drink_upgrade2_reagents = list( /datum/reagent/consumable/banana, /datum/reagent/consumable/berryjuice, /datum/reagent/consumable/blumpkinjuice ) - upgrade_reagents3 = list( + var/static/list/drink_upgrade3_reagents = list( /datum/reagent/consumable/watermelonjuice, /datum/reagent/consumable/peachjuice, /datum/reagent/consumable/sol_dry ) //SKYRAT EDIT ADDITION END - emagged_reagents = list( + upgrade_reagents = null + /// The default list of emagged reagents dispensable by the soda dispenser + var/static/list/drink_emagged_reagents = list( /datum/reagent/consumable/ethanol/thirteenloko, /datum/reagent/consumable/ethanol/whiskey_cola, /datum/reagent/toxin/mindbreaker, @@ -612,6 +642,24 @@ base_reagent_purity = 0.5 /obj/machinery/chem_dispenser/drinks/Initialize(mapload) + if(dispensable_reagents != null && !dispensable_reagents.len) + dispensable_reagents = drinks_dispensable_reagents + if(emagged_reagents != null && !emagged_reagents.len) + emagged_reagents = drink_emagged_reagents + //SKYRAT EDIT ADDITION BEGIN + if(upgrade_reagents != null && !upgrade_reagents.len) + upgrade_reagents = drink_upgrade_reagents + if(upgrade_reagents) + upgrade_reagents = sort_list(upgrade_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) + if(upgrade2_reagents != null && !upgrade2_reagents.len) + upgrade2_reagents = drink_upgrade2_reagents + if(upgrade2_reagents) + upgrade2_reagents = sort_list(upgrade2_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) + if(upgrade3_reagents != null && !upgrade3_reagents.len) + upgrade3_reagents = drink_upgrade3_reagents + if(upgrade3_reagents) + upgrade3_reagents = sort_list(upgrade3_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) + //SKYRAT EDIT ADDITION END . = ..() AddComponent(/datum/component/simple_rotation) @@ -656,7 +704,8 @@ base_icon_state = "booze_dispenser" dispensed_temperature = WATER_MATTERSTATE_CHANGE_TEMP circuit = /obj/item/circuitboard/machine/chem_dispenser/drinks/beer - dispensable_reagents = list( + /// The default list of reagents dispensable by the beer dispenser + var/static/list/beer_dispensable_reagents = list( /datum/reagent/consumable/ethanol/absinthe, /datum/reagent/consumable/ethanol/ale, /datum/reagent/consumable/ethanol/applejack, @@ -685,9 +734,10 @@ /datum/reagent/consumable/ethanol/yuyake, ) upgrade_reagents = null - upgrade_reagents2 = null //SKYRAT EDIT - upgrade_reagents3 = null //SKYRAT EDIT - emagged_reagents = list( + upgrade2_reagents = null //SKYRAT EDIT + upgrade3_reagents = null //SKYRAT EDIT + /// The default list of emagged reagents dispensable by the beer dispenser + var/static/list/beer_emagged_reagents = list( /datum/reagent/consumable/ethanol, /datum/reagent/iron, /datum/reagent/consumable/mintextract, @@ -695,6 +745,11 @@ /datum/reagent/consumable/ethanol/fernet ) +/obj/machinery/chem_dispenser/drinks/beer/Initialize(mapload) + dispensable_reagents = beer_dispensable_reagents + emagged_reagents = beer_emagged_reagents + . = ..() + /obj/machinery/chem_dispenser/drinks/beer/fullupgrade //fully ugpraded stock parts, emagged desc = "Contains a large reservoir of the good stuff. This model has had its safeties shorted out." obj_flags = CAN_BE_HIT | EMAGGED @@ -708,19 +763,25 @@ /obj/machinery/chem_dispenser/mutagen name = "mutagen dispenser" desc = "Creates and dispenses mutagen." - dispensable_reagents = list(/datum/reagent/toxin/mutagen) + /// The default list of reagents dispensable by mutagen chem dispenser + var/static/list/mutagen_dispensable_reagents = list(/datum/reagent/toxin/mutagen) upgrade_reagents = null - emagged_reagents = list(/datum/reagent/toxin/plasma) + /// The default list of emagged reagents dispensable by mutagen chem dispenser + var/static/list/mutagen_emagged_reagents = list(/datum/reagent/toxin/plasma) +/obj/machinery/chem_dispenser/mutagen/Initialize(mapload) + dispensable_reagents = mutagen_dispensable_reagents + emagged_reagents = mutagen_emagged_reagents + . = ..() /obj/machinery/chem_dispenser/mutagensaltpeter name = "botanical chemical dispenser" desc = "Creates and dispenses chemicals useful for botany." flags_1 = NODECONSTRUCT_1 - circuit = /obj/item/circuitboard/machine/chem_dispenser/mutagensaltpeter - dispensable_reagents = list( + /// The default list of dispensable reagents available in the mutagensaltpeter chem dispenser + var/static/list/mutagensaltpeter_dispensable_reagents = list( /datum/reagent/toxin/mutagen, /datum/reagent/saltpetre, /datum/reagent/plantnutriment/eznutriment, @@ -736,6 +797,10 @@ /datum/reagent/diethylamine) upgrade_reagents = null +/obj/machinery/chem_dispenser/mutagensaltpeter/Initialize(mapload) + dispensable_reagents = mutagensaltpeter_dispensable_reagents + . = ..() + /obj/machinery/chem_dispenser/fullupgrade //fully ugpraded stock parts, emagged desc = "Creates and dispenses chemicals. This model has had its safeties shorted out." obj_flags = CAN_BE_HIT | EMAGGED @@ -757,7 +822,9 @@ working_state = null nopower_state = null use_power = NO_POWER_USE - dispensable_reagents = list( + + /// The default list of dispensable reagents available in the abductor chem dispenser + var/static/list/abductor_dispensable_reagents = list( /datum/reagent/aluminium, /datum/reagent/bromine, /datum/reagent/carbon, @@ -799,3 +866,7 @@ /datum/reagent/consumable/liquidelectricity/enriched, /datum/reagent/medicine/c2/synthflesh ) + +/obj/machinery/chem_dispenser/abductor/Initialize(mapload) + dispensable_reagents = abductor_dispensable_reagents + . = ..() diff --git a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm index b944fdbee80ce3..69f31b0070075a 100644 --- a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm @@ -45,7 +45,13 @@ . = UPDATE_MOB_HEALTH if(good_kind_of_healing && !reaping && SPT_PROB(0.00005, seconds_per_tick)) //janken with the grim reaper! - notify_ghosts("[affected_mob] has entered a game of rock-paper-scissors with death!", source = affected_mob, action = NOTIFY_ORBIT, header = "Who Will Win?") + notify_ghosts( + "[affected_mob] has entered a game of rock-paper-scissors with death!", + source = affected_mob, + action = NOTIFY_ORBIT, + header = "Who Will Win?", + notify_flags = NOTIFY_CATEGORY_DEFAULT, + ) reaping = TRUE if(affected_mob.apply_status_effect(/datum/status_effect/necropolis_curse, CURSE_BLINDING)) helbent = TRUE @@ -496,13 +502,15 @@ show_message = 0 if(!(methods & (PATCH|TOUCH|VAPOR))) return - var/harmies = min(carbies.getBruteLoss(), carbies.adjustBruteLoss(-1.25 * reac_volume, updating_health = FALSE, required_bodytype = affected_bodytype)*-1) - var/burnies = min(carbies.getFireLoss(), carbies.adjustFireLoss(-1.25 * reac_volume, updating_health = FALSE, required_bodytype = affected_bodytype)*-1) + var/current_bruteloss = carbies.getBruteLoss() // because this will be changed after calling adjustBruteLoss() + var/current_fireloss = carbies.getFireLoss() // because this will be changed after calling adjustFireLoss() + var/harmies = clamp(carbies.adjustBruteLoss(-1.25 * reac_volume, updating_health = FALSE, required_bodytype = affected_bodytype), 0, current_bruteloss) + var/burnies = clamp(carbies.adjustFireLoss(-1.25 * reac_volume, updating_health = FALSE, required_bodytype = affected_bodytype), 0, current_fireloss) for(var/i in carbies.all_wounds) var/datum/wound/iter_wound = i iter_wound.on_synthflesh(reac_volume) var/need_mob_update = harmies + burnies - need_mob_update += carbies.adjustToxLoss((harmies+burnies)*(0.5 + (0.25*(1-creation_purity))), updating_health = FALSE, required_biotype = affected_biotype) //0.5 - 0.75 + need_mob_update = carbies.adjustToxLoss((harmies + burnies)*(0.5 + (0.25*(1-creation_purity))), updating_health = FALSE, required_biotype = affected_biotype) || need_mob_update //0.5 - 0.75 if(need_mob_update) carbies.updatehealth() diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index d49976ac10eed2..05bc622faa70f3 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -542,9 +542,9 @@ reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS /datum/chemical_reaction/reagent_explosion/teslium_lightning/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/T1 = created_volume * 8e3 //100 units : Zap 3 times, with powers 8e5/2e6/4.8e6. Tesla revolvers have a power of 10000 for comparison. - var/T2 = created_volume * 2e4 - var/T3 = created_volume * 4.8e4 + var/T1 = created_volume * 20 //100 units : Zap 3 times, with powers 8e5/2e6/4.8e6. Tesla revolvers have a power of 10000 for comparison. + var/T2 = created_volume * 50 + var/T3 = created_volume * 120 var/added_delay = 0.5 SECONDS if(created_volume >= 75) addtimer(CALLBACK(src, PROC_REF(zappy_zappy), holder, T1), added_delay) @@ -557,10 +557,11 @@ addtimer(CALLBACK(src, PROC_REF(default_explode), holder, created_volume, modifier, strengthdiv), added_delay) /datum/chemical_reaction/reagent_explosion/teslium_lightning/proc/zappy_zappy(datum/reagents/holder, power) - if(QDELETED(holder.my_atom)) + var/atom/holder_atom = holder.my_atom + if(QDELETED(holder_atom)) return - tesla_zap(holder.my_atom, 7, power, zap_flags) - playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, TRUE) + tesla_zap(source = holder_atom, zap_range = 7, power = power, cutoff = 1e3, zap_flags = zap_flags) + playsound(holder_atom, 'sound/machines/defib_zap.ogg', 50, TRUE) /datum/chemical_reaction/reagent_explosion/teslium_lightning/heat required_temp = 474 diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 5caec9de68168c..4e05310f056569 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -125,7 +125,7 @@ return var/trans = reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user) - to_chat(user, span_notice("You transfer [round(trans, 0.01)] unit\s of the solution to [target].")) + to_chat(user, span_notice("You transfer [trans] unit\s of the solution to [target].")) else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us. if(!target.reagents.total_volume) @@ -137,7 +137,7 @@ return var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user) - to_chat(user, span_notice("You fill [src] with [round(trans, 0.01)] unit\s of the contents of [target].")) + to_chat(user, span_notice("You fill [src] with [trans] unit\s of the contents of [target].")) target.update_appearance() @@ -158,7 +158,7 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user) - to_chat(user, span_notice("You fill [src] with [round(trans, 0.01)] unit\s of the contents of [target].")) + to_chat(user, span_notice("You fill [src] with [trans] unit\s of the contents of [target].")) target.update_appearance() return SECONDARY_ATTACK_CONTINUE_CHAIN @@ -536,6 +536,11 @@ to_chat(user, span_warning("You can't grind this!")) /obj/item/reagent_containers/cup/mortar/proc/grind_item(obj/item/item, mob/living/carbon/human/user) + if(item.flags_1 & HOLOGRAM_1) + to_chat(user, span_notice("You try to grind [item], but it fades away!")) + qdel(item) + return + if(!item.grind(reagents, user)) if(isstack(item)) to_chat(usr, span_notice("[src] attempts to grind as many pieces of [item] as possible.")) @@ -547,6 +552,11 @@ QDEL_NULL(item) /obj/item/reagent_containers/cup/mortar/proc/juice_item(obj/item/item, mob/living/carbon/human/user) + if(item.flags_1 & HOLOGRAM_1) + to_chat(user, span_notice("You try to juice [item], but it fades away!")) + qdel(item) + return + if(!item.juice(reagents, user)) to_chat(user, span_notice("You fail to juice [item].")) return diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm index ac8d0af0d1c6b9..beb6f3e6314cde 100644 --- a/code/modules/reagents/reagent_containers/dropper.dm +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -46,7 +46,7 @@ target.visible_message(span_danger("[user] tries to squirt something into [target]'s eyes, but fails!"), \ span_userdanger("[user] tries to squirt something into your eyes, but fails!")) - to_chat(user, span_notice("You transfer [round(trans, 0.01)] unit\s of the solution.")) + to_chat(user, span_notice("You transfer [trans] unit\s of the solution.")) update_appearance() return else if(isalien(target)) //hiss-hiss has no eyes! @@ -66,7 +66,7 @@ log_combat(user, M, "squirted", R) trans = src.reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user) - to_chat(user, span_notice("You transfer [round(trans, 0.01)] unit\s of the solution.")) + to_chat(user, span_notice("You transfer [trans] unit\s of the solution.")) update_appearance() target.update_appearance() @@ -82,7 +82,7 @@ var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user) - to_chat(user, span_notice("You fill [src] with [round(trans, 0.01)] unit\s of the solution.")) + to_chat(user, span_notice("You fill [src] with [trans] unit\s of the solution.")) update_appearance() target.update_appearance() diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 28c26c5d3568a6..a554dca6a84ce8 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -50,18 +50,23 @@ to_chat(user, span_warning("Not enough left!")) return - spray(target, user) + if(proximity_flag && (target.density || ismob(target))) + // If we're spraying an adjacent mob or a dense object, we start the spray on ITS tile rather than OURs + // This is so we can use a spray bottle to clean stuff like windows without getting blocked by passflags + spray(target, user, get_turf(target)) + else + spray(target, user) - playsound(src.loc, spray_sound, 50, TRUE, -6) + playsound(src, spray_sound, 50, TRUE, -6) user.changeNext_move(CLICK_CD_RANGE*2) user.newtonian_move(get_dir(target, user)) return /// Handles creating a chem puff that travels towards the target atom, exposing reagents to everything it hits on the way. -/obj/item/reagent_containers/spray/proc/spray(atom/target, mob/user) +/obj/item/reagent_containers/spray/proc/spray(atom/target, mob/user, turf/start_turf = get_turf(src)) var/range = max(min(current_range, get_dist(src, target)), 1) - var/obj/effect/decal/chempuff/reagent_puff = new /obj/effect/decal/chempuff(get_turf(src)) + var/obj/effect/decal/chempuff/reagent_puff = new(start_turf) reagent_puff.create_reagents(amount_per_transfer_from_this) var/puff_reagent_left = range //how many turf, mob or dense objet we can react with before we consider the chem puff consumed @@ -74,9 +79,7 @@ var/wait_step = max(round(2+3/range), 2) var/puff_reagent_string = reagent_puff.reagents.get_reagent_log_string() - var/turf/src_turf = get_turf(src) - - log_combat(user, src_turf, "fired a puff of reagents from", src, addition="with a range of \[[range]\], containing [puff_reagent_string].") + log_combat(user, start_turf, "fired a puff of reagents from", src, addition="with a range of \[[range]\], containing [puff_reagent_string].") user.log_message("fired a puff of reagents from \a [src] with a range of \[[range]\] and containing [puff_reagent_string].", LOG_ATTACK) // do_spray includes a series of step_towards and sleeps. As a result, it will handle deletion of the chempuff. @@ -84,11 +87,20 @@ /// Handles exposing atoms to the reagents contained in a spray's chempuff. Deletes the chempuff when it's completed. /obj/item/reagent_containers/spray/proc/do_spray(atom/target, wait_step, obj/effect/decal/chempuff/reagent_puff, range, puff_reagent_left, mob/user) - var/datum/move_loop/our_loop = SSmove_manager.move_towards_legacy(reagent_puff, target, wait_step, timeout = range * wait_step, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) reagent_puff.user = user reagent_puff.sprayer = src reagent_puff.lifetime = puff_reagent_left reagent_puff.stream = stream_mode + + var/turf/target_turf = get_turf(target) + var/turf/start_turf = get_turf(reagent_puff) + if(target_turf == start_turf) // Don't need to bother movelooping if we don't move + reagent_puff.setDir(user.dir) + reagent_puff.spray_down_turf(target_turf) + reagent_puff.end_life() + return + + var/datum/move_loop/our_loop = SSmove_manager.move_towards_legacy(reagent_puff, target, wait_step, timeout = range * wait_step, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) reagent_puff.RegisterSignal(our_loop, COMSIG_QDELETING, TYPE_PROC_REF(/obj/effect/decal/chempuff, loop_ended)) reagent_puff.RegisterSignal(our_loop, COMSIG_MOVELOOP_POSTPROCESS, TYPE_PROC_REF(/obj/effect/decal/chempuff, check_move)) @@ -181,7 +193,7 @@ if(do_after(user, 3 SECONDS, user)) if(reagents.total_volume >= amount_per_transfer_from_this)//if not empty user.visible_message(span_suicide("[user] pulls the trigger!")) - spray(user) + spray(user, user) return BRUTELOSS else user.visible_message(span_suicide("[user] pulls the trigger...but \the [src] is empty!")) diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm index 3135fddeace8da..8b96c2105110fd 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -168,7 +168,7 @@ eth_stomach.adjust_charge(60) did_we_charge = TRUE - //if we're not targetting a robot part we stop early + //if we're not targeting a robot part we stop early var/obj/item/bodypart/bodypart = blessed.get_bodypart(chap.zone_selected) if(IS_ORGANIC_LIMB(bodypart)) if(!did_we_charge) diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm index c495bdc9e47b5c..098cac6a3894b8 100644 --- a/code/modules/research/designs/mecha_designs.dm +++ b/code/modules/research/designs/mecha_designs.dm @@ -229,6 +229,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -246,6 +247,7 @@ construction_time = 20 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -263,6 +265,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -280,6 +283,7 @@ construction_time = 20 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -297,6 +301,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -314,6 +319,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -331,6 +337,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -348,6 +355,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -365,6 +373,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -382,6 +391,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -399,6 +409,7 @@ construction_time = 20 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -416,6 +427,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -433,6 +445,7 @@ construction_time = 20 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -450,6 +463,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -467,6 +481,7 @@ construction_time = 20 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_WEAPONS, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -486,6 +501,7 @@ RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MISC, RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_ODYSSEUS + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_HONK + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -506,6 +522,7 @@ RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MISC, RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_ODYSSEUS + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_HONK + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -526,6 +543,7 @@ RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MISC, RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_ODYSSEUS + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_HONK + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -566,6 +584,7 @@ RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MISC, RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_ODYSSEUS + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_HONK + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -586,6 +605,7 @@ RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MODULES, RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_ODYSSEUS + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_HONK + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -606,6 +626,7 @@ RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MODULES, RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_ODYSSEUS + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_HONK + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -626,6 +647,7 @@ RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MODULES, RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_ODYSSEUS + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_HONK + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -660,6 +682,7 @@ category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MINING, RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_HONK + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -679,6 +702,7 @@ category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MINING, RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_HONK + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -697,6 +721,7 @@ construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MINING, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, @@ -713,6 +738,7 @@ construction_time = 20 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MINING, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_GYGAX + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_DURAND + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, RND_CATEGORY_MECHFAB_PHAZON + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 9a79ec0db75364..f892426a41e1a5 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -778,12 +778,24 @@ materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT*5,/datum/material/plasma=SHEET_MATERIAL_AMOUNT*5) construction_time = 100 category = list( - RND_CATEGORY_MECHFAB_EQUIPMENT, - RND_CATEGORY_MECHFAB_RIPLEY + RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MODULES, + RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + ) + +/datum/design/paddyupgrade + name = "Ripley MK-I to Paddy Conversion Kit" + id = "paddyupgrade" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/mecha_equipment/ripleyupgrade/paddy + materials = list( + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 10, + /datum/material/glass = SHEET_MATERIAL_AMOUNT * 5, + /datum/material/titanium = SHEET_MATERIAL_AMOUNT *5, ) + construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MODULES, - RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_CHASSIS, ) /datum/design/mech_hydraulic_clamp @@ -794,12 +806,20 @@ materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT*5) construction_time = 100 category = list( - RND_CATEGORY_MECHFAB_EQUIPMENT, - RND_CATEGORY_MECHFAB_RIPLEY + RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MISC, + RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, ) + +/datum/design/mech_hydraulic_claw + name = "Hydraulic Claw" + id = "mech_hydraulic_claw" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw + materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT*5) + construction_time = 100 category = list( RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MISC, - RND_CATEGORY_MECHFAB_RIPLEY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, + RND_CATEGORY_MECHFAB_PADDY + RND_SUBCATEGORY_MECHFAB_SUPPORTED_EQUIPMENT, ) /datum/design/mech_drill diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index 285878e7f2647f..150c69bc21fd2a 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -359,6 +359,28 @@ ) departmental_flags = DEPARTMENT_BITFLAG_MEDICAL +/datum/design/penlight + name = "Penlight" + id = "penlight" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron =SMALL_MATERIAL_AMOUNT*5, /datum/material/glass =SMALL_MATERIAL_AMOUNT*0.5) + build_path = /obj/item/flashlight/pen + category = list( + RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_MEDICAL + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL + +/datum/design/penlight_paramedic + name = "Paramedic Penlight" + id = "penlight_paramedic" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron =SMALL_MATERIAL_AMOUNT*5, /datum/material/glass =SMALL_MATERIAL_AMOUNT*1) + build_path = /obj/item/flashlight/pen/paramedic + category = list( + RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_MEDICAL + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL + ///////////////////////////////////////// //////////Cybernetic Implants//////////// ///////////////////////////////////////// diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index fcbf39ec794fff..a99c5e24217c98 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -819,6 +819,17 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SECURITY +/datum/design/sec_pen + name = "Security Pen" + id = "sec_pen" + build_type = PROTOLATHE | AUTOLATHE + materials = list(/datum/material/iron =SMALL_MATERIAL_AMOUNT) + build_path = /obj/item/pen/red/security + category = list( + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_SECURITY + ) + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + /datum/design/plumbing_rcd name = "Plumbing Constructor" id = "plumbing_rcd" diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index 6a090693ffd37a..23c3c45507a07c 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -26,6 +26,7 @@ density = TRUE use_power = IDLE_POWER_USE circuit = /obj/item/circuitboard/machine/experimentor + interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON|INTERACT_MACHINE_SET_MACHINE var/recentlyExperimented = 0 /// Weakref to the first ian we can find at init var/datum/weakref/tracked_ian_ref diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index 4668753f0483fd..b71bc1d025f3ae 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -107,10 +107,7 @@ ) /obj/machinery/rnd/production/ui_interact(mob/user, datum/tgui/ui) - user.set_machine(src) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) ui = new(user, src, "Fabricator") ui.open() diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 4f1e7dd0e2a2c8..e70fc1974aa05e 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -98,6 +98,7 @@ "sec_dart", "sec_Islug", "sec_rshot", + "sec_pen", "servingtray", "shaker", "shot_glass", @@ -299,6 +300,7 @@ "plumbing_rcd_service", "plumbing_rcd_sci", "portable_chem_mixer", + "penlight", "retractor", "scalpel", "stethoscope", @@ -417,6 +419,7 @@ "medigel", "medipen_refiller", "pandemic", + "penlight_paramedic", "soda_dispenser", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) @@ -1875,6 +1878,18 @@ ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) +/datum/techweb_node/paddy + id = "mech_paddy" + display_name = "EXOSUIT: APLU \"Paddy\"" + description = "Paddy exosuit designs" + prereq_ids = list("adv_mecha", "adv_mecha_armor") + design_ids = list( + "paddyupgrade", + "mech_hydraulic_claw" + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) + discount_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier3_mechbay = 5000) + /datum/techweb_node/gygax id = "mech_gygax" display_name = "EXOSUIT: Gygax" diff --git a/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm b/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm index 0152b343c45dfd..5e9045e751f984 100644 --- a/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm +++ b/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm @@ -684,30 +684,6 @@ virus_suspectibility = 0 resulting_atoms = list(/mob/living/basic/butterfly = 3) -/datum/micro_organism/cell_line/leaper - desc = "atypical amphibian cells" - required_reagents = list( - /datum/reagent/consumable/nutriment/protein, - /datum/reagent/ants, - /datum/reagent/consumable/eggyolk, - /datum/reagent/medicine/c2/synthflesh) - - supplementary_reagents = list( - /datum/reagent/growthserum = 4, - /datum/reagent/drug/blastoff = 3, - /datum/reagent/drug/space_drugs = 2, - /datum/reagent/consumable/ethanol/eggnog = 2, - /datum/reagent/consumable/vanilla = 2, - /datum/reagent/consumable/banana = 1, - /datum/reagent/consumable/nutriment/vitamin = 1) - - suppressive_reagents = list( - /datum/reagent/toxin/cyanide = -5, - /datum/reagent/consumable/mold = -2, - /datum/reagent/toxin/spore = -1) - - resulting_atoms = list(/mob/living/simple_animal/hostile/jungle/leaper = 1) - /datum/micro_organism/cell_line/mega_arachnid desc = "pseudoarachnoid cells" required_reagents = list( diff --git a/code/modules/shuttle/battlecruiser_starfury.dm b/code/modules/shuttle/battlecruiser_starfury.dm index ab1f6802d43ee2..054de00504eb5a 100644 --- a/code/modules/shuttle/battlecruiser_starfury.dm +++ b/code/modules/shuttle/battlecruiser_starfury.dm @@ -172,14 +172,14 @@ "The battlecruiser has an object of interest: [our_candidate]!", source = our_candidate, action = NOTIFY_ORBIT, - header = "Something's Interesting!" - ) + header = "Something's Interesting!", + ) else notify_ghosts( "The battlecruiser has an object of interest: [spawner]!", source = spawner, action = NOTIFY_ORBIT, - header="Something's Interesting!" - ) + header="Something's Interesting!", + ) priority_announce("Unidentified armed ship detected near the station.") diff --git a/code/modules/shuttle/computer.dm b/code/modules/shuttle/computer.dm index 4065591582e262..cf53fef368c1bb 100644 --- a/code/modules/shuttle/computer.dm +++ b/code/modules/shuttle/computer.dm @@ -13,7 +13,7 @@ icon_keyboard = "tech_key" light_color = LIGHT_COLOR_CYAN req_access = list() - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON /// ID of the attached shuttle var/shuttleId /// Possible destinations of the attached shuttle diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 8bb7a3cd174858..d1b30ddfad5657 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -337,7 +337,7 @@ . = ..() -/obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, area/signal_origin, reason, red_alert, set_coefficient=null, silent=FALSE) //SKYRAT EDIT CHANGE - AUTOTRANSFER +/obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, area/signal_origin, reason, red_alert, set_coefficient=null, silent=FALSE) // SKYRAT EDIT CHANGE - AUTOTRANSFER - adds silent arg if(!isnum(set_coefficient)) set_coefficient = SSsecurity_level.current_security_level.shuttle_call_time_mod alert_coeff = set_coefficient @@ -358,8 +358,17 @@ else SSshuttle.emergency_last_call_loc = null - if(!silent) // SKYRAT EDIT ADDITION - priority_announce("The emergency shuttle has been called. [red_alert ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [timeLeft(600)] minutes.[reason][SSshuttle.emergency_last_call_loc ? "\n\nCall signal traced. Results can be viewed on any communications console." : "" ][SSshuttle.admin_emergency_no_recall ? "\n\nWarning: Shuttle recall subroutines disabled; Recall not possible." : ""]", null, ANNOUNCER_SHUTTLECALLED, ANNOUNCEMENT_TYPE_PRIORITY, color_override = "orange") + // SKYRAT EDIT ADDITION START + if(silent) + return + // SKYRAT EDIT ADDITION END + priority_announce( + text = "The emergency shuttle has been called. [red_alert ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [(timeLeft(60 SECONDS))] minutes.[reason][SSshuttle.emergency_last_call_loc ? "\n\nCall signal traced. Results can be viewed on any communications console." : "" ][SSshuttle.admin_emergency_no_recall ? "\n\nWarning: Shuttle recall subroutines disabled; Recall not possible." : ""]", + title = "Emergency Shuttle Dispatched", + sound = ANNOUNCER_SHUTTLECALLED, + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "orange", + ) /obj/docking_port/mobile/emergency/cancel(area/signalOrigin) if(mode != SHUTTLE_CALL) @@ -374,7 +383,13 @@ SSshuttle.emergency_last_call_loc = signalOrigin else SSshuttle.emergency_last_call_loc = null - priority_announce("The emergency shuttle has been recalled.[SSshuttle.emergency_last_call_loc ? " Recall signal traced. Results can be viewed on any communications console." : "" ]", null, ANNOUNCER_SHUTTLERECALLED, ANNOUNCEMENT_TYPE_PRIORITY, color_override = "orange") + priority_announce( + text = "The emergency shuttle has been recalled.[SSshuttle.emergency_last_call_loc ? " Recall signal traced. Results can be viewed on any communications console." : "" ]", + title = "Emergency Shuttle Recalled", + sound = ANNOUNCER_SHUTTLERECALLED, + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "orange", + ) SSticker.emergency_reason = null @@ -463,7 +478,13 @@ mode = SHUTTLE_DOCKED setTimer(SSshuttle.emergency_dock_time) send2adminchat("Server", "The Emergency Shuttle has docked with the station.") - priority_announce("[SSshuttle.emergency] has docked with the station. You have [timeLeft(600)] minutes to board the Emergency Shuttle.", null, ANNOUNCER_SHUTTLEDOCK, ANNOUNCEMENT_TYPE_PRIORITY, color_override = "orange") + priority_announce( + text = "[SSshuttle.emergency] has docked with the station. You have [DisplayTimeText(SSshuttle.emergency_dock_time)] to board the emergency shuttle.", + title = "Emergency Shuttle Arrival", + sound = ANNOUNCER_SHUTTLEDOCK, + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "orange", + ) ShuttleDBStuff() addtimer(CALLBACK(src, PROC_REF(announce_shuttle_events)), 20 SECONDS) @@ -516,7 +537,12 @@ mode = SHUTTLE_ESCAPE launch_status = ENDGAME_LAUNCHED setTimer(SSshuttle.emergency_escape_time * engine_coeff) - priority_announce("The Emergency Shuttle has left the station. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, ANNOUNCEMENT_TYPE_PRIORITY, color_override = "orange") + priority_announce( + text = "The emergency shuttle has left the station. Estimate [timeLeft(60 SECONDS)] minutes until the shuttle docks at [command_name()].", + title = "Emergency Shuttle Departure", + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "orange", + ) INVOKE_ASYNC(SSticker, TYPE_PROC_REF(/datum/controller/subsystem/ticker, poll_hearts)) bolt_all_doors() //SKYRAT EDIT ADDITION SSmapping.mapvote() //If no map vote has been run yet, start one. @@ -584,7 +610,12 @@ mode = SHUTTLE_ESCAPE launch_status = ENDGAME_LAUNCHED setTimer(SSshuttle.emergency_escape_time) - priority_announce("The Emergency Shuttle is preparing for direct jump. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, ANNOUNCEMENT_TYPE_PRIORITY, color_override = "orange") + priority_announce( + text = "The emergency shuttle is preparing for direct jump. Estimate [timeLeft(60 SECONDS)] minutes until the shuttle docks at [command_name()].", + title = "Emergency Shuttle Transit Failure", + sender_override = "Emergency Shuttle Uplink Alert", + color_override = "orange", + ) ///Generate a list of events to run during the departure /obj/docking_port/mobile/emergency/proc/setup_shuttle_events() diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index cdabfdc4926407..548c3a52b57bbd 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -1,38 +1,38 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( /mob/living, - /obj/structure/blob, - /obj/effect/rune, - /obj/item/disk/nuclear, - /obj/machinery/nuclearbomb, - /obj/item/beacon, - /obj/narsie, - /obj/tear_in_reality, - /obj/machinery/teleport/station, - /obj/machinery/teleport/hub, - /obj/machinery/quantumpad, - /obj/effect/mob_spawn, + /obj/docking_port, /obj/effect/hierophant, - /obj/structure/receiving_pad, - /obj/item/warp_cube, - /obj/machinery/rnd/production, //print tracking beacons, send shuttle - /obj/machinery/autolathe, //same - /obj/projectile/beam/wormhole, + /obj/effect/mob_spawn, /obj/effect/portal, - /obj/item/shared_storage, - /obj/structure/extraction_point, - /obj/machinery/syndicatebomb, + /obj/effect/rune, + /obj/item/beacon, + /obj/item/disk/nuclear, + /obj/item/gps, /obj/item/hilbertshotel, - /obj/item/swapper, - /obj/docking_port, - /obj/machinery/launchpad, - /obj/machinery/exodrone_launcher, - /obj/machinery/disposal, - /obj/structure/disposalpipe, /obj/item/mail, + /obj/item/shared_storage, + /obj/item/swapper, + /obj/item/warp_cube, + /obj/machinery/autolathe, // In case you manage to get it to print a beacon while in transit /obj/machinery/camera, - /obj/item/gps, + /obj/machinery/disposal, + /obj/machinery/exodrone_launcher, + /obj/machinery/fax, + /obj/machinery/launchpad, + /obj/machinery/nuclearbomb, + /obj/machinery/quantumpad, + /obj/machinery/rnd/production, + /obj/machinery/syndicatebomb, + /obj/machinery/teleport/hub, + /obj/machinery/teleport/station, + /obj/narsie, + /obj/projectile/beam/wormhole, + /obj/structure/blob, /obj/structure/checkoutmachine, - /obj/machinery/fax + /obj/structure/disposalpipe, + /obj/structure/extraction_point, + /obj/structure/guardian_beacon, + /obj/tear_in_reality, ))) /// How many goody orders we can fit in a lockbox before we upgrade to a crate @@ -157,42 +157,42 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( var/value = 0 var/purchases = 0 + var/price + var/pack_cost var/list/goodies_by_buyer = list() // if someone orders more than GOODY_FREE_SHIPPING_MAX goodies, we upcharge to a normal crate so they can't carry around 20 combat shotties - var/list/forced_briefcases = list() //SKYRAT EDIT + var/list/clean_up_orders = list() // orders to remove since we are done with them + var/list/forced_briefcases = list() // SKYRAT EDIT ADDITION for(var/datum/supply_order/spawning_order in SSshuttle.shopping_list) if(!empty_turfs.len) break - var/price = spawning_order.pack.get_cost() - if(spawning_order.applied_coupon) - price *= (1 - spawning_order.applied_coupon.discount_pct_off) + price = spawning_order.get_final_cost() + // department orders EARN money for cargo, not the other way around var/datum/bank_account/paying_for_this - - //department orders EARN money for cargo, not the other way around - //Skyrat Edit Add if(!spawning_order.department_destination && spawning_order.charge_on_purchase) - //Skyrat Edit End if(spawning_order.paying_account) //Someone paid out of pocket paying_for_this = spawning_order.paying_account - var/list/current_buyer_orders = goodies_by_buyer[spawning_order.paying_account] // so we can access the length a few lines down - if(!spawning_order.pack.goody) - price *= 1.1 //TODO make this customizable by the quartermaster - // note this is before we increment, so this is the GOODY_FREE_SHIPPING_MAX + 1th goody to ship. also note we only increment off this step if they successfully pay the fee, so there's no way around it - else if(LAZYLEN(current_buyer_orders) == GOODY_FREE_SHIPPING_MAX) - price += CRATE_TAX - paying_for_this.bank_card_talk("Goody order size exceeds free shipping limit: Assessing [CRATE_TAX] credit S&H fee.") + if(spawning_order.pack.goody) + var/list/current_buyer_orders = goodies_by_buyer[spawning_order.paying_account] + if(LAZYLEN(current_buyer_orders) == GOODY_FREE_SHIPPING_MAX) + price = round(price + CRATE_TAX) + paying_for_this.bank_card_talk("Goody order size exceeds free shipping limit: Assessing [CRATE_TAX] credit S&H fee.") else paying_for_this = SSeconomy.get_dep_account(ACCOUNT_CAR) + if(paying_for_this) if(!paying_for_this.adjust_money(-price, "Cargo: [spawning_order.pack.name]")) if(spawning_order.paying_account) paying_for_this.bank_card_talk("Cargo order #[spawning_order.id] rejected due to lack of funds. Credits required: [price]") + if(!spawning_order.can_be_cancelled) //only if it absolutly cannot be canceled by the player do we cancel it for them + SSshuttle.shopping_list -= spawning_order + clean_up_orders += spawning_order continue - //Skyrat Edit Add - if(spawning_order.paying_account && spawning_order.charge_on_purchase) - //Skyrat Edit End + + pack_cost = spawning_order.pack.get_cost() + if(spawning_order.paying_account && spawning_order.charge_on_purchase) // SKYRAT EDIT CHANGE - ORIGINAL: if(spawning_order.paying_account) paying_for_this = spawning_order.paying_account if(spawning_order.pack.goody) LAZYADD(goodies_by_buyer[spawning_order.paying_account], spawning_order) @@ -202,13 +202,10 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( paying_for_this.bank_card_talk(reciever_message) SSeconomy.track_purchase(paying_for_this, price, spawning_order.pack.name) var/datum/bank_account/department/cargo = SSeconomy.get_dep_account(ACCOUNT_CAR) - cargo.adjust_money(price - spawning_order.pack.get_cost()) //Cargo gets the handling fee - value += spawning_order.pack.get_cost() - SSshuttle.shopping_list -= spawning_order - SSshuttle.order_history += spawning_order - QDEL_NULL(spawning_order.applied_coupon) + cargo.adjust_money(price - pack_cost) //Cargo gets the handling fee + value += pack_cost - if(!spawning_order.pack.goody && !(spawning_order?.paying_account in forced_briefcases)) //we handle goody crates below //SKYRAT EDIT + if(!spawning_order.pack.goody && !(spawning_order?.paying_account in forced_briefcases)) // SKYRAT EDIT CHANGE - ORIGINAL : if(!spawning_order.pack.goody) var/obj/structure/closet/crate = spawning_order.generate(pick_n_take(empty_turfs)) crate.name += " - #[spawning_order.id]" @@ -221,6 +218,10 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( message_admins("\A [spawning_order.pack.name] ordered by [ADMIN_LOOKUPFLW(spawning_order.orderer_ckey)], paid by [from_whom] has shipped.") purchases++ + // done dealing with order. Time to remove & delete it + SSshuttle.shopping_list -= spawning_order + clean_up_orders += spawning_order + // we handle packing all the goodies last, since the type of crate we use depends on how many goodies they ordered. If it's more than GOODY_FREE_SHIPPING_MAX // then we send it in a crate (including the CRATE_TAX cost), otherwise send it in a free shipping case for(var/buyer_key in goodies_by_buyer) @@ -262,7 +263,10 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( order.generateCombo(miscboxes[miscbox], miscbox, misc_contents[miscbox], misc_costs[miscbox]) qdel(order) - SSeconomy.import_total += value + //clean up all dealt with orders + for(var/datum/supply_order/completed_order in clean_up_orders) + qdel(completed_order) + var/datum/bank_account/cargo_budget = SSeconomy.get_dep_account(ACCOUNT_CAR) investigate_log("[purchases] orders in this shipment, worth [value] credits. [cargo_budget.account_balance] credits left.", INVESTIGATE_CARGO) @@ -297,7 +301,6 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( msg += export_text + "\n" cargo_budget.adjust_money(report.total_value[exported_datum]) - SSeconomy.export_total += (cargo_budget.account_balance - presale_points) SSshuttle.centcom_message = msg investigate_log("contents sold for [cargo_budget.account_balance - presale_points] credits. Contents: [report.exported_atoms ? report.exported_atoms.Join(",") + "." : "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO) diff --git a/code/modules/spells/spell_types/conjure/_conjure.dm b/code/modules/spells/spell_types/conjure/_conjure.dm index 3afe7c52557548..5fcff10ee18abd 100644 --- a/code/modules/spells/spell_types/conjure/_conjure.dm +++ b/code/modules/spells/spell_types/conjure/_conjure.dm @@ -61,3 +61,28 @@ /// Called on atoms summoned after they are created, allows extra variable editing and such of created objects /datum/action/cooldown/spell/conjure/proc/post_summon(atom/summoned_object, atom/cast_on) return + +///limits the amount of summons +/datum/action/cooldown/spell/conjure/limit_summons + ///max number of after images + var/max_summons + ///How many clones do we have summoned + var/number_of_summons = 0 + +/datum/action/cooldown/spell/conjure/limit_summons/can_cast_spell(feedback = TRUE) + . = ..() + if(!.) + return FALSE + if(number_of_summons >= max_summons) + return FALSE + return TRUE + +/datum/action/cooldown/spell/conjure/limit_summons/post_summon(atom/summoned_object, atom/cast_on) + RegisterSignals(summoned_object, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH), PROC_REF(delete_copy)) + number_of_summons++ + +/datum/action/cooldown/spell/conjure/limit_summons/proc/delete_copy(datum/source) + SIGNAL_HANDLER + + UnregisterSignal(source, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH)) + number_of_summons-- diff --git a/code/modules/spells/spell_types/pointed/mind_transfer.dm b/code/modules/spells/spell_types/pointed/mind_transfer.dm index 08c638ffe07074..fa401c3b432f67 100644 --- a/code/modules/spells/spell_types/pointed/mind_transfer.dm +++ b/code/modules/spells/spell_types/pointed/mind_transfer.dm @@ -55,11 +55,21 @@ if(!isliving(cast_on)) to_chat(owner, span_warning("You can only swap minds with living beings!")) return FALSE + + if(HAS_TRAIT(cast_on, TRAIT_MIND_TEMPORARILY_GONE)) + to_chat(owner, span_warning("This creature's mind is somewhere else entirely!")) + return FALSE + + if(HAS_TRAIT(cast_on, TRAIT_NO_MINDSWAP)) + to_chat(owner, span_warning("This type of magic can't operate on [cast_on.p_their()] mind!")) + return FALSE + if(is_type_in_typecache(cast_on, blacklisted_mobs)) to_chat(owner, span_warning("This creature is too [pick("powerful", "strange", "arcane", "obscene")] to control!")) return FALSE + if(isguardian(cast_on)) - var/mob/living/simple_animal/hostile/guardian/stand = cast_on + var/mob/living/basic/guardian/stand = cast_on if(stand.summoner && stand.summoner == owner) to_chat(owner, span_warning("Swapping minds with your own guardian would just put you back into your own head!")) return FALSE @@ -86,7 +96,7 @@ var/mob/living/to_swap = cast_on if(isguardian(cast_on)) - var/mob/living/simple_animal/hostile/guardian/stand = cast_on + var/mob/living/basic/guardian/stand = cast_on if(stand.summoner) to_swap = stand.summoner diff --git a/code/modules/spells/spell_types/self/personality_commune.dm b/code/modules/spells/spell_types/self/personality_commune.dm deleted file mode 100644 index cd10c2b7736aac..00000000000000 --- a/code/modules/spells/spell_types/self/personality_commune.dm +++ /dev/null @@ -1,56 +0,0 @@ -// This can probably be changed to use mind linker at some point -/datum/action/cooldown/spell/personality_commune - name = "Personality Commune" - desc = "Sends thoughts to your alternate consciousness." - button_icon_state = "telepathy" - cooldown_time = 0 SECONDS - spell_requirements = NONE - - /// Fluff text shown when a message is sent to the pair - var/fluff_text = span_boldnotice("You hear an echoing voice in the back of your head...") - /// The message to send to the corresponding person on cast - var/to_send - -/datum/action/cooldown/spell/personality_commune/New(Target) - . = ..() - if(!istype(target, /datum/brain_trauma/severe/split_personality)) - stack_trace("[type] was created on a target that isn't a /datum/brain_trauma/severe/split_personality, this doesn't work.") - qdel(src) - -/datum/action/cooldown/spell/personality_commune/is_valid_target(atom/cast_on) - return isliving(cast_on) - -/datum/action/cooldown/spell/personality_commune/before_cast(atom/cast_on) - . = ..() - if(. & SPELL_CANCEL_CAST) - return - - var/datum/brain_trauma/severe/split_personality/trauma = target - if(!istype(trauma)) // hypothetically impossible but you never know - return . | SPELL_CANCEL_CAST - - to_send = tgui_input_text(cast_on, "What would you like to tell your other self?", "Commune") - if(QDELETED(src) || QDELETED(trauma) || QDELETED(cast_on) || QDELETED(trauma.owner) || !can_cast_spell()) - return . | SPELL_CANCEL_CAST - if(!to_send) - reset_cooldown() - return . | SPELL_CANCEL_CAST - -// Pillaged and adapted from telepathy code -/datum/action/cooldown/spell/personality_commune/cast(mob/living/cast_on) - . = ..() - var/datum/brain_trauma/severe/split_personality/trauma = target - - var/user_message = span_boldnotice("You concentrate and send thoughts to your other self:") - var/user_message_body = span_notice("[to_send]") - - to_chat(cast_on, "[user_message] [user_message_body]") - - trauma.owner.balloon_alert(trauma.owner, "you hear a voice") - to_chat(trauma.owner, "[fluff_text] [user_message_body]") - - log_directed_talk(cast_on, trauma.owner, to_send, LOG_SAY, "[name]") - for(var/dead_mob in GLOB.dead_mob_list) - if(!isobserver(dead_mob)) - continue - to_chat(dead_mob, "[FOLLOW_LINK(dead_mob, cast_on)] [span_boldnotice("[cast_on] [name]:")] [span_notice("\"[to_send]\" to")] [span_name("[trauma]")]") diff --git a/code/modules/spells/spell_types/shapeshift/_shapeshift.dm b/code/modules/spells/spell_types/shapeshift/_shapeshift.dm index 5aecd863bce43c..59c9ffdde3b0be 100644 --- a/code/modules/spells/spell_types/shapeshift/_shapeshift.dm +++ b/code/modules/spells/spell_types/shapeshift/_shapeshift.dm @@ -128,7 +128,7 @@ new gib_type(get_turf(possible_vent)) playsound(possible_vent, 'sound/effects/reee.ogg', 75, TRUE) - priority_announce("We detected a pipe blockage around [get_area(get_turf(cast_on))], please dispatch someone to investigate.", "Central Command") + priority_announce("We detected a pipe blockage around [get_area(get_turf(cast_on))], please dispatch someone to investigate.", "[command_name()]") // Gib our caster, and make sure to leave nothing behind // (If we leave something behind, it'll drop on the turf of the pipe, which is kinda wrong.) cast_on.investigate_log("has been gibbed by shapeshifting while ventcrawling.", INVESTIGATE_DEATHS) diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index ec29b326ae9fc4..5795effc2b6d85 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -243,7 +243,12 @@ GLOBAL_VAR_INIT(bsa_unlock, FALSE) point.Beam(target, icon_state = "bsa_beam", time = 5 SECONDS, maxdistance = world.maxx) //ZZZAP new /obj/effect/temp_visual/bsa_splash(point, dir) - notify_ghosts("The Bluespace Artillery has been fired!", source = bullseye, header = "KABOOM!") + notify_ghosts( + "The Bluespace Artillery has been fired!", + source = bullseye, + header = "KABOOM!", + ) + if(!blocker) message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)].") user.log_message("has launched an artillery strike targeting [AREACOORD(bullseye)].", LOG_GAME) diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index 7eee48f9a797d0..050a34efd3825c 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -32,6 +32,8 @@ var/datum/worn_feature_offset/worn_suit_offset /// Offset to apply to equipment worn on the neck var/datum/worn_feature_offset/worn_neck_offset + /// Which functional (i.e. flightpotion) wing types (if any) does this bodypart support? If count is >1 a radial menu is used to choose between all icons in list + var/list/wing_types = list(/obj/item/organ/external/wings/functional/angel) /obj/item/bodypart/chest/can_dismember(obj/item/item) if(owner.stat < HARD_CRIT || !get_organs()) @@ -81,6 +83,7 @@ bodypart_flags = BODYPART_UNREMOVABLE max_damage = 500 acceptable_bodytype = BODYTYPE_HUMANOID + wing_types = NONE /obj/item/bodypart/chest/larva icon = 'icons/mob/human/species/alien/bodyparts.dmi' @@ -93,6 +96,7 @@ max_damage = 50 bodytype = BODYTYPE_LARVA_PLACEHOLDER | BODYTYPE_ORGANIC acceptable_bodytype = BODYTYPE_LARVA_PLACEHOLDER + wing_types = NONE /// Parent Type for arms, should not appear in game. /obj/item/bodypart/arm diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index d967f2da9ec242..f7fc5367816aa5 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -203,6 +203,8 @@ robotic_emp_paralyze_damage_percent_threshold = 0.6 + wing_types = list(/obj/item/organ/external/wings/functional/robotic) + /obj/item/bodypart/chest/robot/emp_act(severity) . = ..() if(!. || isnull(owner)) diff --git a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm index 2215b388320e8d..feda164b6f2594 100644 --- a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm @@ -22,6 +22,7 @@ is_dimorphic = FALSE dmg_overlay_type = null brute_modifier = 1.25 //ethereal are weak to brute damages + wing_types = NONE /obj/item/bodypart/chest/ethereal/update_limb(dropping_limb, is_creating) . = ..() diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm index b5b306aaf67030..442a159a3fd498 100644 --- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -8,6 +8,7 @@ icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' limb_id = SPECIES_LIZARD is_dimorphic = TRUE + wing_types = list(/obj/item/organ/external/wings/functional/dragon) /obj/item/bodypart/arm/left/lizard icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm index 1f7f00c64112c5..f928a56edf74ea 100644 --- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -1,50 +1,47 @@ ///SNAIL /obj/item/bodypart/head/snail - biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates! limb_id = SPECIES_SNAIL is_dimorphic = FALSE burn_modifier = 2 head_flags = HEAD_EYESPRITES|HEAD_DEBRAIN + biological_state = (BIO_FLESH|BIO_BLOODED) /obj/item/bodypart/chest/snail - biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates! limb_id = SPECIES_SNAIL is_dimorphic = FALSE burn_modifier = 2 + biological_state = (BIO_FLESH|BIO_BLOODED) + wing_types = NONE /obj/item/bodypart/arm/left/snail - biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates! limb_id = SPECIES_SNAIL unarmed_attack_verb = "slap" unarmed_attack_effect = ATTACK_EFFECT_DISARM - unarmed_damage_low = 1 //SKYRAT EDIT - Roundstart Snails - Lowest possible punch damage. if this is set to 0, punches will always miss. - unarmed_damage_high = 5 //snails are soft and squishy //SKYRAT EDIT - Roundstart Snails - A Bit More Damage. - ORIGINAL: unarmed_damage_high = 0.5 //snails are soft and squishy + unarmed_damage_high = 0.5 //snails are soft and squishy burn_modifier = 2 + biological_state = (BIO_FLESH|BIO_BLOODED) /obj/item/bodypart/arm/right/snail - biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates! limb_id = SPECIES_SNAIL unarmed_attack_verb = "slap" unarmed_attack_effect = ATTACK_EFFECT_DISARM - unarmed_damage_low = 1 //SKYRAT EDIT - Roundstart Snails - Lowest possible punch damage. if this is set to 0, punches will always miss. - unarmed_damage_high = 5 //snails are soft and squishy //SKYRAT EDIT - Roundstart Snails - A Bit More Damage. - ORIGINAL: unarmed_damage_high = 0.5 //snails are soft and squishy + unarmed_damage_high = 0.5 burn_modifier = 2 + biological_state = (BIO_FLESH|BIO_BLOODED) /obj/item/bodypart/leg/left/snail - biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates! limb_id = SPECIES_SNAIL - unarmed_damage_low = 1 //SKYRAT EDIT - Roundstart Snails - Lowest possible punch damage. if this is set to 0, punches will always miss. - unarmed_damage_high = 5 //snails are soft and squishy //SKYRAT EDIT - Roundstart Snails - A Bit More Damage. - ORIGINAL: unarmed_damage_high = 0.5 //snails are soft and squishy + unarmed_damage_high = 0.5 burn_modifier = 2 - // speed_modifier = 3 //disgustingly slow // SKYRAT EDIT - Moved the movespeed to the shell. + // speed_modifier = 3 //disgustingly slow // SKYRAT EDIT REMOVAL - Moved the movespeed to the shell. + biological_state = (BIO_FLESH|BIO_BLOODED) /obj/item/bodypart/leg/right/snail - biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates! limb_id = SPECIES_SNAIL - unarmed_damage_low = 1 //SKYRAT EDIT - Roundstart Snails - Lowest possible punch damage. if this is set to 0, punches will always miss. - unarmed_damage_high = 5 //snails are soft and squishy //SKYRAT EDIT - Roundstart Snails - A Bit More Damage. - ORIGINAL: unarmed_damage_high = 0.5 //snails are soft and squishy + unarmed_damage_high = 0.5 burn_modifier = 2 - // speed_modifier = 3 //disgustingly slow // SKYRAT EDIT - Moved the movespeed to the shell. + // speed_modifier = 3 //disgustingly slow // SKYRAT EDIT REMOVAL - Moved the movespeed to the shell. + biological_state = (BIO_FLESH|BIO_BLOODED) ///ABDUCTOR /obj/item/bodypart/head/abductor @@ -57,6 +54,7 @@ limb_id = SPECIES_ABDUCTOR is_dimorphic = FALSE should_draw_greyscale = FALSE + wing_types = NONE /obj/item/bodypart/arm/left/abductor limb_id = SPECIES_ABDUCTOR @@ -91,27 +89,28 @@ is_dimorphic = TRUE dmg_overlay_type = null burn_modifier = 0.5 // = 1/2x generic burn damage + wing_types = NONE /obj/item/bodypart/arm/left/jelly - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_JELLYPERSON dmg_overlay_type = null burn_modifier = 0.5 // = 1/2x generic burn damage /obj/item/bodypart/arm/right/jelly - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_JELLYPERSON dmg_overlay_type = null burn_modifier = 0.5 // = 1/2x generic burn damage /obj/item/bodypart/leg/left/jelly - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_JELLYPERSON dmg_overlay_type = null burn_modifier = 0.5 // = 1/2x generic burn damage /obj/item/bodypart/leg/right/jelly - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_JELLYPERSON dmg_overlay_type = null burn_modifier = 0.5 // = 1/2x generic burn damage @@ -127,13 +126,14 @@ biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_SLIMEPERSON is_dimorphic = TRUE + wing_types = NONE /obj/item/bodypart/arm/left/slime - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_SLIMEPERSON /obj/item/bodypart/arm/right/slime - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_SLIMEPERSON /obj/item/bodypart/leg/left/slime @@ -141,7 +141,7 @@ limb_id = SPECIES_SLIMEPERSON /obj/item/bodypart/leg/right/slime - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_SLIMEPERSON ///LUMINESCENT @@ -155,21 +155,22 @@ biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_LUMINESCENT is_dimorphic = TRUE + wing_types = NONE /obj/item/bodypart/arm/left/luminescent - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_LUMINESCENT /obj/item/bodypart/arm/right/luminescent - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_LUMINESCENT /obj/item/bodypart/leg/left/luminescent - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_LUMINESCENT /obj/item/bodypart/leg/right/luminescent - biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) + biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_LUMINESCENT ///ZOMBIE @@ -183,6 +184,7 @@ limb_id = SPECIES_ZOMBIE is_dimorphic = FALSE should_draw_greyscale = FALSE + wing_types = NONE /obj/item/bodypart/arm/left/zombie limb_id = SPECIES_ZOMBIE @@ -221,6 +223,7 @@ limb_id = SPECIES_PODPERSON is_dimorphic = TRUE burn_modifier = 1.25 + wing_types = NONE /obj/item/bodypart/arm/left/pod limb_id = SPECIES_PODPERSON @@ -257,6 +260,7 @@ limb_id = SPECIES_FLYPERSON is_dimorphic = TRUE should_draw_greyscale = FALSE + wing_types = list(/obj/item/organ/external/wings/functional/fly) /obj/item/bodypart/arm/left/fly limb_id = SPECIES_FLYPERSON @@ -287,6 +291,7 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE burn_modifier = 1.5 + wing_types = NONE /obj/item/bodypart/arm/left/shadow limb_id = SPECIES_SHADOW @@ -329,6 +334,7 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE dmg_overlay_type = null + wing_types = list(/obj/item/organ/external/wings/functional/skeleton) /obj/item/bodypart/arm/left/skeleton biological_state = (BIO_BONE|BIO_JOINTED) @@ -366,6 +372,7 @@ is_dimorphic = TRUE bodypart_traits = list(TRAIT_NO_JUMPSUIT) burn_modifier = 1.25 + wing_types = NONE /obj/item/bodypart/arm/left/mushroom limb_id = SPECIES_MUSHROOM @@ -466,6 +473,7 @@ should_draw_greyscale = FALSE dmg_overlay_type = null bodypart_traits = list(TRAIT_NO_JUMPSUIT) + wing_types = NONE /obj/item/bodypart/chest/golem/Initialize(mapload) worn_belt_offset = new( @@ -568,3 +576,45 @@ unarmed_damage_low = 7 unarmed_damage_high = 21 unarmed_stun_threshold = 11 + +///flesh + +/obj/item/bodypart/arm/left/flesh + limb_id = BODYPART_ID_MEAT + should_draw_greyscale = FALSE + +/obj/item/bodypart/arm/left/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) + . = ..() + if(!dont_spawn_flesh) + new /mob/living/basic/living_limb_flesh(src, src) + ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + +/obj/item/bodypart/arm/right/flesh + limb_id = BODYPART_ID_MEAT + should_draw_greyscale = FALSE + +/obj/item/bodypart/arm/right/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) + . = ..() + if(!dont_spawn_flesh) + new /mob/living/basic/living_limb_flesh(src, src) + ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + +/obj/item/bodypart/leg/left/flesh + limb_id = BODYPART_ID_MEAT + should_draw_greyscale = FALSE + +/obj/item/bodypart/leg/left/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) + . = ..() + if(!dont_spawn_flesh) + new /mob/living/basic/living_limb_flesh(src, src) + ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + +/obj/item/bodypart/leg/right/flesh + limb_id = BODYPART_ID_MEAT + should_draw_greyscale = FALSE + +/obj/item/bodypart/leg/right/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) + . = ..() + if(!dont_spawn_flesh) + new /mob/living/basic/living_limb_flesh(src, src) + ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) diff --git a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm index 8b091ed34b95a9..e75997b1a427f1 100644 --- a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm @@ -15,6 +15,7 @@ limb_id = SPECIES_MOTH is_dimorphic = TRUE should_draw_greyscale = FALSE + wing_types = list(/obj/item/organ/external/wings/functional/moth/megamoth, /obj/item/organ/external/wings/functional/moth/mothra) /obj/item/bodypart/arm/left/moth icon = 'icons/mob/human/species/moth/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm index f478d522d5690a..8070072521f346 100644 --- a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm @@ -22,6 +22,7 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + wing_types = NONE /obj/item/bodypart/arm/left/plasmaman icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi' diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm index 5b78cb30796e75..a3feba76fece3e 100644 --- a/code/modules/surgery/organs/_organ.dm +++ b/code/modules/surgery/organs/_organ.dm @@ -181,7 +181,11 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) SEND_SIGNAL(src, COMSIG_ORGAN_REMOVED, organ_owner) SEND_SIGNAL(organ_owner, COMSIG_CARBON_LOSE_ORGAN, src, special) - if(!IS_ROBOTIC_ORGAN(src) && !(item_flags & NO_BLOOD_ON_ITEM) && !QDELING(src)) + // We don't need to readd things to the organ if it's getting deleted + if(QDELING(src)) + return + + if(!IS_ROBOTIC_ORGAN(src) && !(item_flags & NO_BLOOD_ON_ITEM)) AddElement(/datum/element/decal/blood) var/list/diseases = organ_owner.get_static_viruses() diff --git a/code/modules/surgery/organs/autosurgeon.dm b/code/modules/surgery/organs/autosurgeon.dm index 0987df92bd94e1..921acf808ed90c 100644 --- a/code/modules/surgery/organs/autosurgeon.dm +++ b/code/modules/surgery/organs/autosurgeon.dm @@ -74,15 +74,21 @@ return if(implant_time) - user.visible_message( "[user] prepares to use [src] on [target].", "You begin to prepare to use [src] on [target].") - if(!do_after(user, (8 SECONDS * surgery_speed), target)) + user.visible_message( + span_notice("[user] prepares to use [src] on [target]."), + span_notice("You begin to prepare to use [src] on [target]."), + ) + if(!do_after(user, (implant_time * surgery_speed), target)) return if(target != user) log_combat(user, target, "autosurgeon implanted [stored_organ] into", "[src]", "in [AREACOORD(target)]") user.visible_message(span_notice("[user] presses a button on [src] as it plunges into [target]'s body."), span_notice("You press a button on [src] as it plunges into [target]'s body.")) else - user.visible_message(span_notice("[user] pressses a button on [src] as it plunges into [user.p_their()] body."), "You press a button on [src] as it plunges into your body.") + user.visible_message( + span_notice("[user] pressses a button on [src] as it plunges into [user.p_their()] body."), + span_notice("You press a button on [src] as it plunges into your body."), + ) stored_organ.Insert(target)//insert stored organ into the user stored_organ = null diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index a5f8543f1e77b8..7c7181afc838d8 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -33,7 +33,7 @@ /obj/item/organ/external/tail/Remove(mob/living/carbon/organ_owner, special, moving) if(wag_flags & WAG_WAGGING) - wag(FALSE) + wag(organ_owner, start = FALSE) return ..() @@ -46,30 +46,42 @@ organ_owner.add_mood_event("tail_lost", /datum/mood_event/tail_lost) organ_owner.add_mood_event("tail_balance_lost", /datum/mood_event/tail_balance_lost) - -/obj/item/organ/external/tail/proc/wag(mob/user, start = TRUE, stop_after = 0) +/obj/item/organ/external/tail/proc/wag(mob/living/carbon/organ_owner, start = TRUE, stop_after = 0) if(!(wag_flags & WAG_ABLE)) return if(start) - start_wag() - if(stop_after) - addtimer(CALLBACK(src, PROC_REF(wag), FALSE), stop_after, TIMER_STOPPABLE|TIMER_DELETE_ME) + if(start_wag(organ_owner) && stop_after) + addtimer(CALLBACK(src, PROC_REF(wag), organ_owner, FALSE), stop_after, TIMER_STOPPABLE|TIMER_DELETE_ME) else - stop_wag() - owner.update_body() // SKYRAT EDIT - Golden update this in your upcoming tail refactor please :) - Original: owner.update_body_parts() + stop_wag(organ_owner) ///We need some special behaviour for accessories, wrapped here so we can easily add more interactions later -/obj/item/organ/external/tail/proc/start_wag() +/obj/item/organ/external/tail/proc/start_wag(mob/living/carbon/organ_owner) + if(wag_flags & WAG_WAGGING) // we are already wagging + return FALSE + if(organ_owner.stat == DEAD || organ_owner != owner) // no wagging when owner is dead or tail has been disembodied + return FALSE + var/datum/bodypart_overlay/mutant/tail/accessory = bodypart_overlay wag_flags |= WAG_WAGGING accessory.wagging = TRUE + organ_owner.update_body_parts() + RegisterSignal(organ_owner, COMSIG_LIVING_DEATH, PROC_REF(stop_wag)) + return TRUE ///We need some special behaviour for accessories, wrapped here so we can easily add more interactions later -/obj/item/organ/external/tail/proc/stop_wag() +/obj/item/organ/external/tail/proc/stop_wag(mob/living/carbon/organ_owner) + SIGNAL_HANDLER + var/datum/bodypart_overlay/mutant/tail/accessory = bodypart_overlay wag_flags &= ~WAG_WAGGING accessory.wagging = FALSE + if(isnull(organ_owner)) + return + + organ_owner.update_body_parts() + UnregisterSignal(organ_owner, COMSIG_LIVING_DEATH) ///Tail parent type (which is MONKEEEEEEEEEEE by default), with wagging functionality /datum/bodypart_overlay/mutant/tail diff --git a/code/modules/surgery/organs/external/wings/functional_wings.dm b/code/modules/surgery/organs/external/wings/functional_wings.dm index 0cdca01f72cd32..8f82bcb945a149 100644 --- a/code/modules/surgery/organs/external/wings/functional_wings.dm +++ b/code/modules/surgery/organs/external/wings/functional_wings.dm @@ -26,10 +26,8 @@ ///Are our wings open or closed? var/wings_open = FALSE -// SKYRAT EDIT START - No free fall softening for everyone -/obj/item/organ/external/wings/functional/can_soften_fall() - return TRUE -// SKYRAT EDIT END + // grind_results = list(/datum/reagent/flightpotion = 5) + food_reagents = list(/datum/reagent/flightpotion = 5) /obj/item/organ/external/wings/functional/Insert(mob/living/carbon/receiver, special, drop_if_replaced) . = ..() diff --git a/code/modules/surgery/organs/external/wings/wings.dm b/code/modules/surgery/organs/external/wings/wings.dm index 1abe48e30d852c..73c6fb64c79b56 100644 --- a/code/modules/surgery/organs/external/wings/wings.dm +++ b/code/modules/surgery/organs/external/wings/wings.dm @@ -11,7 +11,7 @@ ///Checks if the wings can soften short falls /obj/item/organ/external/wings/proc/can_soften_fall() - return FALSE // SKYRAT EDIT - No free fall softening for everyone - Original: return TRUE + return TRUE ///Bodypart overlay of default wings. Does not have any wing functionality /datum/bodypart_overlay/mutant/wings diff --git a/code/modules/surgery/organs/internal/appendix/_appendix.dm b/code/modules/surgery/organs/internal/appendix/_appendix.dm index bb02c8b9ef9e9c..43a6bfb7a41a8e 100644 --- a/code/modules/surgery/organs/internal/appendix/_appendix.dm +++ b/code/modules/surgery/organs/internal/appendix/_appendix.dm @@ -46,7 +46,12 @@ if(owner) ADD_TRAIT(owner, TRAIT_DISEASELIKE_SEVERITY_MEDIUM, type) owner.med_hud_set_status() - notify_ghosts("[owner] has developed spontaneous appendicitis!", source = owner, action = NOTIFY_ORBIT, header = "Whoa, Sick!") + notify_ghosts( + "[owner] has developed spontaneous appendicitis!", + source = owner, + action = NOTIFY_ORBIT, + header = "Whoa, Sick!", + ) /obj/item/organ/internal/appendix/proc/inflamation(seconds_per_tick) var/mob/living/carbon/organ_owner = owner diff --git a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm index 4cc8ee404c14d3..c1632f33329d41 100644 --- a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm +++ b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm @@ -92,7 +92,7 @@ playsound(carbon, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) carbon.cut_overlay(overcharge) - tesla_zap(carbon, 2, crystal_charge * 1e3, ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES) + tesla_zap(source = carbon, zap_range = 2, power = crystal_charge * 2.5, cutoff = 1e3, zap_flags = ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES) adjust_charge(ETHEREAL_CHARGE_FULL - crystal_charge) carbon.visible_message(span_danger("[carbon] violently discharges energy!"), span_warning("You violently discharge energy!")) diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index c5f62883b5f119..83b1b0705ef861 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -597,33 +597,31 @@ ui.open() /obj/item/blood_filter/ui_data(mob/user) - var/list/data = list() - var/list/chem_names = list() + . = list() + + .["whitelist"] = list() for(var/key in whitelist) - chem_names += whitelist[key] - data["whitelist"] = chem_names - return data + .["whitelist"] += whitelist[key] /obj/item/blood_filter/ui_act(action, params) . = ..() if(.) return + . = TRUE switch(action) if("add") - var/selected_reagent = tgui_input_list(usr, "Select reagent to filter", "Whitelist reagent", GLOB.chemical_name_list) + var/selected_reagent = tgui_input_list(usr, "Select reagent to filter", "Whitelist reagent", GLOB.name2reagent) if(!selected_reagent) - return TRUE + return FALSE - var/chem_id = get_chem_id(selected_reagent) + var/datum/reagent/chem_id = GLOB.name2reagent[selected_reagent] if(!chem_id) - return TRUE + return FALSE if(!(chem_id in whitelist)) whitelist[chem_id] = selected_reagent - - if("remove") var/chem_name = params["reagent"] var/chem_id = get_chem_id(chem_name) diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm index 41a04733945257..b9a9f27a28ae86 100644 --- a/code/modules/tgs/core/core.dm +++ b/code/modules/tgs/core/core.dm @@ -153,4 +153,9 @@ /world/TgsSecurityLevel() var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) if(api) - api.SecurityLevel() + return api.SecurityLevel() + +/world/TgsVisibility() + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + return api.Visibility() diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm index 68b0330fe86065..07ce3b684584eb 100644 --- a/code/modules/tgs/core/datum.dm +++ b/code/modules/tgs/core/datum.dm @@ -11,6 +11,15 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null) src.event_handler = event_handler src.version = version +/datum/tgs_api/proc/TerminateWorld() + while(TRUE) + TGS_DEBUG_LOG("About to terminate world. Tick: [world.time], sleep_offline: [world.sleep_offline]") + world.sleep_offline = FALSE // https://www.byond.com/forum/post/2894866 + del(world) + world.sleep_offline = FALSE // just in case, this is BYOND after all... + sleep(1) + TGS_DEBUG_LOG("BYOND DIDN'T TERMINATE THE WORLD!!! TICK IS: [world.time], sleep_offline: [world.sleep_offline]") + /datum/tgs_api/latest parent_type = /datum/tgs_api/v5 @@ -57,3 +66,6 @@ TGS_PROTECT_DATUM(/datum/tgs_api) /datum/tgs_api/proc/SecurityLevel() return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/Visibility() + return TGS_UNIMPLEMENTED diff --git a/code/modules/tgs/v4/api.dm b/code/modules/tgs/v4/api.dm index b9a75c4abb4891..945e2e41176711 100644 --- a/code/modules/tgs/v4/api.dm +++ b/code/modules/tgs/v4/api.dm @@ -73,7 +73,7 @@ if(cached_json["apiValidateOnly"]) TGS_INFO_LOG("Validating API and exiting...") Export(TGS4_COMM_VALIDATE, list(TGS4_PARAMETER_DATA = "[minimum_required_security_level]")) - del(world) + TerminateWorld() security_level = cached_json["securityLevel"] chat_channels_json_path = cached_json["chatChannelsJson"] @@ -188,7 +188,7 @@ requesting_new_port = TRUE if(!world.OpenPort(0)) //open any port TGS_ERROR_LOG("Unable to open random port to retrieve new port![TGS4_PORT_CRITFAIL_MESSAGE]") - del(world) + TerminateWorld() //request a new port export_lock = FALSE @@ -196,16 +196,16 @@ if(!new_port_json) TGS_ERROR_LOG("No new port response from server![TGS4_PORT_CRITFAIL_MESSAGE]") - del(world) + TerminateWorld() var/new_port = new_port_json[TGS4_PARAMETER_DATA] if(!isnum(new_port) || new_port <= 0) TGS_ERROR_LOG("Malformed new port json ([json_encode(new_port_json)])![TGS4_PORT_CRITFAIL_MESSAGE]") - del(world) + TerminateWorld() if(new_port != world.port && !world.OpenPort(new_port)) TGS_ERROR_LOG("Unable to open port [new_port]![TGS4_PORT_CRITFAIL_MESSAGE]") - del(world) + TerminateWorld() requesting_new_port = FALSE while(export_lock) diff --git a/code/modules/tgs/v5/__interop_version.dm b/code/modules/tgs/v5/__interop_version.dm index 5d3d491a7362bb..1b52b31d6a73ee 100644 --- a/code/modules/tgs/v5/__interop_version.dm +++ b/code/modules/tgs/v5/__interop_version.dm @@ -1 +1 @@ -"5.6.1" +"5.6.2" diff --git a/code/modules/tgs/v5/_defines.dm b/code/modules/tgs/v5/_defines.dm index f973338daa032d..bdcd4e4dd58e69 100644 --- a/code/modules/tgs/v5/_defines.dm +++ b/code/modules/tgs/v5/_defines.dm @@ -48,6 +48,7 @@ #define DMAPI5_RUNTIME_INFORMATION_REVISION "revision" #define DMAPI5_RUNTIME_INFORMATION_TEST_MERGES "testMerges" #define DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL "securityLevel" +#define DMAPI5_RUNTIME_INFORMATION_VISIBILITY "visibility" #define DMAPI5_CHAT_UPDATE_CHANNELS "channels" diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm index 34cc43f8762f7c..7226f29bba603c 100644 --- a/code/modules/tgs/v5/api.dm +++ b/code/modules/tgs/v5/api.dm @@ -4,6 +4,7 @@ var/instance_name var/security_level + var/visibility var/reboot_mode = TGS_REBOOT_MODE_NORMAL @@ -50,10 +51,11 @@ if(runtime_information[DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY]) TGS_INFO_LOG("DMAPI validation, exiting...") - del(world) + TerminateWorld() version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION]) security_level = runtime_information[DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL] + visibility = runtime_information[DMAPI5_RUNTIME_INFORMATION_VISIBILITY] instance_name = runtime_information[DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME] var/list/revisionData = runtime_information[DMAPI5_RUNTIME_INFORMATION_REVISION] @@ -252,3 +254,7 @@ /datum/tgs_api/v5/SecurityLevel() RequireInitialBridgeResponse() return security_level + +/datum/tgs_api/v5/Visibility() + RequireInitialBridgeResponse() + return visibility diff --git a/code/modules/tgs/v5/undefs.dm b/code/modules/tgs/v5/undefs.dm index c679737dfc4961..f163adaaafe3b6 100644 --- a/code/modules/tgs/v5/undefs.dm +++ b/code/modules/tgs/v5/undefs.dm @@ -48,6 +48,7 @@ #undef DMAPI5_RUNTIME_INFORMATION_REVISION #undef DMAPI5_RUNTIME_INFORMATION_TEST_MERGES #undef DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL +#undef DMAPI5_RUNTIME_INFORMATION_VISIBILITY #undef DMAPI5_CHAT_UPDATE_CHANNELS diff --git a/code/modules/tgui_input/alert.dm b/code/modules/tgui_input/alert.dm index 4dc197a3c8cdd0..0ea9c45d310b8f 100644 --- a/code/modules/tgui_input/alert.dm +++ b/code/modules/tgui_input/alert.dm @@ -18,7 +18,11 @@ var/client/client = user user = client.mob else - return + return null + + if(isnull(user.client)) + return null + // A gentle nudge - you should not be using TGUI alert for anything other than a simple message. if(length(buttons) > 3) log_tgui(user, "Error: TGUI Alert initiated with too many buttons. Use a list.", "TguiAlert") diff --git a/code/modules/tgui_input/checkboxes.dm b/code/modules/tgui_input/checkboxes.dm index ec43bd8914d5ab..9204e67ba36075 100644 --- a/code/modules/tgui_input/checkboxes.dm +++ b/code/modules/tgui_input/checkboxes.dm @@ -14,13 +14,17 @@ if (!user) user = usr if(!length(items)) - return + return null if (!istype(user)) if (istype(user, /client)) var/client/client = user user = client.mob else - return + return null + + if(isnull(user.client)) + return null + if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input)) return input(user, message, title) as null|anything in items var/datum/tgui_checkbox_input/input = new(user, message, title, items, min_checked, max_checked, timeout, ui_state) diff --git a/code/modules/tgui_input/list.dm b/code/modules/tgui_input/list.dm index 95daaadb32649e..18525e6b10a1d8 100644 --- a/code/modules/tgui_input/list.dm +++ b/code/modules/tgui_input/list.dm @@ -14,17 +14,24 @@ if (!user) user = usr if(!length(items)) - return + return null if (!istype(user)) if (istype(user, /client)) var/client/client = user user = client.mob else - return + return null + + if(isnull(user.client)) + return null + /// Client does NOT have tgui_input on: Returns regular input if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input)) return input(user, message, title, default) as null|anything in items var/datum/tgui_list_input/input = new(user, message, title, items, default, timeout, ui_state) + if(input.invalid) + qdel(input) + return input.ui_interact(user) input.wait() if (input) @@ -58,6 +65,8 @@ var/closed /// The TGUI UI state that will be returned in ui_state(). Default: always_state var/datum/ui_state/state + /// Whether the tgui list input is invalid or not (i.e. due to all list entries being null) + var/invalid = FALSE /datum/tgui_list_input/New(mob/user, message, title, list/items, default, timeout, ui_state) src.title = title @@ -77,6 +86,9 @@ string_key = avoid_assoc_duplicate_keys(string_key, repeat_items) src.items += string_key src.items_map[string_key] = i + + if(length(src.items) == 0) + invalid = TRUE if (timeout) src.timeout = timeout start_time = world.time diff --git a/code/modules/tgui_input/number.dm b/code/modules/tgui_input/number.dm index bcdf495fd82e86..e0a3f1951e5a72 100644 --- a/code/modules/tgui_input/number.dm +++ b/code/modules/tgui_input/number.dm @@ -23,7 +23,11 @@ var/client/client = user user = client.mob else - return + return null + + if (isnull(user.client)) + return null + // Client does NOT have tgui_input on: Returns regular input if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input)) var/input_number = input(user, message, title, default) as null|num diff --git a/code/modules/tgui_input/text.dm b/code/modules/tgui_input/text.dm index 811673a4c03aae..f78ededab5d96a 100644 --- a/code/modules/tgui_input/text.dm +++ b/code/modules/tgui_input/text.dm @@ -23,7 +23,11 @@ var/client/client = user user = client.mob else - return + return null + + if(isnull(user.client)) + return null + // Client does NOT have tgui_input on: Returns regular input if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input)) if(encode) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 914f902baf2944..c14f807aa1962d 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -168,6 +168,7 @@ #include "load_map_security.dm" #include "lungs.dm" #include "machine_disassembly.dm" +#include "mafia.dm" #include "map_landmarks.dm" #include "mapload_space_verification.dm" #include "mapping.dm" @@ -254,6 +255,7 @@ #include "subsystem_init.dm" #include "suit_storage_icons.dm" #include "surgeries.dm" +#include "tail_wag.dm" #include "teleporters.dm" #include "tgui_create_message.dm" #include "timer_sanity.dm" diff --git a/code/modules/unit_tests/barsigns.dm b/code/modules/unit_tests/barsigns.dm index 7058dd5346dc98..64e8b3ad09ab5a 100644 --- a/code/modules/unit_tests/barsigns.dm +++ b/code/modules/unit_tests/barsigns.dm @@ -2,28 +2,41 @@ * Test if icon states for each datum actually exist in the DMI. */ /datum/unit_test/barsigns_icon + var/list/blacklisted_sign_types = list(/datum/barsign/skyrat, /datum/barsign/skyrat/tan/, /datum/barsign/skyrat/large) // SKYRAT EDIT ADDITION - Modular barsigns /datum/unit_test/barsigns_icon/Run() var/obj/machinery/barsign_type = /obj/machinery/barsign var/icon/barsign_icon = initial(barsign_type.icon) var/list/barsign_icon_states = icon_states(barsign_icon) + barsign_icon_states += icon_states(SKYRAT_BARSIGN_FILE) // SKYRAT EDIT ADDITION - Need to check modular barsigns + barsign_icon_states += icon_states(SKYRAT_LARGE_BARSIGN_FILE) // SKYRAT EDIT ADDITION - Need to check modular barsigns + barsign_icon_states += icon_states(TAN_BAR_SIGNS) // Check every datum real bar sign for(var/sign_type in (subtypesof(/datum/barsign) - /datum/barsign/hiddensigns)) + // SKYRAT EDIT ADDITION BEGIN - MODULAR BARSIGNS + if(sign_type in blacklisted_sign_types) + continue + // SKYRAT EDIT ADDITION END var/datum/barsign/sign = new sign_type() - if(!(sign.icon in barsign_icon_states)) + if(!(sign.icon_state in barsign_icon_states)) TEST_FAIL("Icon state for [sign_type] does not exist in [barsign_icon].") /** * Check that bar signs have a name and desc, and that the name is unique. */ /datum/unit_test/barsigns_name + var/list/blacklisted_sign_types = list(/datum/barsign/skyrat, /datum/barsign/skyrat/large) // SKYRAT EDIT ADDITION - Modular barsigns /datum/unit_test/barsigns_name/Run() var/list/existing_names = list() - for(var/sign_type in subtypesof(/datum/barsign) - /datum/barsign/hiddensigns) + for(var/sign_type in (subtypesof(/datum/barsign) - /datum/barsign/hiddensigns)) + // SKYRAT EDIT ADDITION BEGIN - MODULAR BARSIGNS + if(sign_type in blacklisted_sign_types) + continue + // SKYRAT EDIT ADDITION END var/datum/barsign/sign = new sign_type() if(!sign.name) diff --git a/code/modules/unit_tests/mafia.dm b/code/modules/unit_tests/mafia.dm new file mode 100644 index 00000000000000..85fa50842932b5 --- /dev/null +++ b/code/modules/unit_tests/mafia.dm @@ -0,0 +1,48 @@ +///Checks if a Mafia game with a Modular Computer and a Ghost will run with 'basic_setup', which is the default +///way the game is ran, without admin-intervention. +///The game should immediately end in a Town Victory due to lack of evils, but we can verify that both the PDA and the ghost +///successfully managed to get into the round. +/datum/unit_test/mafia + ///Boolean on whether the Mafia game started or not. Will Fail if it hasn't. + var/mafia_game_started = FALSE + +/datum/unit_test/mafia/Run() + RegisterSignal(SSdcs, COMSIG_MAFIA_GAME_START, PROC_REF(on_mafia_start)) + var/datum/mafia_controller/controller = GLOB.mafia_game || new() + + TEST_ASSERT(controller, "No Mafia game was found, nor was it able to be created properly.") + + //spawn human and give them a laptop. + var/mob/living/carbon/human/consistent/living_player = allocate(/mob/living/carbon/human/consistent) + var/obj/item/modular_computer/laptop/preset/mafia/modpc_player = allocate(/obj/item/modular_computer/laptop/preset/mafia) + living_player.put_in_active_hand(modpc_player, TRUE) + + //make the laptop run Mafia app. + var/datum/computer_file/program/mafia/mafia_program = locate() in modpc_player.stored_files + TEST_ASSERT(mafia_program, "Mafia program was unable to be found on [modpc_player].") + modpc_player.active_program = mafia_program + + //Spawn a ghost and make them eligible to use the Mafia UI (just to be safe). + var/mob/dead/observer/ghost_player = allocate(/mob/dead/observer) + var/datum/client_interface/mock_client = new() + ghost_player.mock_client = mock_client + mock_client.mob = ghost_player + ADD_TRAIT(ghost_player, TRAIT_PRESERVE_UI_WITHOUT_CLIENT, TRAIT_SOURCE_UNIT_TESTS) + + //First make the human sign up for Mafia, then the ghost, then we'll auto-start it. + controller.signup_mafia(living_player, modpc = modpc_player) + controller.signup_mafia(ghost_player, ghost_client = mock_client) + + controller.basic_setup() + + TEST_ASSERT(mafia_game_started, "Mafia game did not start despite basic_setup being called.") + TEST_ASSERT_NOTNULL(controller.player_role_lookup[modpc_player], "The Modular Computer was unable to join a game of Mafia.") + TEST_ASSERT_NOTNULL(controller.player_role_lookup[mock_client.ckey], "The Mock client wasn't put into a game of Mafia.") + + mock_client.mob = null + + qdel(controller) + +/datum/unit_test/mafia/proc/on_mafia_start(datum/controller/subsystem/processing/dcs/source, datum/mafia_controller/game) + SIGNAL_HANDLER + mafia_game_started = TRUE diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index f6b6b9af2b88a2..5227a33aeaf2cd 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -58,59 +58,30 @@ /mob/living/simple_animal/hostile/asteroid/polarbear, /mob/living/simple_animal/hostile/asteroid/polarbear/lesser, /mob/living/simple_animal/hostile/asteroid/wolf, - /mob/living/simple_animal/hostile/construct, - /mob/living/simple_animal/hostile/construct/proteon, - /mob/living/simple_animal/hostile/construct/proteon/hostile, - /mob/living/simple_animal/hostile/construct/wraith, - /mob/living/simple_animal/hostile/construct/wraith/angelic, - /mob/living/simple_animal/hostile/construct/wraith/hostile, - /mob/living/simple_animal/hostile/construct/wraith/mystic, - /mob/living/simple_animal/hostile/construct/wraith/noncult, /mob/living/simple_animal/hostile/dark_wizard, - /mob/living/simple_animal/hostile/guardian, - /mob/living/simple_animal/hostile/guardian/assassin, - /mob/living/simple_animal/hostile/guardian/charger, - /mob/living/simple_animal/hostile/guardian/dextrous, - /mob/living/simple_animal/hostile/guardian/explosive, - /mob/living/simple_animal/hostile/guardian/gaseous, - /mob/living/simple_animal/hostile/guardian/gravitokinetic, - /mob/living/simple_animal/hostile/guardian/lightning, - /mob/living/simple_animal/hostile/guardian/protector, - /mob/living/simple_animal/hostile/guardian/ranged, - /mob/living/simple_animal/hostile/guardian/standard, - /mob/living/simple_animal/hostile/guardian/support, /mob/living/simple_animal/hostile/illusion, /mob/living/simple_animal/hostile/illusion/escape, /mob/living/simple_animal/hostile/illusion/mirage, - /mob/living/simple_animal/hostile/jungle, - /mob/living/simple_animal/hostile/jungle/leaper, /mob/living/simple_animal/hostile/megafauna, /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner, /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/doom, /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance, /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter, - /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/virtual_domain, /mob/living/simple_animal/hostile/megafauna/bubblegum, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination, - /mob/living/simple_animal/hostile/megafauna/bubblegum/virtual_domain, /mob/living/simple_animal/hostile/megafauna/clockwork_defender, /mob/living/simple_animal/hostile/megafauna/colossus, - /mob/living/simple_animal/hostile/megafauna/colossus/virtual_domain, /mob/living/simple_animal/hostile/megafauna/demonic_frost_miner, /mob/living/simple_animal/hostile/megafauna/dragon, /mob/living/simple_animal/hostile/megafauna/dragon/lesser, - /mob/living/simple_animal/hostile/megafauna/dragon/virtual_domain, /mob/living/simple_animal/hostile/megafauna/hierophant, - /mob/living/simple_animal/hostile/megafauna/hierophant/virtual_domain, /mob/living/simple_animal/hostile/megafauna/legion, - /mob/living/simple_animal/hostile/megafauna/legion/virtual_domain, /mob/living/simple_animal/hostile/megafauna/legion/medium, /mob/living/simple_animal/hostile/megafauna/legion/medium/eye, /mob/living/simple_animal/hostile/megafauna/legion/medium/left, /mob/living/simple_animal/hostile/megafauna/legion/medium/right, /mob/living/simple_animal/hostile/megafauna/legion/small, /mob/living/simple_animal/hostile/megafauna/wendigo, - /mob/living/simple_animal/hostile/megafauna/wendigo/virtual_domain, /mob/living/simple_animal/hostile/mimic, /mob/living/simple_animal/hostile/mimic/copy, /mob/living/simple_animal/hostile/mimic/copy/machine, @@ -120,18 +91,10 @@ /mob/living/simple_animal/hostile/ooze, /mob/living/simple_animal/hostile/ooze/gelatinous, /mob/living/simple_animal/hostile/ooze/grapes, - /mob/living/simple_animal/hostile/pirate, - /mob/living/simple_animal/hostile/pirate/melee, - /mob/living/simple_animal/hostile/pirate/melee/space, - /mob/living/simple_animal/hostile/pirate/ranged, - /mob/living/simple_animal/hostile/pirate/ranged/space, /mob/living/simple_animal/hostile/retaliate, /mob/living/simple_animal/hostile/retaliate/goose, /mob/living/simple_animal/hostile/retaliate/goose/vomit, - /mob/living/simple_animal/hostile/retaliate/trader, - /mob/living/simple_animal/hostile/retaliate/trader/mrbones, /mob/living/simple_animal/hostile/vatbeast, - /mob/living/simple_animal/hostile/wizard, /mob/living/simple_animal/hostile/zombie, /mob/living/simple_animal/parrot, /mob/living/simple_animal/parrot/natural, @@ -150,7 +113,6 @@ /mob/living/simple_animal/pet/gondola, /mob/living/simple_animal/pet/gondola/gondolapod, /mob/living/simple_animal/pet/gondola/virtual_domain, - /mob/living/simple_animal/shade, /mob/living/simple_animal/slime, /mob/living/simple_animal/slime/pet, /mob/living/simple_animal/slime/random, diff --git a/code/modules/unit_tests/spell_shapeshift.dm b/code/modules/unit_tests/spell_shapeshift.dm index 9b5804e3520621..3b598e9994200c 100644 --- a/code/modules/unit_tests/spell_shapeshift.dm +++ b/code/modules/unit_tests/spell_shapeshift.dm @@ -87,7 +87,7 @@ shift.shapeshift_type = shift.possible_shapes[1] shift.Grant(dummy) - var/mob/living/simple_animal/hostile/guardian/test_stand = allocate(/mob/living/simple_animal/hostile/guardian) + var/mob/living/basic/guardian/test_stand = allocate(/mob/living/basic/guardian) test_stand.set_summoner(dummy) // The stand's summoner is dummy. diff --git a/code/modules/unit_tests/tail_wag.dm b/code/modules/unit_tests/tail_wag.dm new file mode 100644 index 00000000000000..0d828557953d63 --- /dev/null +++ b/code/modules/unit_tests/tail_wag.dm @@ -0,0 +1,90 @@ +/// Tests to make sure tail wagging behaves as expected +/datum/unit_test/tail_wag + // used by the stop_after test + var/timer_finished = FALSE + +/datum/unit_test/tail_wag/Run() + var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent) + var/obj/item/organ/external/tail/cat/dummy_tail = allocate(/obj/item/organ/external/tail/cat) + dummy_tail.Insert(dummy, special = TRUE, drop_if_replaced = FALSE) + + // SANITY TEST + + // start wagging + SEND_SIGNAL(dummy, COMSIG_ORGAN_WAG_TAIL, TRUE) + if(!(dummy_tail.wag_flags & WAG_WAGGING)) + TEST_FAIL("Tail did not start wagging when it should have!") + + // stop wagging + SEND_SIGNAL(dummy, COMSIG_ORGAN_WAG_TAIL, FALSE) + if(dummy_tail.wag_flags & WAG_WAGGING) + TEST_FAIL("Tail did not stop wagging when it should have!") + + // TESTING WAG_ABLE FLAG + + // flip the wag flag to unwaggable + dummy_tail.wag_flags &= ~WAG_ABLE + + // try to wag it again + SEND_SIGNAL(dummy, COMSIG_ORGAN_WAG_TAIL, TRUE) + if(dummy_tail.wag_flags & WAG_WAGGING) + TEST_FAIL("Tail should not have the ability to wag, yet it did!") + + // flip the wag flag to waggable again + dummy_tail.wag_flags |= WAG_ABLE + + // start wagging again + SEND_SIGNAL(dummy, COMSIG_ORGAN_WAG_TAIL, TRUE) + if(!(dummy_tail.wag_flags & WAG_WAGGING)) + TEST_FAIL("Tail did not start wagging when it should have!") + + // TESTING STOP_AFTER + + // stop wagging + SEND_SIGNAL(dummy, COMSIG_ORGAN_WAG_TAIL, FALSE) + if(dummy_tail.wag_flags & WAG_WAGGING) + TEST_FAIL("Tail did not stop wagging when it should have!") + + // start wagging, stop after 0.1 seconds + SEND_SIGNAL(dummy, COMSIG_ORGAN_WAG_TAIL, TRUE, 0.1 SECONDS) + // because timers are a pain + addtimer(VARSET_CALLBACK(src, timer_finished, TRUE), 0.2 SECONDS) + if(!(dummy_tail.wag_flags & WAG_WAGGING)) + TEST_FAIL("Tail did not start wagging when it should have!") + + UNTIL(timer_finished) // wait a little bit + + if(dummy_tail.wag_flags & WAG_WAGGING) + TEST_FAIL("Tail was supposed to stop wagging on its own after 0.1 seconds but it did not!") + + // TESTING TAIL REMOVAL + + // remove the tail + dummy_tail.Remove(dummy, special = TRUE) + + // check if tail is still wagging after being removed + if(dummy_tail.wag_flags & WAG_WAGGING) + TEST_FAIL("Tail was still wagging after being removed!") + + // try to wag the removed tail + SEND_SIGNAL(dummy, COMSIG_ORGAN_WAG_TAIL, TRUE) + if(dummy_tail.wag_flags & WAG_WAGGING) + TEST_FAIL("A disembodied tail was able to start wagging!") + + // TESTING MOB DEATH + + // put it back and start wagging again + dummy_tail.Insert(dummy, special = TRUE, drop_if_replaced = FALSE) + SEND_SIGNAL(dummy, COMSIG_ORGAN_WAG_TAIL, TRUE) + if(!(dummy_tail.wag_flags & WAG_WAGGING)) + TEST_FAIL("Tail did not start wagging when it should have!") + + // kill the mob, see if it stops wagging + dummy.adjustBruteLoss(9001) + if(dummy_tail.wag_flags & WAG_WAGGING) + TEST_FAIL("A mob's tail was still wagging after being killed!") + + // check if we are still able to wag the tail after death + SEND_SIGNAL(dummy, COMSIG_ORGAN_WAG_TAIL, TRUE) + if(dummy_tail.wag_flags & WAG_WAGGING) + TEST_FAIL("A dead mob was able to wag their tail!") diff --git a/code/modules/uplink/uplink_items/badass.dm b/code/modules/uplink/uplink_items/badass.dm index 67676edcd7da9f..458747a2a7b3f1 100644 --- a/code/modules/uplink/uplink_items/badass.dm +++ b/code/modules/uplink/uplink_items/badass.dm @@ -22,7 +22,12 @@ if(!.) return - notify_ghosts("[user] has purchased a BADASS Syndicate Balloon!", source = src, action = NOTIFY_ORBIT, header = "What are they THINKING?") + notify_ghosts( + "[user] has purchased a BADASS Syndicate Balloon!", + source = src, + action = NOTIFY_ORBIT, + header = "What are they THINKING?", + ) /datum/uplink_item/badass/syndiecards name = "Syndicate Playing Cards" diff --git a/code/modules/uplink/uplink_items/dangerous.dm b/code/modules/uplink/uplink_items/dangerous.dm index f1788c6e1dec32..e84657e7884f94 100644 --- a/code/modules/uplink/uplink_items/dangerous.dm +++ b/code/modules/uplink/uplink_items/dangerous.dm @@ -82,7 +82,7 @@ desc = "Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, they require an \ organic host as a home base and source of fuel. Holoparasites come in various types and share damage with their host." progression_minimum = 30 MINUTES - item = /obj/item/guardiancreator/tech/choose/traitor + item = /obj/item/guardian_creator/tech cost = 18 surplus = 0 purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm index 96a1c13827f548..2073024a962dd7 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -146,6 +146,13 @@ cost = 11 restricted_roles = list(JOB_STATION_ENGINEER, JOB_CHIEF_ENGINEER) +/datum/uplink_item/role_restricted/rebarxbowsyndie + name = "Syndicate Rebar Crossbow" + desc = "A much more proffessional version of the engineer's bootleg rebar crossbow. 3 shot mag, quicker loading, and better ammo. Owners manual included." + item = /obj/item/storage/box/syndie_kit/rebarxbowsyndie + cost = 10 + restricted_roles = list(JOB_STATION_ENGINEER, JOB_CHIEF_ENGINEER) + /datum/uplink_item/role_restricted/magillitis_serum name = "Magillitis Serum Autoinjector" desc = "A single-use autoinjector which contains an experimental serum that causes rapid muscular growth in Hominidae. \ diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm index 78dedc0c07261b..df7fd7c5f2dcbd 100644 --- a/code/modules/uplink/uplink_items/nukeops.dm +++ b/code/modules/uplink/uplink_items/nukeops.dm @@ -42,6 +42,21 @@ // ~~ Weapon Categories ~~ +// Core Gear Box: This contains all the 'fundamental' equipment that most nuclear operatives probably should be buying. It isn't cheaper, but it is a quick and convenient method of acquiring all the gear necessary immediately. +// Only allows one purchase, and doesn't prevent the purchase of the contained items. Focused on newer players to help them understand what items they need to succeed, and to help older players quickly purchase the baseline gear they need. + +/datum/uplink_item/weapon_kits/core + name = "Core Equipment Box (Essential)" + desc = "This box contains an airlock authentification override card, a C-4 explosive charge, a freedom implant and a stimpack injector. \ + The most important support items for most operatives to succeed in their mission, bundled together. It is highly recommend you buy this kit. \ + Note: This bundle is not at a discount. You can purchase all of these items separately. You do not NEED these items, but most operatives fail WITHOUT at \ + least SOME of these items. More experienced operatives can do without." + item = /obj/item/storage/box/syndie_kit/core_gear + cost = 14 //freedom 5, doormag 3, c-4 1, stimpack 5 + limited_stock = 1 + cant_discount = TRUE + purchasable_from = UPLINK_NUKE_OPS + //Low-cost firearms: Around 8 TC each. Meant for easy squad weapon purchases /datum/uplink_item/weapon_kits/low_cost @@ -153,7 +168,7 @@ cost = 4 purchasable_from = UPLINK_NUKE_OPS -// ~~ Energy Sword and Shield ~~ +// ~~ Energy Sword and Shield & CQC ~~ /datum/uplink_item/weapon_kits/medium_cost/sword_and_board name = "Energy Shield and Sword Case (Very Hard)" @@ -161,6 +176,13 @@ energy and laser projectiles, and the sword most forms of attack. Perfect for the enterprising nuclear knight. " item = /obj/item/storage/toolbox/guncase/sword_and_board +/datum/uplink_item/weapon_kits/medium_cost/cqc + name = "CQC Equipment Case (Very Hard)" + desc = "Contains a manual that instructs you in the ways of CQC, or Close Quarters Combat. Comes with a stealth implant, a pack of smokes and a snazzy bandana (use it with the hat stabilizers in your MODsuit)." + item = /obj/item/storage/toolbox/guncase/cqc + purchasable_from = UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS + surplus = 0 + // ~~ Syndicate Revolver ~~ // Nuclear operatives get a special deal on their revolver purchase compared to traitors. @@ -331,13 +353,6 @@ Blast your enemies with instant shots! Just watch out for the rebound..." item = /obj/item/ammo_box/magazine/sniper_rounds/marksman -/datum/uplink_item/weapon_kits/high_cost/cqc - name = "CQC Equipment Case (Very Hard)" - desc = "Contains a manual that instructs you in the ways of CQC, or Close Quarters Combat. Comes with a stealth implant and a snazzy bandana (and a hat stabilizer to go with it)." - item = /obj/item/storage/toolbox/guncase/cqc - purchasable_from = UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS - surplus = 0 - /datum/uplink_item/weapon_kits/high_cost/doublesword name = "Double-Energy Sword Case (Very Hard)" desc = "A case containing a double-energy sword, anti-slip module, meth autoinjector, and a bar of soap. \ @@ -803,7 +818,7 @@ /datum/uplink_item/badass/hats name = "Hat Crate" - desc = "Hat crate! Contains hats, along with hat stabilizers to wear your hats while you're in your suit! HATS!!!" + desc = "Hat crate! Contains hats! HATS!!!" item = /obj/structure/closet/crate/large/hats cost = 5 purchasable_from = UPLINK_CLOWN_OPS | UPLINK_NUKE_OPS diff --git a/code/modules/uplink/uplink_items/stealthy.dm b/code/modules/uplink/uplink_items/stealthy.dm index 2f205a9d0bd692..36cb47cc28f464 100644 --- a/code/modules/uplink/uplink_items/stealthy.dm +++ b/code/modules/uplink/uplink_items/stealthy.dm @@ -76,7 +76,7 @@ and gain the ability to swat bullets from the air, but you will also refuse to use dishonorable ranged weaponry." item = /obj/item/book/granter/martial/carp progression_minimum = 30 MINUTES - cost = 13 + cost = 17 surplus = 0 purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm index 1fd230bb47a82e..6b019cac27059b 100644 --- a/code/modules/vehicles/cars/clowncar.dm +++ b/code/modules/vehicles/cars/clowncar.dm @@ -198,7 +198,7 @@ * * Fart and make everyone nearby laugh */ /obj/vehicle/sealed/car/clowncar/proc/roll_the_dice(mob/user) - if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_CLOWNCAR_RANDOMNESS)) + if(TIMER_COOLDOWN_RUNNING(src, COOLDOWN_CLOWNCAR_RANDOMNESS)) to_chat(user, span_notice("The button panel is currently recharging.")) return TIMER_COOLDOWN_START(src, COOLDOWN_CLOWNCAR_RANDOMNESS, dice_cooldown_time) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 573e09f347df6a..f586a9656e82b9 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -682,7 +682,7 @@ if(!(livinguser in return_controllers_with_flag(VEHICLE_CONTROL_MELEE))) to_chat(livinguser, span_warning("You're in the wrong seat to interact with your hands.")) return - var/on_cooldown = TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MELEE_ATTACK) + var/on_cooldown = TIMER_COOLDOWN_RUNNING(src, COOLDOWN_MECHA_MELEE_ATTACK) var/adjacent = Adjacent(target) if(SEND_SIGNAL(src, COMSIG_MECHA_MELEE_CLICK, livinguser, target, on_cooldown, adjacent) & COMPONENT_CANCEL_MELEE_CLICK) return @@ -749,7 +749,7 @@ balloon_alert(user, "cabin can't be sealed!") log_message("Tried to seal cabin. This mech can't be airtight.", LOG_MECHA) return - if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_CABIN_SEAL)) + if(TIMER_COOLDOWN_RUNNING(src, COOLDOWN_MECHA_CABIN_SEAL)) balloon_alert(user, "on cooldown!") return TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_CABIN_SEAL, 1 SECONDS) diff --git a/code/modules/vehicles/mecha/combat/marauder.dm b/code/modules/vehicles/mecha/combat/marauder.dm index 79b09568994303..2fe8da4bdc73c3 100644 --- a/code/modules/vehicles/mecha/combat/marauder.dm +++ b/code/modules/vehicles/mecha/combat/marauder.dm @@ -61,7 +61,7 @@ /datum/action/vehicle/sealed/mecha/mech_smoke/Trigger(trigger_flags) if(!owner || !chassis || !(owner in chassis.occupants)) return - if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_SMOKE) && chassis.smoke_charges>0) + if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_SMOKE) && chassis.smoke_charges>0) chassis.smoke_system.start() chassis.smoke_charges-- TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_SMOKE, chassis.smoke_cooldown) diff --git a/code/modules/vehicles/mecha/combat/savannah_ivanov.dm b/code/modules/vehicles/mecha/combat/savannah_ivanov.dm index e3926aa7d3502e..1aa4223b98c644 100644 --- a/code/modules/vehicles/mecha/combat/savannah_ivanov.dm +++ b/code/modules/vehicles/mecha/combat/savannah_ivanov.dm @@ -86,7 +86,7 @@ if(chassis.phasing) to_chat(owner, span_warning("You're already airborne!")) return - if(TIMER_COOLDOWN_CHECK(chassis, COOLDOWN_MECHA_SKYFALL)) + if(TIMER_COOLDOWN_RUNNING(chassis, COOLDOWN_MECHA_SKYFALL)) var/timeleft = S_TIMER_COOLDOWN_TIMELEFT(chassis, COOLDOWN_MECHA_SKYFALL) to_chat(owner, span_warning("You need to wait [DisplayTimeText(timeleft, 1)] before attempting to Skyfall.")) return @@ -254,7 +254,7 @@ /datum/action/vehicle/sealed/mecha/ivanov_strike/Trigger(trigger_flags) if(!owner || !chassis || !(owner in chassis.occupants)) return - if(TIMER_COOLDOWN_CHECK(chassis, COOLDOWN_MECHA_MISSILE_STRIKE)) + if(TIMER_COOLDOWN_RUNNING(chassis, COOLDOWN_MECHA_MISSILE_STRIKE)) var/timeleft = S_TIMER_COOLDOWN_TIMELEFT(chassis, COOLDOWN_MECHA_MISSILE_STRIKE) to_chat(owner, span_warning("You need to wait [DisplayTimeText(timeleft, 1)] before firing another Ivanov Strike.")) return @@ -292,7 +292,7 @@ /** * ## end_missile_targeting * - * Called by the ivanov strike datum action or other actions that would end targetting + * Called by the ivanov strike datum action or other actions that would end targeting * Unhooks signals into clicking to call drop_missile plus other flavor like the overlay */ /datum/action/vehicle/sealed/mecha/ivanov_strike/proc/end_missile_targeting() diff --git a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm index f9ee84ba4b893f..6c8d178c5b9918 100644 --- a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm +++ b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm @@ -107,7 +107,7 @@ if(get_integrity() <= 1) to_chat(chassis.occupants, span_warning("Error -- Equipment critically damaged.")) return FALSE - if(TIMER_COOLDOWN_CHECK(chassis, COOLDOWN_MECHA_EQUIPMENT(type))) + if(TIMER_COOLDOWN_RUNNING(chassis, COOLDOWN_MECHA_EQUIPMENT(type))) return FALSE return TRUE @@ -121,7 +121,7 @@ * Cooldown proc variant for using do_afters between activations instead of timers * Example of usage is mech drills, rcds * arguments: - * * target: targetted atom for action activation + * * target: targeted atom for action activation * * user: occupant to display do after for * * interaction_key: interaction key to pass to [/proc/do_after] */ diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm index 0c8fad8a255e60..b7ddb1f6c57bcd 100644 --- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm @@ -14,36 +14,35 @@ harmful = TRUE mech_flags = EXOSUIT_MODULE_RIPLEY ///Bool for whether we beat the hell out of things we punch (and tear off their arms) - //var/killer_clamp = FALSE -------SKYRAT EDIT - A clamp is a clamp, just like it was on the oldbase. var/killer_clamp = TRUE ///How much base damage this clamp does - var/clamp_damage = 30 //SKYRAT EDIT - We've removed instant arm delimbs, so this is a buff to make up for it. -// var/clamp_damage = 20 SKYRAT EDIT - Original line + var/clamp_damage = 20 ///Var for the chassis we are attached to, needed to access ripley contents and such var/obj/vehicle/sealed/mecha/ripley/cargo_holder ///Audio for using the hydraulic clamp var/clampsound = 'sound/mecha/hydraulic.ogg' + ///Chassis but typed for the cargo_hold var + var/obj/vehicle/sealed/mecha/ripley/workmech /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/attach(obj/vehicle/sealed/mecha/new_mecha) . = ..() - if(istype(chassis, /obj/vehicle/sealed/mecha/ripley)) - cargo_holder = chassis + workmech = chassis ADD_TRAIT(chassis, TRAIT_OREBOX_FUNCTIONAL, TRAIT_MECH_EQUIPMENT(type)) /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/detach(atom/moveto) REMOVE_TRAIT(chassis, TRAIT_OREBOX_FUNCTIONAL, TRAIT_MECH_EQUIPMENT(type)) - cargo_holder = null + workmech = null return ..() /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/action(mob/living/source, atom/target, list/modifiers) if(!action_checks(target)) return - if(!cargo_holder) - return + if(!workmech.cargo_hold) + CRASH("Mech [chassis] has a clamp device, but no internal storage. This should be impossible.") if(ismecha(target)) var/obj/vehicle/sealed/mecha/M = target var/have_ammo - for(var/obj/item/mecha_ammo/box in cargo_holder.cargo) + for(var/obj/item/mecha_ammo/box in workmech.cargo_hold.contents) if(istype(box, /obj/item/mecha_ammo) && box.rounds) have_ammo = TRUE if(M.ammo_resupply(box, source, TRUE)) @@ -68,7 +67,7 @@ if(clamptarget.anchored) to_chat(source, "[icon2html(src, source)][span_warning("[target] is firmly secured!")]") return - if(LAZYLEN(cargo_holder.cargo) >= cargo_holder.cargo_capacity) + if(workmech.cargo_hold.contents.len >= workmech.cargo_hold.cargo_capacity) to_chat(source, "[icon2html(src, source)][span_warning("Not enough room in cargo compartment!")]") return playsound(chassis, clampsound, 50, FALSE, -6) @@ -77,13 +76,12 @@ if(!do_after_cooldown(target, source)) clamptarget.set_anchored(initial(clamptarget.anchored)) return - LAZYADD(cargo_holder.cargo, clamptarget) - clamptarget.forceMove(chassis) + clamptarget.forceMove(workmech.cargo_hold) clamptarget.set_anchored(FALSE) - if(!cargo_holder.ore_box && istype(clamptarget, /obj/structure/ore_box)) - cargo_holder.ore_box = clamptarget + if(!chassis.ore_box && istype(clamptarget, /obj/structure/ore_box)) + chassis.ore_box = clamptarget to_chat(source, "[icon2html(src, source)][span_notice("[target] successfully loaded.")]") - log_message("Loaded [clamptarget]. Cargo compartment capacity: [cargo_holder.cargo_capacity - LAZYLEN(cargo_holder.cargo)]", LOG_MECHA) + log_message("Loaded [clamptarget]. Cargo compartment capacity: [workmech.cargo_hold.cargo_capacity - workmech.cargo_hold.contents.len]", LOG_MECHA) else if(isliving(target)) var/mob/living/M = target @@ -334,15 +332,17 @@ //Dunno where else to put this so shrug /obj/item/mecha_parts/mecha_equipment/ripleyupgrade name = "Ripley MK-II Conversion Kit" - desc = "A pressurized canopy attachment kit for an Autonomous Power Loader Unit \"Ripley\" MK-I mecha, to convert it to the slower, but space-worthy MK-II design. This kit cannot be removed, once applied." + desc = "A pressurized canopy attachment kit for an Autonomous Power Loader Unit \"Ripley\" MK-I exosuit, to convert it to the slower, but space-worthy MK-II design. This kit cannot be removed, once applied." icon_state = "ripleyupgrade" mech_flags = EXOSUIT_MODULE_RIPLEY + var/result = /obj/vehicle/sealed/mecha/ripley/mk2 /obj/item/mecha_parts/mecha_equipment/ripleyupgrade/can_attach(obj/vehicle/sealed/mecha/ripley/mecha, attach_right = FALSE, mob/user) if(mecha.type != /obj/vehicle/sealed/mecha/ripley) to_chat(user, span_warning("This conversion kit can only be applied to APLU MK-I models.")) return FALSE - if(LAZYLEN(mecha.cargo)) + var/obj/vehicle/sealed/mecha/ripley/workmech = mecha + if(LAZYLEN(workmech.cargo_hold)) to_chat(user, span_warning("[mecha]'s cargo hold must be empty before this conversion kit can be applied.")) return FALSE if(!(mecha.mecha_flags & PANEL_OPEN)) //non-removable upgrade, so lets make sure the pilot or owner has their say. @@ -357,43 +357,56 @@ return TRUE /obj/item/mecha_parts/mecha_equipment/ripleyupgrade/attach(obj/vehicle/sealed/mecha/markone, attach_right = FALSE) - var/obj/vehicle/sealed/mecha/ripley/mk2/marktwo = new (get_turf(markone),1) - if(!marktwo) + var/obj/vehicle/sealed/mecha/newmech = new result(get_turf(markone),1) + if(!newmech) return - QDEL_NULL(marktwo.cell) + QDEL_NULL(newmech.cell) if (markone.cell) - marktwo.cell = markone.cell - markone.cell.forceMove(marktwo) + newmech.cell = markone.cell + markone.cell.forceMove(newmech) markone.cell = null - QDEL_NULL(marktwo.scanmod) + QDEL_NULL(newmech.scanmod) if (markone.scanmod) - marktwo.scanmod = markone.scanmod - markone.scanmod.forceMove(marktwo) + newmech.scanmod = markone.scanmod + markone.scanmod.forceMove(newmech) markone.scanmod = null - QDEL_NULL(marktwo.capacitor) + QDEL_NULL(newmech.capacitor) if (markone.capacitor) - marktwo.capacitor = markone.capacitor - markone.capacitor.forceMove(marktwo) + newmech.capacitor = markone.capacitor + markone.capacitor.forceMove(newmech) markone.capacitor = null - QDEL_NULL(marktwo.servo) + QDEL_NULL(newmech.servo) if (markone.servo) - marktwo.servo = markone.servo - markone.servo.forceMove(marktwo) + newmech.servo = markone.servo + markone.servo.forceMove(newmech) markone.servo = null - marktwo.update_part_values() + newmech.update_part_values() for(var/obj/item/mecha_parts/mecha_equipment/equipment in markone.flat_equipment) //Move the equipment over... if(istype(equipment, /obj/item/mecha_parts/mecha_equipment/ejector)) - continue //the MK2 already has one. + continue //the new mech already has one. var/righthandgun = markone.equip_by_category[MECHA_R_ARM] == equipment - equipment.detach(marktwo) - equipment.attach(marktwo, righthandgun) - marktwo.dna_lock = markone.dna_lock - marktwo.mecha_flags = markone.mecha_flags - marktwo.strafe = markone.strafe + equipment.detach(newmech) + equipment.attach(newmech, righthandgun) + newmech.dna_lock = markone.dna_lock + newmech.mecha_flags = markone.mecha_flags + newmech.strafe = markone.strafe //Integ set to the same percentage integ as the old mecha, rounded to be whole number - marktwo.update_integrity(round((markone.get_integrity() / markone.max_integrity) * marktwo.get_integrity())) + newmech.update_integrity(round((markone.get_integrity() / markone.max_integrity) * newmech.get_integrity())) if(markone.name != initial(markone.name)) - marktwo.name = markone.name + newmech.name = markone.name markone.wreckage = FALSE qdel(markone) - playsound(get_turf(marktwo),'sound/items/ratchet.ogg',50,TRUE) + playsound(get_turf(newmech),'sound/items/ratchet.ogg',50,TRUE) + +/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/paddy + name = "Paddy Conversion Kit" + desc = "A hardpoint modification kit for an Autonomous Power Loader Unit \"Ripley\" MK-I exosuit, to convert it to the Paddy lightweight security design. This kit cannot be removed, once applied." + icon_state = "paddyupgrade" + mech_flags = EXOSUIT_MODULE_RIPLEY + result = /obj/vehicle/sealed/mecha/ripley/paddy + +/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/paddy/can_attach(obj/vehicle/sealed/mecha/ripley/mecha, attach_right = FALSE, mob/user) + if(mecha.equip_by_category[MECHA_L_ARM] || mecha.equip_by_category[MECHA_R_ARM]) //Paddys can't use RIPLEY-type equipment + to_chat(user, span_warning("This kit cannot be applied with hardpoint equipment attached.")) + return FALSE + return ..() diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index a879341629650c..bd2198025151fd 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -540,3 +540,76 @@ equip_cooldown = 60 det_time = 20 mech_flags = EXOSUIT_MODULE_HONK + +///long claw of the law +/obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw + name = "hydraulic claw" + desc = "A modified hydraulic clamp, for use exclusively with the Paddy exosuit. Non-lethally apprehends suspects." + icon_state = "paddy_claw" + equip_cooldown = 15 + energy_drain = 10 + tool_behaviour = TOOL_RETRACTOR + range = MECHA_MELEE + toolspeed = 0.8 + mech_flags = EXOSUIT_MODULE_PADDY + ///Chassis but typed for the cargo_hold var + var/obj/vehicle/sealed/mecha/ripley/secmech + ///Audio for using the hydraulic clamp + var/clampsound = 'sound/mecha/hydraulic.ogg' + ///Var for the cuff type. Basically stole how cuffing works from secbots + var/cuff_type = /obj/item/restraints/handcuffs/cable/zipties/used + ///Var for autocuff, can be toggled in the mech interface. + var/autocuff = TRUE + + +/obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/attach(obj/vehicle/sealed/mecha/new_mecha) + . = ..() + secmech = chassis + +/obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/detach(atom/moveto) + secmech = null + return ..() + +/obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/action(mob/living/source, atom/target, list/modifiers) + if(!secmech.cargo_hold) //We did try + CRASH("Mech [chassis] has a claw device, but no internal storage. This should be impossible.") + if(ismob(target)) + var/mob/living/mobtarget = target + if(mobtarget.move_resist == MOVE_FORCE_OVERPOWERING) //No megafauna or bolted AIs, please. + to_chat(source, "[span_warning("[src] is unable to lift [mobtarget].")]") + return + if(secmech.cargo_hold.contents.len >= secmech.cargo_hold.cargo_capacity) + to_chat(source, "[icon2html(src, source)][span_warning("Not enough room in cargo compartment!")]") + return + + playsound(chassis, clampsound, 50, FALSE, -6) + mobtarget.visible_message(span_notice("[chassis] lifts [mobtarget] into its internal holding cell."),span_userdanger("[chassis] grips you with [src] and prepares to load you into [secmech.cargo_hold]!")) + if(!do_after_cooldown(mobtarget, source)) + return + mobtarget.forceMove(secmech.cargo_hold) + log_message("Loaded [mobtarget]. Cargo compartment capacity: [secmech.cargo_hold.cargo_capacity - secmech.cargo_hold.contents.len]", LOG_MECHA) + to_chat(source, "[icon2html(src, source)][span_notice("[mobtarget] successfully loaded.")]") + to_chat(mobtarget, "[span_warning("You have been moved into [secmech.cargo_hold]. You can attempt to resist out if you wish.")]") + if(autocuff && iscarbon(target)) + var/mob/living/carbon/carbontarget = target + carbontarget.set_handcuffed(new cuff_type(carbontarget)) + carbontarget.update_handcuffed() + return + + if(!istype(target, /obj/machinery/door)) + return + var/obj/machinery/door/target_door = target + playsound(chassis, clampsound, 50, FALSE, -6) + target_door.try_to_crowbar(src, source) + +/obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/get_snowflake_data() + return list( + "snowflake_id" = MECHA_SNOWFLAKE_ID_CLAW, + "autocuff" = autocuff, + ) + +/obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/handle_ui_act(action, list/params) + switch(action) + if("togglecuff") + autocuff = !autocuff + return TRUE diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm index 56b3cd2138c5ed..a840f75ad86ae9 100644 --- a/code/modules/vehicles/mecha/mech_fabricator.dm +++ b/code/modules/vehicles/mecha/mech_fabricator.dm @@ -403,9 +403,6 @@ . = TRUE - add_fingerprint(usr) - usr.set_machine(src) - switch(action) if("build") var/designs = params["designs"] diff --git a/code/modules/vehicles/mecha/mecha_construction_paths.dm b/code/modules/vehicles/mecha/mecha_construction_paths.dm index fb572f7d1282e5..3ff01b511669d7 100644 --- a/code/modules/vehicles/mecha/mecha_construction_paths.dm +++ b/code/modules/vehicles/mecha/mecha_construction_paths.dm @@ -503,7 +503,7 @@ list( "key" = /obj/item/circuitboard/mecha/honker/targeting, "action" = ITEM_DELETE, - "desc" = "Prank targetting board can be added!", + "desc" = "Prank targeting board can be added!", "forward_message" = "added prank" ), list( diff --git a/code/modules/vehicles/mecha/mecha_control_console.dm b/code/modules/vehicles/mecha/mecha_control_console.dm index 771ed97268bfda..6cb5ec6bde8533 100644 --- a/code/modules/vehicles/mecha/mecha_control_console.dm +++ b/code/modules/vehicles/mecha/mecha_control_console.dm @@ -36,9 +36,9 @@ tracker_ref = REF(MT) ) if(istype(M, /obj/vehicle/sealed/mecha/ripley)) - var/obj/vehicle/sealed/mecha/ripley/RM = M + var/obj/vehicle/sealed/mecha/ripley/workmech = M mech_data += list( - cargo_space = round((LAZYLEN(RM.cargo) / RM.cargo_capacity) * 100) + cargo_space = round(workmech.cargo_hold.contents.len / workmech.cargo_hold.cargo_capacity * 100) ) data["mechs"] += list(mech_data) @@ -101,8 +101,8 @@ Pilot: [english_list(chassis.return_drivers(), nothing_text = "None")]
Location: [get_area_name(chassis, TRUE) || "Unknown"]"} if(istype(chassis, /obj/vehicle/sealed/mecha/ripley)) - var/obj/vehicle/sealed/mecha/ripley/RM = chassis - answer += "
Used Cargo Space: [round((LAZYLEN(RM.cargo) / RM.cargo_capacity * 100), 0.01)]%" + var/obj/item/mecha_parts/mecha_equipment/ejector/cargo_holder = locate(/obj/item/mecha_parts/mecha_equipment/ejector) in chassis.equip_by_category[MECHA_UTILITY] + answer += "
Used Cargo Space: [round((cargo_holder.contents.len / cargo_holder.cargo_capacity * 100), 0.01)]%" return answer diff --git a/code/modules/vehicles/mecha/mecha_damage.dm b/code/modules/vehicles/mecha/mecha_damage.dm index 08f294f202f94f..8a06aaf298fa51 100644 --- a/code/modules/vehicles/mecha/mecha_damage.dm +++ b/code/modules/vehicles/mecha/mecha_damage.dm @@ -9,7 +9,7 @@ * Pretty simple, adds armor, you can choose against what * ## Internal damage * When taking damage will force you to take some time to repair, encourages improvising in a fight - * Targetting different def zones will damage them to encurage a more strategic approach to fights + * Targeting different def zones will damage them to encurage a more strategic approach to fights * where they target the "dangerous" modules */ diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm index 3df6ba94992d8f..746039e7552685 100644 --- a/code/modules/vehicles/mecha/mecha_defense.dm +++ b/code/modules/vehicles/mecha/mecha_defense.dm @@ -9,11 +9,11 @@ * Pretty simple, adds armor, you can choose against what * ## Internal damage * When taking damage will force you to take some time to repair, encourages improvising in a fight - * Targetting different def zones will damage them to encurage a more strategic approach to fights + * Targeting different def zones will damage them to encurage a more strategic approach to fights * where they target the "dangerous" modules */ -/// tries to damage mech equipment depending on damage and where is being targetted +/// tries to damage mech equipment depending on damage and where is being targeted /obj/vehicle/sealed/mecha/proc/try_damage_component(damage, def_zone) if(damage < component_damage_threshold) return diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm index d6c8feed4b3b96..e8c43ae48f94a3 100644 --- a/code/modules/vehicles/mecha/mecha_movement.dm +++ b/code/modules/vehicles/mecha/mecha_movement.dm @@ -70,14 +70,14 @@ return loc_atom.relaymove(src, direction) var/obj/machinery/portable_atmospherics/canister/internal_tank = get_internal_tank() if(internal_tank?.connected_port) - if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE)) to_chat(occupants, "[icon2html(src, occupants)][span_warning("Unable to move while connected to the air system port!")]") TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE if(!Process_Spacemove(direction)) return FALSE if(zoom_mode) - if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE)) to_chat(occupants, "[icon2html(src, occupants)][span_warning("Unable to move while in zoom mode!")]") TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE @@ -89,17 +89,17 @@ if(isnull(servo)) missing_parts += "micro-servo" if(length(missing_parts)) - if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE)) to_chat(occupants, "[icon2html(src, occupants)][span_warning("Missing [english_list(missing_parts)].")]") TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE if(!use_power(step_energy_drain)) - if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE)) to_chat(occupants, "[icon2html(src, occupants)][span_warning("Insufficient power to move!")]") TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE if(lavaland_only && is_mining_level(z)) - if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_MESSAGE)) + if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE)) to_chat(occupants, "[icon2html(src, occupants)][span_warning("Invalid Environment.")]") TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE diff --git a/code/modules/vehicles/mecha/mecha_wreckage.dm b/code/modules/vehicles/mecha/mecha_wreckage.dm index 3540891d336cde..8f3e821a5bfae6 100644 --- a/code/modules/vehicles/mecha/mecha_wreckage.dm +++ b/code/modules/vehicles/mecha/mecha_wreckage.dm @@ -165,6 +165,10 @@ name = "\improper Ripley MK-II wreckage" icon_state = "ripleymkii-broken" +/obj/structure/mecha_wreckage/ripley/paddy + name = "\improper Paddy wreckage" + icon_state = "paddy-broken" + /obj/structure/mecha_wreckage/clarke name = "\improper Clarke wreckage" icon_state = "clarke-broken" diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index d2b13d48d26ab3..456fa0709bdc15 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -35,10 +35,8 @@ ) /// Amount of Goliath hides attached to the mech var/hides = 0 - /// List of all things in Ripley's Cargo Compartment - var/list/cargo - /// How much things Ripley can carry in their Cargo Compartment - var/cargo_capacity = 15 + /// Reference to the Cargo Hold equipment. + var/obj/item/mecha_parts/mecha_equipment/ejector/cargo_hold /// How fast the mech is in low pressure var/fast_pressure_step_in = 1.5 /// How fast the mech is in normal pressure @@ -66,13 +64,6 @@ bullet = 5 laser = 5 -/obj/vehicle/sealed/mecha/ripley/Destroy() - for(var/atom/movable/A in cargo) - A.forceMove(drop_location()) - step_rand(A) - QDEL_LIST(cargo) - return ..() - /obj/vehicle/sealed/mecha/ripley/mk2 desc = "Autonomous Power Loader Unit MK-II. This prototype Ripley is refitted with a pressurized cabin, trading its prior speed for atmospheric protection and armor." name = "\improper APLU MK-II \"Ripley\"" @@ -99,6 +90,110 @@ fire = 100 acid = 100 +/obj/vehicle/sealed/mecha/ripley/paddy + desc = "Autonomous Power Loader Unit Subtype Paddy. A Modified MK-I Ripley design intended for light security use." + name = "\improper APLU \"Paddy\"" + icon_state = "paddy" + base_icon_state = "paddy" + max_temperature = 20000 + max_integrity = 250 + mech_type = EXOSUIT_MODULE_PADDY + possible_int_damage = MECHA_INT_FIRE|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT + accesses = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY) + armor_type = /datum/armor/mecha_paddy + wreckage = /obj/structure/mecha_wreckage/ripley/paddy + silicon_icon_state = "paddy-empty" + equip_by_category = list( + MECHA_L_ARM = null, + MECHA_R_ARM = null, + MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/ejector/seccage), + MECHA_POWER = list(), + MECHA_ARMOR = list(), + ) + ///Siren Lights/Sound State + var/siren = FALSE + ///Overlay for Siren Lights + var/mutable_appearance/sirenlights + ///Looping sound datum for the Siren audio + var/datum/looping_sound/siren/weewooloop + +/datum/armor/mecha_paddy + melee = 40 + bullet = 20 + laser = 10 + energy = 20 + bomb = 40 + fire = 100 + acid = 100 + +/obj/vehicle/sealed/mecha/ripley/paddy/Initialize(mapload) + . = ..() + weewooloop = new(src, FALSE, FALSE) + weewooloop.volume = 100 + +/obj/vehicle/sealed/mecha/ripley/paddy/generate_actions() + . = ..() + initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/siren) + +/obj/vehicle/sealed/mecha/ripley/paddy/mob_exit(mob/M, silent = FALSE, randomstep = FALSE, forced = FALSE) + var/obj/item/mecha_parts/mecha_equipment/ejector/seccage/cargo_holder = locate(/obj/item/mecha_parts/mecha_equipment/ejector/seccage) in equip_by_category[MECHA_UTILITY] + for(var/mob/contained in cargo_holder) + cargo_holder.cheese_it(contained) + togglesiren(force_off = TRUE) + return ..() + +/obj/vehicle/sealed/mecha/ripley/paddy/proc/togglesiren(force_off = FALSE) + if(force_off || siren) + weewooloop.stop() + siren = FALSE + else + weewooloop.start() + siren = TRUE + for(var/mob/occupant as anything in occupants) + balloon_alert(occupant, "siren [siren ? "activated" : "disabled"]") + var/datum/action/act = locate(/datum/action/vehicle/sealed/mecha/siren) in occupant.actions + act.button_icon_state = "mech_siren_[siren ? "on" : "off"]" + act.build_all_button_icons() + update_appearance(UPDATE_OVERLAYS) + +/obj/vehicle/sealed/mecha/ripley/paddy/update_overlays() + . = ..() + if(!siren) + return + sirenlights = new() + sirenlights.icon = icon + sirenlights.icon_state = "paddy_sirens" + SET_PLANE_EXPLICIT(sirenlights, ABOVE_LIGHTING_PLANE, src) + . += sirenlights + +/obj/vehicle/sealed/mecha/ripley/paddy/Destroy() + QDEL_NULL(weewooloop) + return ..() + +/datum/action/vehicle/sealed/mecha/siren + name = "Toggle External Siren and Lights" + button_icon_state = "mech_siren_off" + +/datum/action/vehicle/sealed/mecha/siren/New() + . = ..() + var/obj/vehicle/sealed/mecha/ripley/paddy/secmech = chassis + button_icon_state = "mech_siren_[secmech?.siren ? "on" : "off"]" + +/datum/action/vehicle/sealed/mecha/siren/Trigger(trigger_flags, forced_state = FALSE) + var/obj/vehicle/sealed/mecha/ripley/paddy/secmech = chassis + secmech.togglesiren() + +/obj/vehicle/sealed/mecha/ripley/paddy/preset + accesses = list(ACCESS_SECURITY) + mecha_flags = CANSTRAFE | IS_ENCLOSED | HAS_LIGHTS | MMI_COMPATIBLE | ID_LOCK_ON + equip_by_category = list( + MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/energy/disabler, + MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw, + MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/ejector/seccage), + MECHA_POWER = list(), + MECHA_ARMOR = list(), + ) + /obj/vehicle/sealed/mecha/ripley/deathripley desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE" name = "\improper DEATH-RIPLEY" @@ -193,37 +288,54 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo) servo = new /obj/item/stock_parts/servo(src) update_part_values() -/obj/vehicle/sealed/mecha/ripley/Exit(atom/movable/leaving, direction) - if(leaving in cargo) - return FALSE - return ..() - -/obj/vehicle/sealed/mecha/ripley/contents_explosion(severity, target) - for(var/i in cargo) - var/obj/cargoobj = i - if(prob(10 * severity)) - LAZYREMOVE(cargo, cargoobj) - cargoobj.forceMove(drop_location()) - return ..() - /obj/item/mecha_parts/mecha_equipment/ejector - name = "Cargo compartment" + name = "cargo compartment" desc = "Holds cargo loaded with a hydraulic clamp." icon_state = "mecha_bin" equipment_slot = MECHA_UTILITY detachable = FALSE + ///Number of atoms we can store + var/cargo_capacity = 15 + +/obj/item/mecha_parts/mecha_equipment/ejector/attach() + . = ..() + var/obj/vehicle/sealed/mecha/ripley/workmech = chassis + workmech.cargo_hold = src + + +/obj/item/mecha_parts/mecha_equipment/ejector/Destroy() + for(var/atom/stored in contents) + forceMove(stored, drop_location()) + step_rand(stored) + return ..() + +/obj/item/mecha_parts/mecha_equipment/ejector/contents_explosion(severity, target) + for(var/obj/stored in contents) + if(prob(10 * severity)) + stored.forceMove(drop_location()) + return ..() + +/obj/item/mecha_parts/mecha_equipment/ejector/relay_container_resist_act(mob/living/user, obj/container) + to_chat(user, span_notice("You lean on the back of [container] and start pushing so it falls out of [src].")) + if(do_after(user, 300, target = container)) + if(!user || user.stat != CONSCIOUS || user.loc != src || container.loc != src ) + return + to_chat(user, span_notice("You successfully pushed [container] out of [src]!")) + container.forceMove(drop_location()) + else + if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded. + to_chat(user, span_warning("You fail to push [container] out of [src]!")) /obj/item/mecha_parts/mecha_equipment/ejector/get_snowflake_data() - var/obj/vehicle/sealed/mecha/ripley/miner = chassis var/list/data = list( "snowflake_id" = MECHA_SNOWFLAKE_ID_EJECTOR, - "cargo_capacity" = miner.cargo_capacity, + "cargo_capacity" = cargo_capacity, "cargo" = list() ) - for(var/obj/crate in miner.cargo) + for(var/atom/entry in contents) data["cargo"] += list(list( - "name" = crate.name, - "ref" = REF(crate), + "name" = entry.name, + "ref" = REF(entry), )) return data @@ -232,30 +344,89 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo) if(.) return TRUE if(action == "eject") - var/obj/vehicle/sealed/mecha/ripley/miner = chassis - var/obj/crate = locate(params["cargoref"]) in miner.cargo + var/obj/crate = locate(params["cargoref"]) in contents if(!crate) return FALSE - to_chat(miner.occupants, "[icon2html(src, miner.occupants)][span_notice("You unload [crate].")]") + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("You unload [crate].")]") crate.forceMove(drop_location()) - LAZYREMOVE(miner.cargo, crate) - if(crate == miner.ore_box) - miner.ore_box = null + if(crate == chassis.ore_box) + chassis.ore_box = null playsound(chassis, 'sound/weapons/tap.ogg', 50, TRUE) - log_message("Unloaded [crate]. Cargo compartment capacity: [miner.cargo_capacity - LAZYLEN(miner.cargo)]", LOG_MECHA) + log_message("Unloaded [crate]. Cargo compartment capacity: [cargo_capacity - contents.len]", LOG_MECHA) return TRUE -/obj/vehicle/sealed/mecha/ripley/relay_container_resist_act(mob/living/user, obj/O) - to_chat(user, span_notice("You lean on the back of [O] and start pushing so it falls out of [src].")) - if(do_after(user, 300, target = O)) - if(!user || user.stat != CONSCIOUS || user.loc != src || O.loc != src ) - return - to_chat(user, span_notice("You successfully pushed [O] out of [src]!")) - O.forceMove(drop_location()) - LAZYREMOVE(cargo, O) - else - if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded. - to_chat(user, span_warning("You fail to push [O] out of [src]!")) +/obj/item/mecha_parts/mecha_equipment/ejector/seccage + name = "holding cell" + desc = "Holds suspects loaded with a hydraulic claw." + cargo_capacity = 4 + +/obj/item/mecha_parts/mecha_equipment/ejector/seccage/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOB_REMOVING_CUFFS, PROC_REF(stop_cuff_removal)) + +/obj/item/mecha_parts/mecha_equipment/ejector/seccage/Destroy() + UnregisterSignal(src, COMSIG_MOB_REMOVING_CUFFS) + for(var/mob/freebird in contents) //Let's not qdel people iside the mech kthx + cheese_it(freebird) + return ..() + +/obj/item/mecha_parts/mecha_equipment/ejector/seccage/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + RegisterSignal(arrived, COMSIG_MOB_REMOVING_CUFFS, PROC_REF(stop_cuff_removal)) + return ..() + +/obj/item/mecha_parts/mecha_equipment/ejector/seccage/Exited(atom/movable/gone, direction) + UnregisterSignal(gone, COMSIG_MOB_REMOVING_CUFFS) + return ..() + +/obj/item/mecha_parts/mecha_equipment/ejector/seccage/proc/stop_cuff_removal(datum/source, obj/item/cuffs) + SIGNAL_HANDLER + to_chat(source, span_warning("You don't have the room to remove [cuffs]!")) + return COMSIG_MOB_BLOCK_CUFF_REMOVAL + +/obj/item/mecha_parts/mecha_equipment/ejector/seccage/ui_act(action, list/params) + if(action == "eject") + var/mob/passenger = locate(params["cargoref"]) in contents + if(!passenger) + return FALSE + to_chat(chassis.occupants, "[icon2html(src, chassis.occupants)][span_notice("You unload [passenger].")]") + passenger.forceMove(drop_location()) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), passenger, chassis.dir), 1) //That's right, one tick. Just enough to cause the tile move animation. + playsound(chassis, 'sound/weapons/tap.ogg', 50, TRUE) + log_message("Unloaded [passenger]. Cargo compartment capacity: [cargo_capacity - contents.len]", LOG_MECHA) + return TRUE + return ..() + +/obj/item/mecha_parts/mecha_equipment/ejector/seccage/container_resist_act(mob/living/user) + to_chat(user, span_notice("You begin attempting a breakout. (This will take around 45 seconds and [chassis] need to remain stationary.)")) + if(!do_after(user, 1 MINUTES, target = chassis)) + return + to_chat(user, span_notice("You break out of the [src].")) + playsound(chassis, 'sound/items/crowbar.ogg', 100, TRUE) + cheese_it(user) + for(var/mob/freebird in contents) + if(user != freebird) + to_chat(freebird, span_warning("[user] has managed to open the hatch, and you fall out with him. You're free!")) + cheese_it(freebird) + +/obj/item/mecha_parts/mecha_equipment/ejector/seccage/proc/cheese_it(mob/living/escapee) + var/range = rand(1, 3) + var/variance = rand(-45, 45) + var/angle = 180 + var/turf/current_turf = get_turf(src) + switch (chassis?.dir) + if(NORTH) + angle = 270 + if(EAST) + angle = 180 + if(SOUTH) + angle = 90 + if(WEST) + angle = 0 + var/target_x = round(range * cos(angle + variance), 1) + current_turf.x + var/target_y = round(range * sin(angle + variance), 1) + current_turf.y + escapee.Knockdown(1) //Otherwise everyone hits eachother while being thrown + escapee.forceMove(drop_location()) + escapee.throw_at(locate(target_x, target_y, current_turf.z), range, 1) /** * Makes the mecha go faster and halves the mecha drill cooldown if in Lavaland pressure. diff --git a/code/modules/vehicles/vehicle_actions.dm b/code/modules/vehicles/vehicle_actions.dm index 1fbf394d2700aa..5afcd58c0c0ca6 100644 --- a/code/modules/vehicles/vehicle_actions.dm +++ b/code/modules/vehicles/vehicle_actions.dm @@ -232,7 +232,7 @@ var/hornsound = 'sound/items/carhorn.ogg' /datum/action/vehicle/sealed/horn/Trigger(trigger_flags) - if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_CAR_HONK)) + if(TIMER_COOLDOWN_RUNNING(src, COOLDOWN_CAR_HONK)) return TIMER_COOLDOWN_START(src, COOLDOWN_CAR_HONK, 2 SECONDS) vehicle_entered_target.visible_message(span_danger("[vehicle_entered_target] loudly honks!")) @@ -316,7 +316,7 @@ var/bell_cooldown /datum/action/vehicle/ridden/wheelchair/bell/Trigger(trigger_flags) - if(TIMER_COOLDOWN_CHECK(src, bell_cooldown)) + if(TIMER_COOLDOWN_RUNNING(src, bell_cooldown)) return TIMER_COOLDOWN_START(src, bell_cooldown, 0.5 SECONDS) playsound(vehicle_ridden_target, 'sound/machines/microwave/microwave-end.ogg', 70) diff --git a/code/modules/vending/megaseed.dm b/code/modules/vending/megaseed.dm index 8bdc7e637e25ab..130a0921a43a41 100644 --- a/code/modules/vending/megaseed.dm +++ b/code/modules/vending/megaseed.dm @@ -20,6 +20,7 @@ /obj/item/seeds/cocoapod = 3, /obj/item/seeds/eggplant = 3, /obj/item/seeds/grape = 3, + /obj/item/seeds/lanternfruit = 3, /obj/item/seeds/lemon = 3, /obj/item/seeds/lime = 3, /obj/item/seeds/olive = 3, diff --git a/code/modules/wiremod/components/action/pathfind.dm b/code/modules/wiremod/components/action/pathfind.dm index 9820d9b81e076a..0de6d346db17f8 100644 --- a/code/modules/wiremod/components/action/pathfind.dm +++ b/code/modules/wiremod/components/action/pathfind.dm @@ -77,7 +77,7 @@ return // If we're going to the same place and the cooldown hasn't subsided, we're probably on the same path as before - if (destination == old_dest && TIMER_COOLDOWN_CHECK(parent, COOLDOWN_CIRCUIT_PATHFIND_SAME)) + if (destination == old_dest && TIMER_COOLDOWN_RUNNING(parent, COOLDOWN_CIRCUIT_PATHFIND_SAME)) // Check if the current turf is the same as the current turf we're supposed to be in. If so, then we set the next step as the next turf on the list if(current_turf == next_turf) @@ -92,7 +92,7 @@ else // Either we're not going to the same place or the cooldown is over. Either way, we need a new path - if(destination != old_dest && TIMER_COOLDOWN_CHECK(parent, COOLDOWN_CIRCUIT_PATHFIND_DIF)) + if(destination != old_dest && TIMER_COOLDOWN_RUNNING(parent, COOLDOWN_CIRCUIT_PATHFIND_DIF)) failed.set_output(COMPONENT_SIGNAL) reason_failed.set_output("Cooldown still active!") return diff --git a/code/modules/wiremod/components/action/radio.dm b/code/modules/wiremod/components/action/radio.dm index 74b2c54c1b816d..3940059453ead4 100644 --- a/code/modules/wiremod/components/action/radio.dm +++ b/code/modules/wiremod/components/action/radio.dm @@ -74,7 +74,7 @@ INVOKE_ASYNC(src, PROC_REF(handle_radio_input), port) /obj/item/circuit_component/radio/proc/handle_radio_input(datum/port/input/port) - if(!TIMER_COOLDOWN_CHECK(parent, COOLDOWN_SIGNALLER_SEND)) + if(TIMER_COOLDOWN_RUNNING(parent, COOLDOWN_SIGNALLER_SEND)) return var/frequency = freq.value diff --git a/code/modules/wiremod/components/action/soundemitter.dm b/code/modules/wiremod/components/action/soundemitter.dm index 6ee9b273fae394..44b9cbae8ab05e 100644 --- a/code/modules/wiremod/components/action/soundemitter.dm +++ b/code/modules/wiremod/components/action/soundemitter.dm @@ -87,7 +87,7 @@ if(!parent.shell) return - if(TIMER_COOLDOWN_CHECK(parent.shell, COOLDOWN_CIRCUIT_SOUNDEMITTER)) + if(TIMER_COOLDOWN_RUNNING(parent.shell, COOLDOWN_CIRCUIT_SOUNDEMITTER)) return var/sound_to_play = options_map[sound_file.value] diff --git a/code/modules/wiremod/components/action/speech.dm b/code/modules/wiremod/components/action/speech.dm index 809c473c14a50e..4bf735cf82bf0a 100644 --- a/code/modules/wiremod/components/action/speech.dm +++ b/code/modules/wiremod/components/action/speech.dm @@ -26,7 +26,7 @@ if(!parent.shell) return - if(TIMER_COOLDOWN_CHECK(parent.shell, COOLDOWN_CIRCUIT_SPEECH)) + if(TIMER_COOLDOWN_RUNNING(parent.shell, COOLDOWN_CIRCUIT_SPEECH)) return if(message.value) diff --git a/code/modules/wiremod/components/bci/hud/target_intercept.dm b/code/modules/wiremod/components/bci/hud/target_intercept.dm index 8352b0aead991e..bfdaec13122a05 100644 --- a/code/modules/wiremod/components/bci/hud/target_intercept.dm +++ b/code/modules/wiremod/components/bci/hud/target_intercept.dm @@ -42,7 +42,7 @@ if(!owner || !istype(owner) || !owner.client) return - if(TIMER_COOLDOWN_CHECK(parent.shell, COOLDOWN_CIRCUIT_TARGET_INTERCEPT)) + if(TIMER_COOLDOWN_RUNNING(parent.shell, COOLDOWN_CIRCUIT_TARGET_INTERCEPT)) return to_chat(owner, "Left-click to trigger target interceptor!") diff --git a/code/modules/wiremod/components/list/assoc_list_pick.dm b/code/modules/wiremod/components/list/assoc_list_pick.dm index 9c8e94c074a630..64dbe6a0a0b65b 100644 --- a/code/modules/wiremod/components/list/assoc_list_pick.dm +++ b/code/modules/wiremod/components/list/assoc_list_pick.dm @@ -15,7 +15,6 @@ /obj/item/circuit_component/list_pick/assoc/make_list_port() input_list = add_input_port("List", PORT_TYPE_ASSOC_LIST(PORT_TYPE_STRING, PORT_TYPE_ANY)) - /obj/item/circuit_component/list_pick/assoc/pre_input_received(datum/port/input/port) if(port == list_options) var/new_type = list_options.value diff --git a/code/modules/wiremod/components/list/assoc_literal.dm b/code/modules/wiremod/components/list/assoc_literal.dm index a3f97cae745504..f829ad08f25ec3 100644 --- a/code/modules/wiremod/components/list/assoc_literal.dm +++ b/code/modules/wiremod/components/list/assoc_literal.dm @@ -39,20 +39,20 @@ /obj/item/circuit_component/assoc_literal/populate_ports() AddComponent(/datum/component/circuit_component_add_port, \ - port_list = entry_ports, \ + port_list = key_ports, \ add_action = "add", \ remove_action = "remove", \ - port_type = PORT_TYPE_ANY, \ - prefix = "Index", \ + port_type = PORT_TYPE_STRING, \ + prefix = "Key", \ minimum_amount = 1, \ maximum_amount = 20 \ ) AddComponent(/datum/component/circuit_component_add_port, \ - port_list = key_ports, \ + port_list = entry_ports, \ add_action = "add", \ remove_action = "remove", \ - port_type = PORT_TYPE_STRING, \ - prefix = "Key", \ + port_type = PORT_TYPE_ANY, \ + prefix = "Value", \ minimum_amount = 1, \ maximum_amount = 20 \ ) diff --git a/code/modules/wiremod/components/list/list_pick.dm b/code/modules/wiremod/components/list/list_pick.dm index bce3e82688f880..a1e8141f3c34ac 100644 --- a/code/modules/wiremod/components/list/list_pick.dm +++ b/code/modules/wiremod/components/list/list_pick.dm @@ -27,39 +27,24 @@ circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL - var/index_type = PORT_TYPE_NUMBER - -/obj/item/circuit_component/list_pick/populate_options() - list_options = add_option_port("List Type", GLOB.wiremod_basic_types) - /obj/item/circuit_component/list_pick/proc/make_list_port() - input_list = add_input_port("List", PORT_TYPE_LIST(PORT_TYPE_ANY)) + input_list = add_input_port("List", PORT_TYPE_LIST(PORT_TYPE_STRING)) /obj/item/circuit_component/list_pick/populate_ports() input_name = add_input_port("Input Name", PORT_TYPE_STRING) - user = add_input_port("User", PORT_TYPE_ATOM) + user = add_input_port("User", PORT_TYPE_USER) make_list_port() - output = add_output_port("Picked Item", PORT_TYPE_NUMBER) - trigger_output = add_output_port("Triggered", PORT_TYPE_SIGNAL) + output = add_output_port("Picked Item", PORT_TYPE_STRING) failure = add_output_port("On Failure", PORT_TYPE_SIGNAL) - success = add_output_port("On Succes", PORT_TYPE_SIGNAL) - - -/obj/item/circuit_component/list_pick/pre_input_received(datum/port/input/port) - if(port == list_options) - var/new_type = list_options.value - input_list.set_datatype(PORT_TYPE_LIST(new_type)) - output.set_datatype(new_type) - + success = add_output_port("On Success", PORT_TYPE_SIGNAL) /obj/item/circuit_component/list_pick/input_received(datum/port/input/port) - if(parent.Adjacent(user.value)) + var/mob/mob_user = user.value + if(!ismob(mob_user) || HAS_TRAIT_FROM(parent, TRAIT_CIRCUIT_UI_OPEN, REF(mob_user))) + failure.set_output(COMPONENT_SIGNAL) return - - if(ismob(user.value)) - trigger_output.set_output(COMPONENT_SIGNAL) - INVOKE_ASYNC(src, PROC_REF(show_list), user.value, input_name.value, input_list.value) + INVOKE_ASYNC(src, PROC_REF(show_list), mob_user, input_name.value, input_list.value) /// Show a list of options to the user using standed TGUI input list /obj/item/circuit_component/list_pick/proc/show_list(mob/user, message, list/showed_list) @@ -68,10 +53,17 @@ return if(!message) message = "circuit input" - if(!(user.can_perform_action(src, FORBID_TELEKINESIS_REACH))) + if(!(user.can_perform_action(parent.shell, FORBID_TELEKINESIS_REACH|ALLOW_SILICON_REACH|ALLOW_RESTING))) + failure.set_output(COMPONENT_SIGNAL) return + var/user_ref = REF(user) + ADD_TRAIT(parent, TRAIT_CIRCUIT_UI_OPEN, user_ref) var/picked = tgui_input_list(user, message = message, items = showed_list) - if(!(user.can_perform_action(src, FORBID_TELEKINESIS_REACH))) + REMOVE_TRAIT(parent, TRAIT_CIRCUIT_UI_OPEN, user_ref) + if(QDELETED(src)) + return + if(!(user.can_perform_action(parent.shell, FORBID_TELEKINESIS_REACH|ALLOW_SILICON_REACH|ALLOW_RESTING))) + failure.set_output(COMPONENT_SIGNAL) return choose_item(picked, showed_list) diff --git a/code/modules/wiremod/components/sensors/view_sensor.dm b/code/modules/wiremod/components/sensors/view_sensor.dm index f65853986e315f..1725044c035978 100644 --- a/code/modules/wiremod/components/sensors/view_sensor.dm +++ b/code/modules/wiremod/components/sensors/view_sensor.dm @@ -37,7 +37,7 @@ if(!parent.shell) return - if(TIMER_COOLDOWN_CHECK(parent.shell, COOLDOWN_CIRCUIT_VIEW_SENSOR)) + if(TIMER_COOLDOWN_RUNNING(parent.shell, COOLDOWN_CIRCUIT_VIEW_SENSOR)) result.set_output(null) cooldown.set_output(COMPONENT_SIGNAL) return diff --git a/code/modules/wiremod/datatypes/datum.dm b/code/modules/wiremod/datatypes/datum.dm index f3faa8f5d8e1cf..4045ee3793e66f 100644 --- a/code/modules/wiremod/datatypes/datum.dm +++ b/code/modules/wiremod/datatypes/datum.dm @@ -4,6 +4,7 @@ datatype_flags = DATATYPE_FLAG_ALLOW_MANUAL_INPUT|DATATYPE_FLAG_ALLOW_ATOM_INPUT can_receive_from = list( PORT_TYPE_ATOM, + PORT_TYPE_USER ) /datum/circuit_datatype/datum/convert_value(datum/port/port, value_to_convert) diff --git a/code/modules/wiremod/datatypes/entity.dm b/code/modules/wiremod/datatypes/entity.dm index e3a76892f97d93..437b3d7adb49c6 100644 --- a/code/modules/wiremod/datatypes/entity.dm +++ b/code/modules/wiremod/datatypes/entity.dm @@ -2,6 +2,9 @@ datatype = PORT_TYPE_ATOM color = "purple" datatype_flags = DATATYPE_FLAG_ALLOW_MANUAL_INPUT|DATATYPE_FLAG_ALLOW_ATOM_INPUT + can_receive_from = list( + PORT_TYPE_USER, + ) /datum/circuit_datatype/entity/convert_value(datum/port/port, value_to_convert) var/atom/object = value_to_convert diff --git a/code/modules/wiremod/datatypes/user.dm b/code/modules/wiremod/datatypes/user.dm new file mode 100644 index 00000000000000..693941dcd74099 --- /dev/null +++ b/code/modules/wiremod/datatypes/user.dm @@ -0,0 +1,9 @@ +/datum/circuit_datatype/user + datatype = PORT_TYPE_USER + color = "label" + +/datum/circuit_datatype/user/convert_value(datum/port/port, value_to_convert) + var/datum/object = value_to_convert + if(QDELETED(object)) + return null + return object diff --git a/code/modules/wiremod/shell/bot.dm b/code/modules/wiremod/shell/bot.dm index 36fd6c5b369933..dfd9845bc05b1d 100644 --- a/code/modules/wiremod/shell/bot.dm +++ b/code/modules/wiremod/shell/bot.dm @@ -31,7 +31,7 @@ var/datum/port/output/entity /obj/item/circuit_component/bot/populate_ports() - entity = add_output_port("User", PORT_TYPE_ATOM) + entity = add_output_port("User", PORT_TYPE_USER) signal = add_output_port("Signal", PORT_TYPE_SIGNAL) /obj/item/circuit_component/bot/register_shell(atom/movable/shell) @@ -46,4 +46,3 @@ playsound(source, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE) entity.set_output(user) signal.set_output(COMPONENT_SIGNAL) - diff --git a/code/modules/wiremod/shell/brain_computer_interface.dm b/code/modules/wiremod/shell/brain_computer_interface.dm index 89aac209c83e4f..c3ac3154d2d132 100644 --- a/code/modules/wiremod/shell/brain_computer_interface.dm +++ b/code/modules/wiremod/shell/brain_computer_interface.dm @@ -114,7 +114,7 @@ send_message_signal = add_input_port("Send Message", PORT_TYPE_SIGNAL) show_charge_meter = add_input_port("Show Charge Meter", PORT_TYPE_NUMBER, trigger = PROC_REF(update_charge_action)) - user_port = add_output_port("User", PORT_TYPE_ATOM) + user_port = add_output_port("User", PORT_TYPE_USER) /obj/item/circuit_component/bci_core/Destroy() QDEL_NULL(charge_action) diff --git a/code/modules/wiremod/shell/controller.dm b/code/modules/wiremod/shell/controller.dm index 7040e554a0a4ae..3092d3315f1655 100644 --- a/code/modules/wiremod/shell/controller.dm +++ b/code/modules/wiremod/shell/controller.dm @@ -34,7 +34,7 @@ var/datum/port/output/entity /obj/item/circuit_component/controller/populate_ports() - entity = add_output_port("User", PORT_TYPE_ATOM) + entity = add_output_port("User", PORT_TYPE_USER) signal = add_output_port("Signal", PORT_TYPE_SIGNAL) alt = add_output_port("Alternate Signal", PORT_TYPE_SIGNAL) right = add_output_port("Extra Signal", PORT_TYPE_SIGNAL) @@ -51,6 +51,12 @@ COMSIG_CLICK_ALT, )) +/obj/item/circuit_component/controller/proc/handle_trigger(atom/source, user, port_name, datum/port/output/port_signal) + source.balloon_alert(user, "clicked [port_name] button") + playsound(source, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE) + entity.set_output(user) + port_signal.set_output(COMPONENT_SIGNAL) + /** * Called when the shell item is used in hand */ @@ -58,10 +64,7 @@ SIGNAL_HANDLER if(!user.Adjacent(source)) return - source.balloon_alert(user, "clicked primary button") - playsound(source, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE) - entity.set_output(user) - signal.set_output(COMPONENT_SIGNAL) + handle_trigger(source, user, "primary", signal) /** * Called when the shell item is alt-clicked @@ -70,10 +73,8 @@ SIGNAL_HANDLER if(!user.Adjacent(source)) return - source.balloon_alert(user, "clicked alternate button") - playsound(source, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE) - entity.set_output(user) - alt.set_output(COMPONENT_SIGNAL) + handle_trigger(source, user, "alternate", alt) + /** * Called when the shell item is right-clicked in active hand @@ -82,7 +83,4 @@ SIGNAL_HANDLER if(!user.Adjacent(source)) return - source.balloon_alert(user, "clicked extra button") - playsound(source, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE) - entity.set_output(user) - right.set_output(COMPONENT_SIGNAL) + handle_trigger(source, user, "extra", right) diff --git a/code/modules/wiremod/shell/keyboard.dm b/code/modules/wiremod/shell/keyboard.dm index 4231a6dc814d49..05b9ded074baa3 100644 --- a/code/modules/wiremod/shell/keyboard.dm +++ b/code/modules/wiremod/shell/keyboard.dm @@ -27,7 +27,7 @@ var/datum/port/output/output /obj/item/circuit_component/keyboard_shell/populate_ports() - entity = add_output_port("User", PORT_TYPE_ATOM) + entity = add_output_port("User", PORT_TYPE_USER) output = add_output_port("Message", PORT_TYPE_STRING) signal = add_output_port("Signal", PORT_TYPE_SIGNAL) @@ -53,4 +53,3 @@ output.set_output(message) signal.set_output(COMPONENT_SIGNAL) - diff --git a/code/modules/wiremod/shell/module.dm b/code/modules/wiremod/shell/module.dm index bffff02e5fbca5..4201c6afb179a6 100644 --- a/code/modules/wiremod/shell/module.dm +++ b/code/modules/wiremod/shell/module.dm @@ -123,7 +123,7 @@ toggle_suit = add_input_port("Toggle Suit", PORT_TYPE_SIGNAL) select_module = add_input_port("Select Module", PORT_TYPE_SIGNAL) // States - wearer = add_output_port("Wearer", PORT_TYPE_ATOM) + wearer = add_output_port("Wearer", PORT_TYPE_USER) deployed = add_output_port("Deployed", PORT_TYPE_NUMBER) activated = add_output_port("Activated", PORT_TYPE_NUMBER) selected_module = add_output_port("Selected Module", PORT_TYPE_STRING) diff --git a/code/modules/wiremod/shell/moneybot.dm b/code/modules/wiremod/shell/moneybot.dm index 46a834e2d60543..20eb596eb72672 100644 --- a/code/modules/wiremod/shell/moneybot.dm +++ b/code/modules/wiremod/shell/moneybot.dm @@ -95,7 +95,7 @@ /obj/item/circuit_component/money_bot/populate_ports() total_money = add_output_port("Total Money", PORT_TYPE_NUMBER) money_input = add_output_port("Last Input Money", PORT_TYPE_NUMBER) - entity = add_output_port("User", PORT_TYPE_ATOM) + entity = add_output_port("User", PORT_TYPE_USER) money_trigger = add_output_port("Money Input", PORT_TYPE_SIGNAL) /obj/item/circuit_component/money_bot/register_shell(atom/movable/shell) diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm index 3530146f1a2aa2..43a6130c77336c 100644 --- a/code/modules/zombie/organs.dm +++ b/code/modules/zombie/organs.dm @@ -37,10 +37,22 @@ if(timer_id) deltimer(timer_id) +/obj/item/organ/internal/zombie_infection/on_insert(mob/living/carbon/organ_owner, special) + . = ..() + RegisterSignal(organ_owner, COMSIG_LIVING_DEATH, PROC_REF(organ_owner_died)) + +/obj/item/organ/internal/zombie_infection/on_remove(mob/living/carbon/organ_owner, special) + . = ..() + UnregisterSignal(organ_owner, COMSIG_LIVING_DEATH) + +/obj/item/organ/internal/zombie_infection/proc/organ_owner_died(mob/living/carbon/source, gibbed) + SIGNAL_HANDLER + qdel(src) // Congrats you somehow died so hard you stopped being a zombie + /obj/item/organ/internal/zombie_infection/on_find(mob/living/finder) - to_chat(finder, "Inside the head is a disgusting black \ + to_chat(finder, span_warning("Inside the head is a disgusting black \ web of pus and viscera, bound tightly around the brain like some \ - biological harness.") + biological harness.")) /obj/item/organ/internal/zombie_infection/process(seconds_per_tick, times_fired) if(!owner) diff --git a/config/iceruinblacklist.txt b/config/iceruinblacklist.txt index 1871d2d643a349..7d87495f60ba29 100644 --- a/config/iceruinblacklist.txt +++ b/config/iceruinblacklist.txt @@ -14,6 +14,7 @@ #_maps/RandomRuins/IceRuins/icemoon_underground_lavaland.dmm ##MISC +#_maps/RandomRuins/IceRuins/icemoon_surface_gas.dmm #_maps/RandomRuins/IceRuins/icemoon_surface_lust.dmm #_maps/RandomRuins/IceRuins/icemoon_surface_asteroid.dmm #_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm diff --git a/config/jobconfig.toml b/config/jobconfig.toml index fb9cfdc561e17a..949228e368018b 100644 --- a/config/jobconfig.toml +++ b/config/jobconfig.toml @@ -60,6 +60,13 @@ "Spawn Positions" = 1 "Total Positions" = 1 +[BITRUNNER] +"# Playtime Requirements" = 0 +"# Required Account Age" = 0 +"# Required Character Age" = 0 +"# Spawn Positions" = 3 +"# Total Positions" = 3 + [BOTANIST] "Playtime Requirements" = 0 "Required Account Age" = 0 diff --git a/html/changelogs/AutoChangeLog-pr-24648.yml b/html/changelogs/AutoChangeLog-pr-24648.yml deleted file mode 100644 index 1092ccd31d4aa8..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-24648.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - bugfix: "Removed rare hard delete involving telecomms machines." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-24656.yml b/html/changelogs/AutoChangeLog-pr-24656.yml deleted file mode 100644 index 1fd94a67bd975c..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-24656.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - bugfix: "Fixed an invisibility exploit on large mobs. Probably better this way" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-24660.yml b/html/changelogs/AutoChangeLog-pr-24660.yml deleted file mode 100644 index c3302749a80ca8..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-24660.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - rscadd: "Corn oil is now produced from corn instead of regular vegetable oil." - - balance: "Glycerol now uses corn oil instead of vegetable oil in it's recipe." - - bugfix: "Grinding corn now produces oil when it previously only made cornmeal despite having oil in it's reagents." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-24666.yml b/html/changelogs/AutoChangeLog-pr-24666.yml deleted file mode 100644 index 1c9b8c5cdcee70..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-24666.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - spellcheck: "Changed candy description to read better" \ No newline at end of file diff --git a/html/changelogs/archive/2023-10.yml b/html/changelogs/archive/2023-10.yml index b2fa23c2ba17b7..2fcba69cf733ec 100644 --- a/html/changelogs/archive/2023-10.yml +++ b/html/changelogs/archive/2023-10.yml @@ -1413,3 +1413,12 @@ then back on. - code_imp: Flashlights now use light_on instead of defining their own variable. Please report buggy behavior. +2023-10-31: + SkyratBot: + - bugfix: Removed rare hard delete involving telecomms machines. + - spellcheck: Changed candy description to read better + - bugfix: Fixed an invisibility exploit on large mobs. Probably better this way + - rscadd: Corn oil is now produced from corn instead of regular vegetable oil. + - balance: Glycerol now uses corn oil instead of vegetable oil in it's recipe. + - bugfix: Grinding corn now produces oil when it previously only made cornmeal despite + having oil in it's reagents. diff --git a/html/changelogs/archive/2023-11.yml b/html/changelogs/archive/2023-11.yml new file mode 100644 index 00000000000000..ba288ab903ea1c --- /dev/null +++ b/html/changelogs/archive/2023-11.yml @@ -0,0 +1,473 @@ +2023-11-01: + Data_: + - bugfix: The detective's curtains can be closed again in Birdshot. + LT3: + - code_imp: Changing security levels will only trigger the nightshift subsystem + if lighting changes are required + Melbert: + - qol: Clicking on an adjacent dense object (or mob) with Spray Cleaner will now + spritz it rather than doing nothing. This means you can use Spray Cleaner to + clean bloodied windows, as the janitor gods intended. It also means you can + fill a spray bottle with Napalm, I guess. + - refactor: Any cleaning object can now clean a microwave. + NotDhu: + - bugfix: Blueshift's white ship docking port should now work correctly. + OrionTheFox: + - bugfix: fixed the Medium/Long Skirts incorrectly being Toggleable, and falsely + covering the Chest + SkyratBot: + - bugfix: Obsessed's moodlets (Both positive and negative) go away when the trauma + is cured or the antag status is removed. + - bugfix: The Syndicate Revolver now has a Syndicate Firing Pin on the Nuke Ops + uplink. + - bugfix: Bluespace launchpads no longer work on shuttles + - rscadd: Added Abnormal Eggs + - rscadd: Added Two new spiders + - rscdel: Some Tarantula abilities + - balance: Spiders speed are now connected to health + - balance: Spiders now take more brute damage + - balance: All egg laying now has a cooldown + - rscdel: Removed extra consoles from birdshot's bitrunners + - bugfix: Fixes tesla zaps being weird. + - admin: Logs explosions from explosive zaps. + - rscadd: The Ethereal Vintner's Union has been "convinced" to trade their signature + Lanternfruit with Nanotrasen! + - image: Sprites for the aforementioned fruit. + - bugfix: Cargo will remove/cancel orders from its cart if that order exceeds the + available budget (both private or cargo) and the player cannot cancel this order + manually. All order costs are rounded up to integer values + - bugfix: Galactic material market will deny appending stacks to your existing order + if it exceeds the available (private or cargo depending on the mode of ordering) + budget & if it exceeds the available materials on the market. Galactic material + market UI is overall improved. + - rscdel: Remove duplicate light in battlecruiser starfury + - refactor: Pirate NPCs now use the basic mob framework. They'll be a little smarter + in combat, and if you're wearing your ID they'll siphon your bank account with + every melee attack! Beware! Please report any bugs. + - balance: Operatives can once again read about the basics of CQC at a reasonable + price of 14 TC. + - qol: All Syndicate MODsuits come with the potent ability to wear hats on their + helmets FOR FREE. No longer does any operative need be shamed by their bald + helmet's unhatted state when they spot the captain, in their MODsuit, wearing + a hat on their helmet. The embarrassment has resulted in more than a few operatives + prematurely detonating their implants! BUT NO LONGER! FASHION IS YOURS! + - qol: There is now a Core Gear Box, containing a few essential pieces of gear for + success as an operative. This is right at the top of the uplink, you can't miss + it! Great for those operatives just starting out, or operatives who need all + their baseline equipment NOW. + - refactor: Traders are basic mobs now. Please alert us of any strange behaviours! + - code_imp: If there is only one option, radial lists will autopick it. This behaviour + can be turned off via a new argument. + - bugfix: The fire visual on mobs should no longer persist after the fire has been + extinguished. + - bugfix: Plumbing IV Drip has full control over its injection/draining rate. No + longer displays the message controlled by plumbing system + - bugfix: Plumbing IV Drip can be plunged by plunger again + - bugfix: chameleon projector now can copy icon for storage items(backpacks, box, + holsters etc) using right-click on it. + - qol: To avoid poor magazine discipline, most combat-ready personnel have instructed + _not_ to put magazines into the gun loops on their armor vests. + - rscadd: ctrlclicking the knock path eldritch id card will toggle whether it creates + inverted portals or not + - balance: Malf Ability "Robotics Factory" can now be purchased multiple times. + - code_imp: mod reskins now properly shows their icon when skins loaded from different + .dmi + - rscdel: Remove duplicate pipe on pirate ship + - rscadd: living floor, living flesh, and other stuff for the bioresearch outpost + ruin + - rscadd: bioresearch outpost ruin + - bugfix: you may not defeat indestructible grilles and windows with mere tools + - refactor: Wraith constructs have been converted to the basic mob framework. NPC + wraiths are now extra cruel and will attack the lowest-health mob they can see + at any given time. Make sure this isn't you! Please report any bugs. + - bugfix: Artificers and juggernauts no longer attack significantly more slowly + than intended. + - rscadd: Added a new ruin to Ice Box Station, Lizard Gas Station + - rscdel: Remove duplicate power computer on oldstation ruin + - bugfix: Paraplegics can now enter netpods. + - bugfix: Fixes an exploit caused by teleporting out of a netpod. + - bugfix: Outfit selection at netpods shouldn't give armor bonuses any longer. + - refactor: The wings you get from a flight potion (if any) are now determined by + your chest bodypart, not your species. + - qol: Functional wings can now be ground up to get the flight potion back, if you + want to get a different wing variant. + - rscdel: Remove duplicate space heater from snowcabin ruin + - bugfix: Bitrunners can no longer get mass-mindswapped out of their avatar when + the wizard does the event. Something about machinery and magic not going well + together. + - bugfix: signals in circuits now actually function + - bugfix: Lethal ballistic pellet-based shotgun shells no longer instantly delete. + - bugfix: Practice laser carbines can no longer be used to rapidly fire regular + laser guns. + - bugfix: Modular shield generator modules no longer lose linkage when riding a + shuttle + - bugfix: Modular shield generators now gracefully turn off when being moved by + a shuttle rather than leaving their projections behind, the generator's description + was updated to advertise this behavior. + honkpocket: + - code_imp: Changes the syndicate neck gaiter to not have sec-hailer sfx and TTS + filtering + - code_imp: The xeno hybrid tongue now actually looks and sounds like the alien + tongue + - bugfix: Removes the dixel from the new medium and long skirts + sqnztb: + - bugfix: ships can now properly dock at Meta's whiteship dock again. +2023-11-02: + Iajret: + - bugfix: fixed blueshift ordnance chambers and, probably, doppler array + SkyratBot: + - qol: The RPD now accepts upgrade disks inserted by hand, as well as their original + method of hitting the disk with the RPD + - rscdel: Remove duplicate HoP shutter from birdshot + - qol: There is now a more convenient way to prompt surrender to emote - the Security + Pen. Each officer is equipped with one in their PDA. Simply click someone with + it to prompt a 30-second surrender. They are printable at Security Techfab as + well. + - qol: Penlights now are printable at Medical Techfab. + - image: Penlights got a new cleaner sprite to replace its ancient one + - code_imp: The code for Penlight's holographic sign has been improved. + - bugfix: Non-human mobs can hallucinate their mothers without causing a runtime + error + - rscdel: Removed duplicate northstar message monitor computer + - spellcheck: basic mobs getting shoved by humans now display the mob's disarm response + - refactor: Proteon constructs now use the basic mob framework. The ones encountered + in ruins are a bit flightier now, and will briefly flee combat if attacked - + only so that they can return and menace you again soon after. Please report + any bugs. + - bugfix: plumbing reaction chamber will attempt to balance the ph of the solution + a maximum of 5 times before giving up and thus preventing infinite loops, high + tick usage + - rscdel: Remove duplicate syndi turret on waystation ruin + - rscdel: Remove duplicate machinery from russian derelict + - rscdel: Remove duplicate atmos fire alarm, cargo air alarm, and chemistry shutter + from icebox. + - bugfix: plumbing bottler now only deals with bottles, beakers similar stuff but + not pills, patches, syringes or anything than can hold reagents. That & slime + extracts, slime industrial extract & shotgun shell + - qol: Steam vents in maintenance now have tooltips. + deathrobotpunch1: + - rscdel: Removed the biometric scanning toggle from the PENLITE holobarrier +2023-11-03: + Melbert: + - balance: Changelings gutted by Megafauna now take 8x as long to finalize revival + stasis (~5 minutes). + SkyratBot: + - bugfix: Basic mobs will no longer randomly walk into terrain that harms or kills + them. + - bugfix: Space carp that arrive via rifts are no longer stricken with rift travel + related sickness that causes them to become weaker. + - bugfix: Possessed blades can attempt to channel spirits again + - bugfix: venus human traps heal in kudzu again + - spellcheck: The Mothic Rations Chart poster description now mentions Sparkweed + Cigarettes rather than Windgrass + - bugfix: You can no longer eavesdrop on nearby borgs' radio comms if they're using + encryption keys + - bugfix: Fix fireplace smoke particles to work properly with all directions + - bugfix: Gorilla and dexterity holoparasite can now take things out of the backpack + while holding it in his hand. + - code_imp: creatures in cowboy boots will retaliate properly + - rscadd: Added some clarity to the range of netpods (4 tiles) in their exam text. + - bugfix: Bubblegum should no longer teleport out of the simulation when threatened + - rscdel: Chamber of Echoes map removed as it conflicts with the actual Legion + - bugfix: Heretics won't lose their living heart while bitrunning anymore. + ninjanomnom: + - bugfix: Fixes turrets being invisible when they shouldn't be +2023-11-04: + Melbert: + - admin: Admins without `R_POLL` no longer have access to "Server Poll Management", + not that they could have used it anyways. + SkyratBot: + - rscadd: Added a new fishing map to bitrunning. + - rscadd: You are no longer limited to pina coladas on the beach bar domain. Cheers! + - rscdel: Removed a extra coffee pot in birdshot's security breakroom + - bugfix: Added feedback for both extractor and extractee while using fulton extraction + packs. + - qol: Extraction packs now have better exam text. + - refactor: Shades now use the basic mob framework. Please report any bugs. + - qol: Character preferences now have descriptions as tooltips - hover over their + names to see them + - balance: Gorillas, Seedlings, Gold Grubs, Mooks, Constructs, Ascended Knock Heretics, + Fugu and mobs subject to a Fugu Gland now rip up walls in a slightly slower + but more cinematic way. + - bugfix: Softspoken quirk will no longer be applied to sign language + - rscdel: 'Remove duplicate machinery from Metastation: morgue disposal bin, medical + break room air alarm, and IV drip in permabrig medroom' + - bugfix: Fixes midround selection for observers + - refactor: The way mobs get specialized actions (like revenants shocking lights + or regal rats summoning rats to their side when you slap them) have been modified, + please report any bugs. + Syrox25: + - bugfix: Cargo loaders are once again disposal and dishwasher safe + Tattle: + - bugfix: you should now be able to scrub through the library without lagging the + server + Zergspower: + - bugfix: Bounties - Virus bounties work once more + jjpark-kb: + - balance: seed meshes now cost 1 plate, 2 chains instead of 1 plate, 4 chains + - balance: seed meshes now will take 5 seconds to uncover any potential seeds instead + of 10 seconds + - balance: seed meshes will now have a 30% chance to produce a seed instead of 15% + - qol: seed meshes will now loop your sand until you do not have enough sand/basalt + vinylspiders: + - bugfix: Empowered borer eggs and cybernetic eyes can no longer be given as a result + of bioscrambling a mob. +2023-11-05: + Melbert: + - code_imp: Removed species death and species hitby, replaced any uses with signals. + SkyratBot: + - bugfix: Fugu can correctly destroy walls when they get big. + - bugfix: The HFR will not print out a piece of paper every time you multitool it, + saving any desired energy to use for more useful processes. + - admin: Holobarrier creation now adds player fingerprint data + Tattle: + - bugfix: paintings can once again be filtered + timothymtorres, Rahlzel: + - sound: Port salute emote sound from Colonial Marines SS13 attributed to Rahlzel +2023-11-06: + LT3: + - code_imp: Emergency shuttle announcements no longer use hardcoded values + - code_imp: Central Command announcements now correctly use its new name when changed + - spellcheck: Consistency pass on event announcements + - qol: Holobarriers will match the spray paint colour of their projector + SkyratBot: + - bugfix: Mafia games can now start properly. + - bugfix: reagent volumes should be consistent & non breaking across plumbing & + chemistry as a whole + - bugfix: plumbing reaction chambers are more proactive. Will attempt to take in + reagents more frequently + - rscdel: Remove duplicate lighting from beach bar domain + - bugfix: Basic mobs using JPS can move again + jjpark-kb: + - qol: worm fertilizer is now a stackable item + - balance: worm farms produce faster + - balance: you can now feed worms single pieces of food in the same time as plant + bag feeding + nikothedude: + - bugfix: Synthetic slash wounds now mangle exterior instead of interior +2023-11-07: + Melbert: + - rscadd: Fishers can now try their luck at fishing out of hydroponics basins. + Rhials: + - code_imp: The notify_ghosts proc has been cleaned up. Please report any abnormal + changes in deadchat notification behavior. + - qol: The on-screen deadchat popups now contain the notification blurb when hovered + with your mouse again. + SkyratBot: + - bugfix: fixed a couple missing and misplaced disposals pipes on metastation + - qol: Improve the emote help verb to be more user friendly + - bugfix: You will now only become blackout drunk if you've actually been drinking. + - bugfix: Observers should stop being notified that a nameless entity is blacking + out. + - balance: paraplegic is no longer exclusive with spacer or settler or spacer. Broken + legs don't discriminate! + - bugfix: walls built next to firelocks no longer hold onto their alarms + - code_imp: added some trailing commas in lists that were missing them, fixed a + typo in comments + - bugfix: Reagent lookup in chem dispensers now shows correct reagent metabolization + rates + - bugfix: tails will no longer keep wagging even in death + - qol: Make notepad available for everyone, who has only laptop or console. + SpaceLove: + - rscadd: Nanotrasen has removed combat restrictions over Nightvision Cybernetic + Eyes and it is now readily available in advanced cybernetic implants for all + your nightly adventurers! + - rscdel: Nanotrasen medical ethics boards has deemed the militarygrade implants + such as Thermal eyes implant too risky to keep around in medical techfab, therefore + they have been handed over to Robotics only. + nikothedude: + - qol: Rewrote most preference entry descriptions to be more useful +2023-11-08: + LT3: + - bugfix: Maximum smoothing turf groups now includes cliffs + - bugfix: Tramstation floor tiles will correctly get custom station colors when + they exist + SkyratBot: + - bugfix: The screen alert should no longer break ghost UI when it's huge + - rscadd: Added a user type to integrated circuits + - bugfix: Both magic mirrors and regular mirrors are far better at respecting the + choice of the beard you wish to wear (within reason, of course). + - bugfix: fixes synthflesh not dealing and in fact healing toxin damage. + - bugfix: Fix light eater affecting lava, space, openspace, and transparent turfs + - bugfix: Nuclear operative induction implants now work correctly on antagonists + and fail on non-antagonists + - config: The bitrunner job now has a default config for server owners. + - image: Several holidays now have themed floor and tram tiling. + - qol: Light switches have tooltips, and may now be deconstructed with right click + using a screwdriver. + - rscadd: Being sufficiently drunk now has a chance to cause working out to fail + and harm you + - balance: sets the leaper move and pull forces to strong + - rscadd: Maltroach bar sign! + - bugfix: All vehicles (such as VIMs operated by a mouse or a lizard) will no longer + be able to phase through containment fields. + - bugfix: Slimes now need to be on an open turf to reproduce and split into more + slimy slimes, instead of getting away with using phasing powers in pipes. + jjpark-kb: + - rscadd: you can place torches on walls (closed turfs) now +2023-11-09: + Bumtickley00: + - spellcheck: You no longer hear weaponelding when deconstructing a closet. + LovliestPlant: + - rscadd: Adds links to any special rules or metaprotections to antag's objective + panels. + Majkl-J: + - bugfix: Flavor text should no longer bluescreen + Melbert: + - rscadd: Anomalies, portals, and bluespace rifts will now wibble a bit. + Nerev4r: + - rscadd: The holocigar is now public. + SkyratBot: + - balance: Flightpotion wings will no longer make health analyzers list you as nonhuman. + - balance: Harnessing Shoreline Quay (bluespace energy, probably), a mystical energy + (total bullshit) that permeates the Astral Waterways (bluespace quantum dimensions, + probably), Sleeping Carp users can now once against deflect projectiles with + their bare hands when focused in on battle (in combat mode). + - balance: The Keelhaul technique is now nonlethal (a philosophical acknowledgement + of the familial bond of sleep and death), but causes the target to become temporarily + blind and dizzy along with its previous effects. + - balance: Sleeping carp users, while in combat mode, deal Stamina damage with their + grabs and shoves. If the target of their grab has enough Stamina damage (80), + they are knocked unconscious from a well placed nerve pinch. + - balance: Sleeping carp users find it very hard to wake up once they fall asleep.... + - bugfix: Material market buy buttons greys out correctly and thus prevent you from + placing orders that exceeds the available budget. +2023-11-10: + CacheAtWork: + - rscdel: Removed a modular fermentation recipe from soybean; preventing override. + Nerev4r: + - bugfix: Snails now properly don't have any bones. + - qol: Snail limbs and tongue are now available in the limb grower. + Paxilmaniac: + - rscadd: A new quirk has been added, called "Ration Ticket Receiver" for zero points. + What does it do? In exchange for half of your paycheck, you'll get a ticket + every few paychecks that'll let you exchange it for your 1855 Passenger Act + mandated rations! + SkyratBot: + - spellcheck: Renamed Knock to Locks, and changed most of the flavor text of knowledge + gain, and renamed some items and knowledges from the path. + - bugfix: plumbing factories should not rarely/randomly brick at volumes like 0.9999(when + in fact it should have been 1) + - qol: Adds the capability for some player-controlled mobs with ranged attacks to + repeatedly fire their natural weapons by holding down the mouse button. + - rscadd: Three new plants; Peppercorn, Saltcane and Butterbeans. + - rscadd: Soysauce fermentation to soybeans. + - rscadd: Saltcane can be dried into a replacement seaweedsheet for sushi. + - balance: Venus human traps now take 12.5 damage per second instead of 20 while + off kudzu. + - bugfix: Nanotrasen has clarified an issue with their manual publishers, and these + guides should now contain actual user-pertinent content. + - qol: machines/devices that ask you to pick a reagent name from an input list have + their names sorted alphabetically & preserves white space between words making + them more readable. + - qol: improves performance of plumbing reaction chamber furthur + - code_imp: cleaned up code for portable chem mixer & chem dispenser. converted + their ui to typescript + - rscdel: Removed duplicate shutter from HoP office in birdboat, air alarm in northstar + maint, and portable air pump in northstar maint. + - bugfix: Fix holodeck items from being juiced or grinded with a biogenerator or + pestle and mortar + - rscadd: Enginenering rebar crossbows + tot kit + - rscadd: Added a bunch of ammos and crafting junk to make the ammo exist + - image: added icond for all the above + - code_imp: removed order history, import & export value from cargo & economy subsystems. + Allow supply packs to be properly deleted. In general memory savings + - qol: Bandolier can quick gather items now. + - balance: Bandolier capacity increased to 24 and can carry .357 ammo now. + - bugfix: Examining circuit boards now displays their detailed names(tier included) + correctly if required. + SomeRandomOwl: + - qol: Department Heads REJOICE! You now start with departmental budget cards in + your locker! And just so the captain doesn't feel lonely they get one too for + all the assistants that run around. + TiberianEuan: + - image: added blank white ipc screen + TwistedSilicon: + - bugfix: Cryo cells now use their direction to orient their initial connection + instead of defaulting to South. + Zxaber, DrDiasyl, Maurukas: + - rscadd: A new security-focused combat mech, the Paddy, has been added, intended + to be particularly helpful for lone sec officers. You will find one in the Security + main office, and a replacement can be built with late-game mech research. + - bugfix: Ripley MK-I and MK-II mechs no longer qdel their stored items when destroyed. + honkpocket: + - rscadd: The reagent weapons made with the forging stations can be renamed and + redescribed. + - bugfix: Fixes more unintended taur clothing cropping. + projectkepler-ru: + - rscadd: a gun beacon option for the NTC to pick between two of his magnum pistol + choices, fully modular and can be messed with by anyone in the future if more + guns are added. + sqnztb: + - bugfix: soulcatchers' edit name button correctly displays the host name + vinylspiders: + - bugfix: zippo sound effect now only plays for zippo lighters + - bugfix: big mortar can no longer grind/juice holograms + - bugfix: Hearthkin/primitive demihumans will now spawn with their quirks when using + a character loadout + - bugfix: in the loadout manager, trying to name a loadout item that has not been + checked will now inform user that they need to select the item first + - bugfix: the TG barsigns will now use emissives (aka, they will glow in the dark) + - bugfix: skyrat signs will give off small amounts of neon colored neon light like + TG signs do + - image: cyberslyph barsign (the only 96x96 sign) is now useable in the game, and + uses emissives. + - image: added some emissive light masks for a few of the skyrat barsigns + - refactor: converted the modular barsigns file to 64x32, and added a separate file + for 96x96 signs along with modular support for large signs + zergspower: + - balance: NPC Syndicate Shotgunners range requirement returned +2023-11-11: + Iajret: + - qol: SM airalarms on VoidRaptor and Blueshift now actually reads atmos from SM + chamber. + Plum-but-gayer: + - rscadd: Added a new oversized synthetic stomach, for oversized synths. + - bugfix: Fixed oversized synths spawning with organic stomachs. + - image: added a sprite for the oversized synth stomach. It's a lil jank, sorry! + SkyratBot: + - image: Adds yet another bar sign, this one mining themed + - balance: Snails no longer receive blunt wounds, meaning sharp weapons can dismember + them more easily + - balance: Slimes can no longer receive dislocations + - bugfix: Fix mapping linter not identifying duplicate blacklisted objects on a + turf + - code_imp: Add a mapping linter to check for stacked machinery + - rscadd: New Oranges' Juicery bar sign for the OJ connoisseurs. + - bugfix: fixed engi crossbow being able to be used onehanded + ability to craft + with sci inducers + - qol: Ordnance burn, freezing and supermatter chamber air alarms now show the air + contents on the tile of the connected sensor inside the chamber. + Zergspower: + - bugfix: Interdyne Medbay no longer has to worry about a mask that wont go away + if you touch it +2023-11-12: + Melbert: + - bugfix: Split persons can talk to their host once again + - rscdel: The Stethoscope no longer tells you if the target is missing a heart or + lungs. Now, it will simply say the target is lacking a pulse or not breathing. + - bugfix: AI controlled mobs which are immobilized are now properly immobilized + - bugfix: People with copied memories can modify their bank account ID as normal. + Motho: + - bugfix: NanoTrasen remembered to equip the NSV Blueshift with an APLU Paddy. + SkyratBot: + - spellcheck: Fixed typos in the examine text for the lead pipe & lead-acid battery. + - rscdel: Remove duplicate windows from birdshot, delta, and anomaly research ruin. + - refactor: Guardians/Powerminers/Holoparasites now use the basic mob framework. + Please report any unexpected changes or behaviour. + - qol: The verbs used to communicate with, recall, or banish your Guardian are now + action buttons. + - balance: If (as a Guardian) your host moves slightly out of range you will now + be dragged back into range if possible, rather than being instantly teleported + to them. + - balance: Protectors now have a shorter leash range rather than a longer one, in + order to more easily take advantage of their ability to drag their charge out + of danger. + - balance: Ranged Guardians can now hold down the mouse button to fire automatically. + - balance: People riding vehicles or other mobs now inherit all of their movement + traits, so riding a flying mob (or vehicle, if we have any of those) will allow + you to cross chasms and lava safely. + - rscadd: 4 new space ruins + jjpark-kb: + - rscadd: you can farm plants and ants on dug snow + - balance: you must now dig the basalt to farm plants and ants diff --git a/icons/area/areas_station.dmi b/icons/area/areas_station.dmi index cbfe463efa5169..f2182c6e9189a5 100644 Binary files a/icons/area/areas_station.dmi and b/icons/area/areas_station.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 1859a4512708cf..0dd945ff37eb4d 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/mob/actions/actions_animal.dmi b/icons/mob/actions/actions_animal.dmi index f3f9a667f2204e..64b1c700f414c0 100644 Binary files a/icons/mob/actions/actions_animal.dmi and b/icons/mob/actions/actions_animal.dmi differ diff --git a/icons/mob/actions/actions_mecha.dmi b/icons/mob/actions/actions_mecha.dmi index 5ae25522434ef3..7c659ca3b573c6 100644 Binary files a/icons/mob/actions/actions_mecha.dmi and b/icons/mob/actions/actions_mecha.dmi differ diff --git a/icons/mob/actions/actions_trader.dmi b/icons/mob/actions/actions_trader.dmi new file mode 100644 index 00000000000000..59330b4aac8327 Binary files /dev/null and b/icons/mob/actions/actions_trader.dmi differ diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index dc519380cfd7ac..ab4f8c85f30b5c 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi index d1a1777e4e4d8f..a55763038de862 100644 Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ diff --git a/icons/mob/clothing/belt_mirror.dmi b/icons/mob/clothing/belt_mirror.dmi index 0c1b8457be7c34..ef6c60705d12d5 100644 Binary files a/icons/mob/clothing/belt_mirror.dmi and b/icons/mob/clothing/belt_mirror.dmi differ diff --git a/icons/mob/human/bodyparts.dmi b/icons/mob/human/bodyparts.dmi index 7e804e894d213a..2150b3c2c810f3 100644 Binary files a/icons/mob/human/bodyparts.dmi and b/icons/mob/human/bodyparts.dmi differ diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi index 3e29ac726f9951..7e8297c848d3df 100644 Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi index 1a640935e0c6ab..366f285789a0ab 100644 Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/hammers_lefthand.dmi b/icons/mob/inhands/weapons/hammers_lefthand.dmi index 090bcb2ab9e0ab..7f6985e1de5ec5 100644 Binary files a/icons/mob/inhands/weapons/hammers_lefthand.dmi and b/icons/mob/inhands/weapons/hammers_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/hammers_righthand.dmi b/icons/mob/inhands/weapons/hammers_righthand.dmi index 3b0af0743f8d1b..2dd4f4b64c5cfb 100644 Binary files a/icons/mob/inhands/weapons/hammers_righthand.dmi and b/icons/mob/inhands/weapons/hammers_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_lefthand.dmi b/icons/mob/inhands/weapons/swords_lefthand.dmi index 4c665b811b5016..98a037e5c8ea03 100644 Binary files a/icons/mob/inhands/weapons/swords_lefthand.dmi and b/icons/mob/inhands/weapons/swords_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_righthand.dmi b/icons/mob/inhands/weapons/swords_righthand.dmi index 407443bb1ed342..b60f65194d57a6 100644 Binary files a/icons/mob/inhands/weapons/swords_righthand.dmi and b/icons/mob/inhands/weapons/swords_righthand.dmi differ diff --git a/icons/mob/mecha.dmi b/icons/mob/mecha.dmi index 845b1cdf140da1..f6dcbdec2b7eec 100644 Binary files a/icons/mob/mecha.dmi and b/icons/mob/mecha.dmi differ diff --git a/icons/mob/mecha_equipment.dmi b/icons/mob/mecha_equipment.dmi index 18fe707cafe6e2..90f0ce8c736cfb 100644 Binary files a/icons/mob/mecha_equipment.dmi and b/icons/mob/mecha_equipment.dmi differ diff --git a/icons/mob/simple/animal.dmi b/icons/mob/simple/animal.dmi index 87fe3a21506b1d..3bd3438bc62d5d 100644 Binary files a/icons/mob/simple/animal.dmi and b/icons/mob/simple/animal.dmi differ diff --git a/icons/mob/simple/arachnoid.dmi b/icons/mob/simple/arachnoid.dmi index fca53195d4c06f..d17297f2ccf573 100644 Binary files a/icons/mob/simple/arachnoid.dmi and b/icons/mob/simple/arachnoid.dmi differ diff --git a/icons/mob/simple/jungle/leaper.dmi b/icons/mob/simple/jungle/leaper.dmi index 39f807a191c2e8..2150c7b1ac2cf8 100644 Binary files a/icons/mob/simple/jungle/leaper.dmi and b/icons/mob/simple/jungle/leaper.dmi differ diff --git a/icons/mob/simple/traders.dmi b/icons/mob/simple/traders.dmi deleted file mode 100644 index 2f2b828bed911a..00000000000000 Binary files a/icons/mob/simple/traders.dmi and /dev/null differ diff --git a/icons/obj/clothing/belt_overlays.dmi b/icons/obj/clothing/belt_overlays.dmi index 740a832a023ee7..7a215dcb9b1cc4 100644 Binary files a/icons/obj/clothing/belt_overlays.dmi and b/icons/obj/clothing/belt_overlays.dmi differ diff --git a/icons/obj/doors/puzzledoor/danger.dmi b/icons/obj/doors/puzzledoor/danger.dmi new file mode 100644 index 00000000000000..89d19131cc189e Binary files /dev/null and b/icons/obj/doors/puzzledoor/danger.dmi differ diff --git a/icons/obj/doors/puzzledoor/default.dmi b/icons/obj/doors/puzzledoor/default.dmi index ec4fbed514bfa4..49a92061395800 100644 Binary files a/icons/obj/doors/puzzledoor/default.dmi and b/icons/obj/doors/puzzledoor/default.dmi differ diff --git a/icons/obj/drinks/mixed_drinks.dmi b/icons/obj/drinks/mixed_drinks.dmi index afda4ecfe5ed31..231df35f6e6ae3 100644 Binary files a/icons/obj/drinks/mixed_drinks.dmi and b/icons/obj/drinks/mixed_drinks.dmi differ diff --git a/icons/obj/lighting.dmi b/icons/obj/lighting.dmi index 061099defd4cd5..2bda7341e518f5 100644 Binary files a/icons/obj/lighting.dmi and b/icons/obj/lighting.dmi differ diff --git a/icons/obj/machines/barsigns.dmi b/icons/obj/machines/barsigns.dmi index c9450a009a152c..648008cf4311a9 100644 Binary files a/icons/obj/machines/barsigns.dmi and b/icons/obj/machines/barsigns.dmi differ diff --git a/icons/obj/machines/wallmounts.dmi b/icons/obj/machines/wallmounts.dmi index c14f750b25c31b..c5f2254c4bb15e 100644 Binary files a/icons/obj/machines/wallmounts.dmi and b/icons/obj/machines/wallmounts.dmi differ diff --git a/icons/obj/service/bureaucracy.dmi b/icons/obj/service/bureaucracy.dmi index 8cccb7f591032d..d8190ba2e723fb 100644 Binary files a/icons/obj/service/bureaucracy.dmi and b/icons/obj/service/bureaucracy.dmi differ diff --git a/icons/obj/service/hydroponics/growing.dmi b/icons/obj/service/hydroponics/growing.dmi index fcf738998636ae..aee567daa54457 100644 Binary files a/icons/obj/service/hydroponics/growing.dmi and b/icons/obj/service/hydroponics/growing.dmi differ diff --git a/icons/obj/service/hydroponics/growing_fruits.dmi b/icons/obj/service/hydroponics/growing_fruits.dmi index 92c52b55dbfcea..c0f547322c7cc3 100644 Binary files a/icons/obj/service/hydroponics/growing_fruits.dmi and b/icons/obj/service/hydroponics/growing_fruits.dmi differ diff --git a/icons/obj/service/hydroponics/growing_vegetables.dmi b/icons/obj/service/hydroponics/growing_vegetables.dmi index bf49c72ba79b54..30f02e862e037a 100644 Binary files a/icons/obj/service/hydroponics/growing_vegetables.dmi and b/icons/obj/service/hydroponics/growing_vegetables.dmi differ diff --git a/icons/obj/service/hydroponics/harvest.dmi b/icons/obj/service/hydroponics/harvest.dmi index 57a127cd9975ef..b15a34105dec24 100644 Binary files a/icons/obj/service/hydroponics/harvest.dmi and b/icons/obj/service/hydroponics/harvest.dmi differ diff --git a/icons/obj/service/hydroponics/seeds.dmi b/icons/obj/service/hydroponics/seeds.dmi index ffef219193a714..830086686547e7 100644 Binary files a/icons/obj/service/hydroponics/seeds.dmi and b/icons/obj/service/hydroponics/seeds.dmi differ diff --git a/icons/obj/service/library.dmi b/icons/obj/service/library.dmi index 8229c1fc3947e7..79a06dd4b8f912 100644 Binary files a/icons/obj/service/library.dmi and b/icons/obj/service/library.dmi differ diff --git a/icons/obj/stack_objects.dmi b/icons/obj/stack_objects.dmi index b524789417d23c..c1fcad67b2b648 100644 Binary files a/icons/obj/stack_objects.dmi and b/icons/obj/stack_objects.dmi differ diff --git a/icons/obj/storage/box.dmi b/icons/obj/storage/box.dmi index d660e1b7bfe388..c06fe4d8112b6e 100644 Binary files a/icons/obj/storage/box.dmi and b/icons/obj/storage/box.dmi differ diff --git a/icons/obj/storage/crates.dmi b/icons/obj/storage/crates.dmi index f5065b6b86903a..7f78d049302bf3 100644 Binary files a/icons/obj/storage/crates.dmi and b/icons/obj/storage/crates.dmi differ diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi index 5d6e1eb8a24018..a41aa161d0f10f 100644 Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ diff --git a/icons/obj/trader_signs.dmi b/icons/obj/trader_signs.dmi new file mode 100644 index 00000000000000..a6789e0bb4c5f2 Binary files /dev/null and b/icons/obj/trader_signs.dmi differ diff --git a/icons/obj/weapons/guns/ammo.dmi b/icons/obj/weapons/guns/ammo.dmi index a36b593706f76d..07a4bde661a64b 100644 Binary files a/icons/obj/weapons/guns/ammo.dmi and b/icons/obj/weapons/guns/ammo.dmi differ diff --git a/icons/obj/weapons/guns/ballistic.dmi b/icons/obj/weapons/guns/ballistic.dmi index 9dd25af2a92195..5cd823cc9c4121 100644 Binary files a/icons/obj/weapons/guns/ballistic.dmi and b/icons/obj/weapons/guns/ballistic.dmi differ diff --git a/icons/obj/weapons/guns/magic.dmi b/icons/obj/weapons/guns/magic.dmi index 7cab0cdfc25926..53217ef461b37c 100644 Binary files a/icons/obj/weapons/guns/magic.dmi and b/icons/obj/weapons/guns/magic.dmi differ diff --git a/icons/obj/weapons/guns/projectiles.dmi b/icons/obj/weapons/guns/projectiles.dmi index 05ad142ff58d38..168f9fb716c80b 100644 Binary files a/icons/obj/weapons/guns/projectiles.dmi and b/icons/obj/weapons/guns/projectiles.dmi differ diff --git a/icons/obj/weapons/hammer.dmi b/icons/obj/weapons/hammer.dmi index c210f8b436b3a5..6c454462f48cfb 100644 Binary files a/icons/obj/weapons/hammer.dmi and b/icons/obj/weapons/hammer.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index 682809fbf435b1..9dca06d4153cab 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/icons/turf/walls/meat.dmi b/icons/turf/walls/meat.dmi new file mode 100644 index 00000000000000..fbbeb8a9c3cac6 Binary files /dev/null and b/icons/turf/walls/meat.dmi differ diff --git a/icons/ui_icons/achievements/achievements.dmi b/icons/ui_icons/achievements/achievements.dmi index b3e64c9d09f835..5f6626c7993fc6 100644 Binary files a/icons/ui_icons/achievements/achievements.dmi and b/icons/ui_icons/achievements/achievements.dmi differ diff --git a/modular_skyrat/master_files/code/game/machinery/limbgrower.dm b/modular_skyrat/master_files/code/game/machinery/limbgrower.dm new file mode 100644 index 00000000000000..edf0474bfa077e --- /dev/null +++ b/modular_skyrat/master_files/code/game/machinery/limbgrower.dm @@ -0,0 +1,3 @@ +/obj/machinery/limbgrower/Initialize(mapload) + categories += list(SPECIES_SNAIL) + return ..() diff --git a/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm b/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm index 78f1369bae0e63..3f9d365787047a 100644 --- a/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -1,7 +1,7 @@ // Add modular crafting recipes here, NOT IN BASE /tg/ CRAFTING LISTS /** - * Add a list of receipes to an existing recipe sublist. + * Add a list of recipes to an existing recipe sublist. * * Arguments: * * stack_recipes - the existing list of stack recipes. diff --git a/modular_skyrat/master_files/code/game/objects/items/wiki_manuals.dm b/modular_skyrat/master_files/code/game/objects/items/wiki_manuals.dm new file mode 100644 index 00000000000000..97d310625939fc --- /dev/null +++ b/modular_skyrat/master_files/code/game/objects/items/wiki_manuals.dm @@ -0,0 +1,5 @@ +/obj/item/book/manual/wiki/security_space_law + name = "Corporate Regulations" + desc = "A set of Nanotrasen regulations for keeping law, order, and procedure followed within their space stations." + starting_title = "Corporate Regulations" + page_link = "Corporate_Regulations" diff --git a/modular_skyrat/master_files/code/modules/client/preferences/ghost.dm b/modular_skyrat/master_files/code/modules/client/preferences/ghost.dm index 0530276c5bb21e..38eb418b5035a1 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences/ghost.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences/ghost.dm @@ -17,7 +17,7 @@ join_action.Remove(ghost) return TRUE - var/datum/action/innate/join_soulcatcher/new_join_action = new + var/datum/action/innate/join_soulcatcher/new_join_action = new(ghost) new_join_action.Grant(ghost) return TRUE diff --git a/modular_skyrat/master_files/code/modules/clothing/clothing_variation_overrides/suit.dm b/modular_skyrat/master_files/code/modules/clothing/clothing_variation_overrides/suit.dm index 4c2c440c200fb9..26b6d64a6ccf0e 100644 --- a/modular_skyrat/master_files/code/modules/clothing/clothing_variation_overrides/suit.dm +++ b/modular_skyrat/master_files/code/modules/clothing/clothing_variation_overrides/suit.dm @@ -118,6 +118,7 @@ /obj/item/clothing/suit/hooded/wintercoat supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON + gets_cropped_on_taurs = FALSE /obj/item/clothing/suit/toggle/cargo_tech supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON diff --git a/modular_skyrat/master_files/code/modules/clothing/under/jobs/medical.dm b/modular_skyrat/master_files/code/modules/clothing/under/jobs/medical.dm index 7c9d8668aacac2..b1c465ccdf9ef1 100644 --- a/modular_skyrat/master_files/code/modules/clothing/under/jobs/medical.dm +++ b/modular_skyrat/master_files/code/modules/clothing/under/jobs/medical.dm @@ -69,6 +69,10 @@ dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON + gets_cropped_on_taurs = FALSE + +/obj/item/clothing/under/rank/medical/chemist/skirt + gets_cropped_on_taurs = FALSE /* * PARAMEDIC diff --git a/modular_skyrat/master_files/code/modules/clothing/under/skirts_dresses.dm b/modular_skyrat/master_files/code/modules/clothing/under/skirts_dresses.dm index f2d4245028b6f7..224bd78eccd0ee 100644 --- a/modular_skyrat/master_files/code/modules/clothing/under/skirts_dresses.dm +++ b/modular_skyrat/master_files/code/modules/clothing/under/skirts_dresses.dm @@ -37,15 +37,29 @@ icon_state = "skirt_swept" body_parts_covered = GROIN -/obj/item/clothing/under/dress/skirt/skyrat/lone_skirt - name = "skirt" - desc = "Just a skirt! Hope you have a tanktop to wear with this." - icon_state = "lone_skirt" - body_parts_covered = GROIN - greyscale_config = /datum/greyscale_config/lone_skirt - greyscale_config_worn = /datum/greyscale_config/lone_skirt/worn - greyscale_colors = "#5f534a" - flags_1 = IS_PLAYER_COLORABLE_1 +/obj/item/clothing/under/dress/skirt/skyrat/striped_skirt + name = "Striped Skirt" + desc = "A red side-slit skirt with stripes! Comes with a matching two-tone bra." + icon_state = "striped_skirt" + body_parts_covered = CHEST|GROIN|LEGS + can_adjust = TRUE + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION + +/obj/item/clothing/under/dress/skirt/skyrat/red_skirt + name = "Red Skirt" + desc = "An eye-catching knee-length red skirt, with a golden-yellow trim. Comes with a matching two-tone bra." + icon_state = "red_skirt" + body_parts_covered = CHEST|GROIN|LEGS + can_adjust = TRUE + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION + +/obj/item/clothing/under/dress/skirt/skyrat/black_skirt + name = "Black Skirt" + desc = "A black side-slit skirt with a golden-yellow trim. Screams 'affluent goth'. Comes with a funky-looking matching bra." + icon_state = "black_skirt" + body_parts_covered = CHEST|GROIN|LEGS + can_adjust = TRUE + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION /obj/item/clothing/under/dress/skirt/skyrat/turtleskirt_knit //Essentially the same as the Turtleneck Skirt but with a different texture name = "cableknit skirt" @@ -71,36 +85,36 @@ greyscale_colors = "#787878#723E0E#4D7EAC" flags_1 = IS_PLAYER_COLORABLE_1 -/obj/item/clothing/under/dress/skyrat/short_dress - name = "short dress" - desc = "An extremely short dress with a lovely sash and flower - only for those with good self-confidence." - icon_state = "short_dress" - greyscale_config = /datum/greyscale_config/short_dress - greyscale_config_worn = /datum/greyscale_config/short_dress/worn - greyscale_colors = "#ff3636#363030" +/obj/item/clothing/under/dress/skirt/skyrat/lone_skirt + name = "skirt" + desc = "Just a skirt! Hope you have a tanktop to wear with this." + icon_state = "lone_skirt" + body_parts_covered = GROIN + greyscale_config = /datum/greyscale_config/lone_skirt + greyscale_config_worn = /datum/greyscale_config/lone_skirt/worn + greyscale_colors = "#5f534a" flags_1 = IS_PLAYER_COLORABLE_1 -/obj/item/clothing/under/dress/skyrat/pinktutu - name = "pink tutu" - desc = "A fluffy pink tutu." - icon_state = "pinktutu" - -/obj/item/clothing/under/skyrat/medium_skirt +/obj/item/clothing/under/dress/skirt/skyrat/medium name = "medium skirt" - desc = "Appealing medium-length skirt." + desc = "An appealing medium-length skirt. Top not included." icon_state = "medium_skirt" + body_parts_covered = GROIN greyscale_config = /datum/greyscale_config/medium_skirt greyscale_config_worn = /datum/greyscale_config/medium_skirt/worn greyscale_colors = "#3a3c45" + female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY|FEMALE_UNIFORM_NO_BREASTS flags_1 = IS_PLAYER_COLORABLE_1 -/obj/item/clothing/under/skyrat/long_skirt +/obj/item/clothing/under/dress/skirt/skyrat/long name = "long skirt" - desc = "Appealing long skirt." + desc = "An appealing long skirt. At this point does it qualify as a dress?" icon_state = "long_skirt" + body_parts_covered = GROIN|LEGS greyscale_config = /datum/greyscale_config/long_skirt greyscale_config_worn = /datum/greyscale_config/long_skirt/worn greyscale_colors = "#3a3c45" + female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY|FEMALE_UNIFORM_NO_BREASTS alternate_worn_layer = ABOVE_SHOES_LAYER flags_1 = IS_PLAYER_COLORABLE_1 @@ -108,6 +122,20 @@ * Dresses */ +/obj/item/clothing/under/dress/skyrat/short_dress + name = "short dress" + desc = "An extremely short dress with a lovely sash and flower - only for those with good self-confidence." + icon_state = "short_dress" + greyscale_config = /datum/greyscale_config/short_dress + greyscale_config_worn = /datum/greyscale_config/short_dress/worn + greyscale_colors = "#ff3636#363030" + flags_1 = IS_PLAYER_COLORABLE_1 + +/obj/item/clothing/under/dress/skyrat/pinktutu + name = "pink tutu" + desc = "A fluffy pink tutu." + icon_state = "pinktutu" + /obj/item/clothing/under/dress/skyrat/flower name = "flower dress" desc = "Lovely dress. Colored like the autumn leaves." @@ -155,27 +183,3 @@ body_parts_covered = CHEST|GROIN|LEGS can_adjust = TRUE supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION - -/obj/item/clothing/under/dress/skirt/skyrat/striped_skirt - name = "Striped Skirt" - desc = "A red side-slit skirt with stripes! Comes with a matching two-tone bra." - icon_state = "striped_skirt" - body_parts_covered = CHEST|GROIN|LEGS - can_adjust = TRUE - supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION - -/obj/item/clothing/under/dress/skirt/skyrat/red_skirt - name = "Red Skirt" - desc = "An eye-catching knee-length red skirt, with a golden-yellow trim, comes with a two-tone bra." - icon_state = "red_skirt" - body_parts_covered = CHEST|GROIN|LEGS - can_adjust = TRUE - supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION - -/obj/item/clothing/under/dress/skirt/skyrat/black_skirt - name = "Black Skirt" - desc = "A black side-slit skirt with a golden-yellow trim. Screams 'affluent goth'. Comes with a funky-looking matching bra." - icon_state = "black_skirt" - body_parts_covered = CHEST|GROIN|LEGS - can_adjust = TRUE - supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION diff --git a/modular_skyrat/master_files/code/modules/mob/living/examine_tgui.dm b/modular_skyrat/master_files/code/modules/mob/living/examine_tgui.dm index 1b929fb7c1e406..5648dda48d385d 100644 --- a/modular_skyrat/master_files/code/modules/mob/living/examine_tgui.dm +++ b/modular_skyrat/master_files/code/modules/mob/living/examine_tgui.dm @@ -82,7 +82,7 @@ obscured = (holder_human.wear_mask && (holder_human.wear_mask.flags_inv & HIDEFACE)) || (holder_human.head && (holder_human.head.flags_inv & HIDEFACE)) custom_species = obscured ? "Obscured" : holder_human.dna.species.lore_protected ? holder_human.dna.species.name : holder_human.dna.features["custom_species"] flavor_text = obscured ? "Obscured" : holder_human.dna.features["flavor_text"] - custom_species_lore = obscured ? "Obscured" : holder_human.dna.species.lore_protected ? holder_human.dna.species.get_species_lore() : holder_human.dna.features["custom_species_lore"] + custom_species_lore = obscured ? "Obscured" : holder_human.dna.species.lore_protected ? holder_human.dna.species.get_species_lore().Join("\n") : holder_human.dna.features["custom_species_lore"] ooc_notes += holder_human.dna.features["ooc_notes"] if(!obscured) headshot += holder_human.dna.features["headshot"] diff --git a/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/bumbles.dm b/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/bumbles.dm index 10ca65f4acd742..28f8f3994b69ce 100644 --- a/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/bumbles.dm +++ b/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/bumbles.dm @@ -117,7 +117,7 @@ // Bumble AI controller that adds find flowers, resting, and buzzing subtrees. /datum/ai_controller/basic_controller/bumbles blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items(), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, ) ai_traits = STOP_MOVING_WHEN_PULLED diff --git a/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/dogs.dm b/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/dogs.dm index f78a481cbd4bf2..7856a35690ddd9 100644 --- a/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/dogs.dm +++ b/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/dogs.dm @@ -127,7 +127,7 @@ borgi.set_movement_target(target) borgi.blackboard[BB_DOG_HARASS_TARGET] = WEAKREF(target) - borgi.queue_behavior(/datum/ai_behavior/basic_melee_attack/dog, BB_DOG_HARASS_TARGET, BB_PET_TARGETTING_DATUM) + borgi.queue_behavior(/datum/ai_behavior/basic_melee_attack/dog, BB_DOG_HARASS_TARGET, BB_PET_TARGETING_STRATEGY) /mob/living/basic/pet/dog/corgi/borgi/proc/on_attack_hand(datum/source, mob/living/target) SIGNAL_HANDLER @@ -242,7 +242,12 @@ investigate_log("has been gibbed due to being emagged by [user].", INVESTIGATE_DEATHS) visible_message(span_boldwarning("[user] swipes a card through [target]!"), span_notice("You overload [target]s internal reactor...")) - notify_ghosts("[user] has shortcircuited [target] to explode in 60 seconds!", source = target, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Borgi Emagged") + notify_ghosts("[user] has shortcircuited [target] to explode in 60 seconds!", + source = target, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Borgi Emagged", + ) addtimer(CALLBACK(src, PROC_REF(explode_imminent)), 50 SECONDS) return TRUE @@ -263,7 +268,7 @@ BB_DOG_HARASS_HARM = TRUE, BB_VISION_RANGE = AI_DOG_VISION_RANGE, BB_DOG_IS_SLOW = TRUE, - BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic(), + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) planning_subtrees = list( @@ -293,7 +298,7 @@ if(!SPT_PROB(chance, seconds_per_tick)) return - controller.queue_behavior(/datum/ai_behavior/find_potential_targets, BB_BASIC_MOB_CURRENT_TARGET, BB_PET_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/find_potential_targets, BB_BASIC_MOB_CURRENT_TARGET, BB_PET_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) return // Attack. diff --git a/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/poppy.dm b/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/poppy.dm index 4bf62fa12a8de8..4bc4c5cda4c9d4 100644 --- a/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/poppy.dm +++ b/modular_skyrat/master_files/code/modules/mob/living/simple_animal/friendly/poppy.dm @@ -119,7 +119,12 @@ do_jitter_animation(60) manual_emote("'s fur stands up, [src.p_their()] body trembling...") - notify_ghosts("[src] was startled by the supermatter!", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Safety Inspection!") + notify_ghosts("[src] was startled by the supermatter!", + source = src, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Safety Inspection!", + ) addtimer(CALLBACK(src, PROC_REF(calm_down)), 60 SECONDS) /mob/living/simple_animal/pet/poppy/proc/calm_down() diff --git a/modular_skyrat/master_files/code/modules/mod/modules/modules_supply.dm b/modular_skyrat/master_files/code/modules/mod/modules/modules_supply.dm new file mode 100644 index 00000000000000..99021d8d4804ae --- /dev/null +++ b/modular_skyrat/master_files/code/modules/mod/modules/modules_supply.dm @@ -0,0 +1,7 @@ +/obj/item/mod/module/hydraulic/on_suit_activation() + . = ..() + ADD_TRAIT(mod.wearer, TRAIT_TRASHMAN, MOD_TRAIT) + +/obj/item/mod/module/hydraulic/on_suit_deactivation(deleting = FALSE) + . = ..() + REMOVE_TRAIT(mod.wearer, TRAIT_TRASHMAN, MOD_TRAIT) diff --git a/modular_skyrat/master_files/code/modules/research/designs/limbgrower_designs.dm b/modular_skyrat/master_files/code/modules/research/designs/limbgrower_designs.dm new file mode 100644 index 00000000000000..419041848bb320 --- /dev/null +++ b/modular_skyrat/master_files/code/modules/research/designs/limbgrower_designs.dm @@ -0,0 +1,21 @@ +/datum/design/leftarm/New() + category += list(SPECIES_SNAIL) + return ..() + +/datum/design/rightarm/New() + category += list(SPECIES_SNAIL) + return ..() + +/datum/design/leftleg/New() + category += list(SPECIES_SNAIL) + return ..() + +/datum/design/rightleg/New() + category += list(SPECIES_SNAIL) + return ..() + +/datum/design/tongue/snail + name = "Snail Tongue" + id = "snailtongue" + build_path = /obj/item/organ/internal/tongue/snail + category = list(SPECIES_SNAIL, RND_CATEGORY_INITIAL) diff --git a/modular_skyrat/master_files/code/modules/surgery/organs/external/wings/functional_wings.dm b/modular_skyrat/master_files/code/modules/surgery/organs/external/wings/functional_wings.dm new file mode 100644 index 00000000000000..49d2bf5c752c44 --- /dev/null +++ b/modular_skyrat/master_files/code/modules/surgery/organs/external/wings/functional_wings.dm @@ -0,0 +1,3 @@ +// No free fall softening for everyone - but functional wings get it +/obj/item/organ/external/wings/functional/can_soften_fall() + return TRUE diff --git a/modular_skyrat/master_files/code/modules/surgery/organs/external/wings/wings.dm b/modular_skyrat/master_files/code/modules/surgery/organs/external/wings/wings.dm new file mode 100644 index 00000000000000..b975cac1d6bd61 --- /dev/null +++ b/modular_skyrat/master_files/code/modules/surgery/organs/external/wings/wings.dm @@ -0,0 +1,3 @@ +// No free fall softening for everyone +/obj/item/organ/external/wings/functional/can_soften_fall() + return FALSE diff --git a/modular_skyrat/master_files/icons/mob/huds/hud.dmi b/modular_skyrat/master_files/icons/mob/huds/hud.dmi index 235a45ecd4918e..3d81edc5f201a9 100644 Binary files a/modular_skyrat/master_files/icons/mob/huds/hud.dmi and b/modular_skyrat/master_files/icons/mob/huds/hud.dmi differ diff --git a/modular_skyrat/master_files/icons/mob/mod.dmi b/modular_skyrat/master_files/icons/mob/mod.dmi index 046be38264976e..a1055a38d5e036 100644 Binary files a/modular_skyrat/master_files/icons/mob/mod.dmi and b/modular_skyrat/master_files/icons/mob/mod.dmi differ diff --git a/modular_skyrat/master_files/icons/mob/sprite_accessory/ipc_screens.dmi b/modular_skyrat/master_files/icons/mob/sprite_accessory/ipc_screens.dmi index be61ef5518d94d..db52a56c2c848e 100644 Binary files a/modular_skyrat/master_files/icons/mob/sprite_accessory/ipc_screens.dmi and b/modular_skyrat/master_files/icons/mob/sprite_accessory/ipc_screens.dmi differ diff --git a/modular_skyrat/master_files/icons/obj/card.dmi b/modular_skyrat/master_files/icons/obj/card.dmi index 9130183d19d8f4..d44c3417b7ed3b 100644 Binary files a/modular_skyrat/master_files/icons/obj/card.dmi and b/modular_skyrat/master_files/icons/obj/card.dmi differ diff --git a/modular_skyrat/master_files/sound/items/zippo_close.ogg b/modular_skyrat/master_files/sound/items/zippo_close.ogg new file mode 100644 index 00000000000000..8d51263dfd8065 Binary files /dev/null and b/modular_skyrat/master_files/sound/items/zippo_close.ogg differ diff --git a/modular_skyrat/master_files/sound/items/zippo_open.ogg b/modular_skyrat/master_files/sound/items/zippo_open.ogg new file mode 100644 index 00000000000000..1c1681d999a379 Binary files /dev/null and b/modular_skyrat/master_files/sound/items/zippo_open.ogg differ diff --git a/modular_skyrat/modules/Department_Budgets/cards.dm b/modular_skyrat/modules/Department_Budgets/cards.dm new file mode 100644 index 00000000000000..bffa9ace0f5415 --- /dev/null +++ b/modular_skyrat/modules/Department_Budgets/cards.dm @@ -0,0 +1,24 @@ +/obj/item/card/id/departmental_budget/med + department_ID = ACCOUNT_MED + department_name = ACCOUNT_MED_NAME + icon_state = "med_budget" + +/obj/item/card/id/departmental_budget/eng + department_ID = ACCOUNT_ENG + department_name = ACCOUNT_ENG_NAME + icon_state = "eng_budget" + +/obj/item/card/id/departmental_budget/sci + department_ID = ACCOUNT_SCI + department_name = ACCOUNT_SCI_NAME + icon_state = "sci_budget" + +/obj/item/card/id/departmental_budget/srv + department_ID = ACCOUNT_SRV + department_name = ACCOUNT_SRV_NAME + icon_state = "srv_budget" + +/obj/item/card/id/departmental_budget/sec + department_ID = ACCOUNT_SEC + department_name = ACCOUNT_SEC_NAME + icon_state = "sec_budget" diff --git a/modular_skyrat/modules/SiliconQoL/code/robotic_factory.dm b/modular_skyrat/modules/SiliconQoL/code/robotic_factory.dm index 4ff1032bec188f..52585f07b82cad 100644 --- a/modular_skyrat/modules/SiliconQoL/code/robotic_factory.dm +++ b/modular_skyrat/modules/SiliconQoL/code/robotic_factory.dm @@ -53,7 +53,12 @@ if(stored_cyborgs > max_stored_cyborgs) return stored_cyborgs++ - notify_ghosts("A new cyborg shell has been created at the [src]", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "New malfunctioning cyborg created!") + notify_ghosts("A new cyborg shell has been created at the [src]", + source = src, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "New malfunctioning cyborg created!", + ) /obj/machinery/transformer_rp/proc/create_a_cyborg(mob/dead/observer/target_ghost) if(machine_stat & (BROKEN|NOPOWER)) diff --git a/modular_skyrat/modules/Syndie_edits/code/syndie_edits.dm b/modular_skyrat/modules/Syndie_edits/code/syndie_edits.dm index f3c35932d32b98..b800778df80b76 100644 --- a/modular_skyrat/modules/Syndie_edits/code/syndie_edits.dm +++ b/modular_skyrat/modules/Syndie_edits/code/syndie_edits.dm @@ -67,6 +67,9 @@ icon_state = "half_mask" icon = 'modular_skyrat/master_files/icons/obj/clothing/masks.dmi' worn_icon = 'modular_skyrat/master_files/icons/mob/clothing/mask.dmi' + unique_death = 'modular_skyrat/master_files/sound/effects/hacked.ogg' + voice_filter = null + use_radio_beeps_tts = FALSE /obj/item/clothing/shoes/combat //TO-DO: Move these overrides out of a syndicate file! icon = 'modular_skyrat/master_files/icons/obj/clothing/shoes.dmi' diff --git a/modular_skyrat/modules/ashwalkers/code/buildings/antfarm.dm b/modular_skyrat/modules/ashwalkers/code/buildings/antfarm.dm index 898aef8c5d9994..c5f2e645c95b5d 100644 --- a/modular_skyrat/modules/ashwalkers/code/buildings/antfarm.dm +++ b/modular_skyrat/modules/ashwalkers/code/buildings/antfarm.dm @@ -28,8 +28,8 @@ /obj/structure/antfarm/Initialize(mapload) . = ..() var/turf/src_turf = get_turf(src) - if(!istype(get_turf(src), /turf/open/misc/asteroid/basalt)) - src_turf.balloon_alert_to_viewers("must be on basalt") + if(!src_turf.GetComponent(/datum/component/simple_farm)) + src_turf.balloon_alert_to_viewers("must be on farmable surface") return INITIALIZE_HINT_QDEL for(var/obj/structure/antfarm/found_farm in range(2, get_turf(src))) diff --git a/modular_skyrat/modules/ashwalkers/code/buildings/ash_farming.dm b/modular_skyrat/modules/ashwalkers/code/buildings/ash_farming.dm index 7e946053c5d6da..5de8573f6b6a66 100644 --- a/modular_skyrat/modules/ashwalkers/code/buildings/ash_farming.dm +++ b/modular_skyrat/modules/ashwalkers/code/buildings/ash_farming.dm @@ -163,14 +163,19 @@ increase_yield(user) return - else if(istype(attacking_item, /obj/item/worm_fertilizer)) + else if(istype(attacking_item, /obj/item/stack/worm_fertilizer)) + + var/obj/item/stack/attacking_stack = attacking_item + + if(!attacking_stack.use(1)) + balloon_alert(user, "unable to use [attacking_item]") + return if(!decrease_cooldown(user, silent = TRUE) && !increase_yield(user, silent = TRUE)) balloon_alert(user, "plant is already fully upgraded") else balloon_alert(user, "plant was upgraded") - qdel(attacking_item) return @@ -266,6 +271,18 @@ plant_bag?.atom_storage?.attempt_insert(created_harvest, user, TRUE) -/turf/open/misc/asteroid/basalt/Initialize(mapload) +/turf/open/misc/asteroid/basalt/getDug() + . = ..() + AddComponent(/datum/component/simple_farm) + +/turf/open/misc/asteroid/basalt/refill_dug() + . = ..() + qdel(GetComponent(/datum/component/simple_farm)) + +/turf/open/misc/asteroid/snow/getDug() . = ..() AddComponent(/datum/component/simple_farm) + +/turf/open/misc/asteroid/snow/refill_dug() + . = ..() + qdel(GetComponent(/datum/component/simple_farm)) diff --git a/modular_skyrat/modules/ashwalkers/code/buildings/wormfarm.dm b/modular_skyrat/modules/ashwalkers/code/buildings/wormfarm.dm index 94d8171cbc908d..8046a7b4fd0e9d 100644 --- a/modular_skyrat/modules/ashwalkers/code/buildings/wormfarm.dm +++ b/modular_skyrat/modules/ashwalkers/code/buildings/wormfarm.dm @@ -19,7 +19,7 @@ /obj/structure/wormfarm/Initialize(mapload) . = ..() START_PROCESSING(SSobj, src) - COOLDOWN_START(src, worm_timer, 1 MINUTES) + COOLDOWN_START(src, worm_timer, 30 SECONDS) /obj/structure/wormfarm/Destroy() STOP_PROCESSING(SSobj, src) @@ -30,14 +30,14 @@ if(!COOLDOWN_FINISHED(src, worm_timer)) return - COOLDOWN_START(src, worm_timer, 1 MINUTES) + COOLDOWN_START(src, worm_timer, 30 SECONDS) if(current_worm >= 2 && current_worm < max_worm) current_worm++ if(current_food > 0 && current_worm > 1) current_food-- - new /obj/item/worm_fertilizer(get_turf(src)) + new /obj/item/stack/worm_fertilizer(get_turf(src)) /obj/structure/wormfarm/examine(mob/user) . = ..() @@ -89,7 +89,7 @@ in_use = TRUE balloon_alert(user, "feeding the worms") - if(!do_after(user, 5 SECONDS, src)) + if(!do_after(user, 1 SECONDS, src)) balloon_alert(user, "stopped feeding the worms") in_use = FALSE return @@ -129,9 +129,11 @@ return ..() //produced by feeding worms food and can be ground up for plant nutriment or used directly on ash farming -/obj/item/worm_fertilizer +/obj/item/stack/worm_fertilizer name = "worm fertilizer" desc = "When you fed your worms, you should have expected this." icon = 'modular_skyrat/modules/ashwalkers/icons/misc_tools.dmi' icon_state = "fertilizer" grind_results = list(/datum/reagent/plantnutriment/eznutriment = 3, /datum/reagent/plantnutriment/left4zednutriment = 3, /datum/reagent/plantnutriment/robustharvestnutriment = 3) + singular_name = "fertilizer" + merge_type = /obj/item/stack/worm_fertilizer diff --git a/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm b/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm index a79f0dfb8833a0..a0882c288a15dd 100644 --- a/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm +++ b/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm @@ -10,16 +10,22 @@ /obj/item/seed_mesh/attackby(obj/item/attacking_item, mob/user, params) if(istype(attacking_item, /obj/item/stack/ore/glass)) var/obj/item/stack/stack_item = attacking_item - if(!do_after(user, 10 SECONDS, src)) - user.balloon_alert(user, "have to stand still!") - return - if(!stack_item.use(5)) - user.balloon_alert(user, "unable to use five of [stack_item]!") - return - if(prob(85)) - user.balloon_alert(user, "[stack_item] reveals nothing!") - return - var/spawn_seed = pick(subtypesof(/obj/item/seeds) - seeds_blacklist) - new spawn_seed(get_turf(src)) - user.balloon_alert(user, "[stack_item] revealed something!") + + while(stack_item.amount >= 5) + if(!do_after(user, 5 SECONDS, src)) + user.balloon_alert(user, "have to stand still!") + return + + if(!stack_item.use(5)) + user.balloon_alert(user, "unable to use five of [stack_item]!") + return + + if(prob(70)) + user.balloon_alert(user, "[stack_item] reveals nothing!") + continue + + var/spawn_seed = pick(subtypesof(/obj/item/seeds) - seeds_blacklist) + new spawn_seed(get_turf(src)) + user.balloon_alert(user, "[stack_item] revealed something!") + return ..() diff --git a/modular_skyrat/modules/ashwalkers/code/species/Ashwalkers.dm b/modular_skyrat/modules/ashwalkers/code/species/Ashwalkers.dm index 0e60d2ed7e90ce..7e41148ba1107b 100644 --- a/modular_skyrat/modules/ashwalkers/code/species/Ashwalkers.dm +++ b/modular_skyrat/modules/ashwalkers/code/species/Ashwalkers.dm @@ -95,7 +95,7 @@ to_chat(human_target, span_notice("Your body feels hotter...")) if(5) var/datum/action/cooldown/mob_cooldown/fire_breath/granted_action - granted_action = new() + granted_action = new(human_target) granted_action.Grant(human_target) to_chat(human_target, span_notice("Your throat feels larger...")) if(6 to INFINITY) diff --git a/modular_skyrat/modules/ashwalkers/code/turfs/closed_turfs.dm b/modular_skyrat/modules/ashwalkers/code/turfs/closed_turfs.dm new file mode 100644 index 00000000000000..54b4953671a439 --- /dev/null +++ b/modular_skyrat/modules/ashwalkers/code/turfs/closed_turfs.dm @@ -0,0 +1,48 @@ +/turf/closed/attackby(obj/item/attacking_item, mob/user, params) + if(istype(attacking_item, /obj/item/flashlight/flare/torch)) + return place_torch(attacking_item, user, params) + + return ..() + +// Try to place a torch on the wall such that we can only see it from one side +/turf/closed/proc/place_torch(obj/item/flashlight/flare/torch/torch_to_place, mob/user, params) + if(user.transferItemToLoc(torch_to_place, user.drop_location(), silent = FALSE)) + var/found_adjacent_turf = get_open_turf_in_dir(src, get_dir(src, user.loc)) + var/list/modifiers = params2list(params) + + // Center the icon where the user clicked. + if(LAZYACCESS(modifiers, ICON_X) && LAZYACCESS(modifiers, ICON_Y)) + //Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the wall turf) + torch_to_place.pixel_x = clamp(text2num(LAZYACCESS(modifiers, ICON_X)) - 16, -(world.icon_size/3), world.icon_size/3) + torch_to_place.pixel_y = clamp(text2num(LAZYACCESS(modifiers, ICON_Y)) - 16, -(world.icon_size/3), world.icon_size/3) + + // Try to put the torch in the adjacent turf relative to the user. This way it's not visible from the other side of the wall + if(found_adjacent_turf) + torch_to_place.forceMove(found_adjacent_turf) + else + torch_to_place.forceMove(src) // no open turfs for some reason + return TRUE + + // The item itself is in the adjacent turf, so we need to shift the icon one tile over to put it in the wall + switch(get_dir(found_adjacent_turf, src)) + if(NORTH) + torch_to_place.pixel_y += world.icon_size + if(SOUTH) + torch_to_place.pixel_y -= world.icon_size + if(EAST) + torch_to_place.pixel_x += world.icon_size + if(NORTHEAST) + torch_to_place.pixel_y += world.icon_size + torch_to_place.pixel_x += world.icon_size + if(SOUTHEAST) + torch_to_place.pixel_y -= world.icon_size + torch_to_place.pixel_x += world.icon_size + if(WEST) + torch_to_place.pixel_x -= world.icon_size + if(NORTHWEST) + torch_to_place.pixel_y += world.icon_size + torch_to_place.pixel_x -= world.icon_size + if(SOUTHWEST) + torch_to_place.pixel_y -= world.icon_size + torch_to_place.pixel_x -= world.icon_size + return TRUE diff --git a/modular_skyrat/modules/assault_operatives/code/interrogator.dm b/modular_skyrat/modules/assault_operatives/code/interrogator.dm index 6b59191a29bddd..c2876e4d36e2e7 100644 --- a/modular_skyrat/modules/assault_operatives/code/interrogator.dm +++ b/modular_skyrat/modules/assault_operatives/code/interrogator.dm @@ -196,7 +196,11 @@ for(var/datum/status_effect/goldeneye_pinpointer/iterating_pinpointer in GLOB.goldeneye_pinpointers) iterating_pinpointer.set_target(new_key) - notify_ghosts("GoldenEye key launched!", source = new_key, action = NOTIFY_ORBIT, header = "Something's Interesting!") + notify_ghosts("GoldenEye key launched!", + source = new_key, + action = NOTIFY_ORBIT, + header = "Something's Interesting!", + ) /obj/machinery/interrogator/proc/find_drop_turf() var/list/possible_turfs = list() diff --git a/modular_skyrat/modules/assault_operatives/code/sunbeam.dm b/modular_skyrat/modules/assault_operatives/code/sunbeam.dm index e05dea055ef807..4bea46d1ec782a 100644 --- a/modular_skyrat/modules/assault_operatives/code/sunbeam.dm +++ b/modular_skyrat/modules/assault_operatives/code/sunbeam.dm @@ -57,7 +57,11 @@ var/matrix/our_matrix = matrix() our_matrix.Scale(scale_x, scale_y) transform = our_matrix - notify_ghosts("An ICARUS sunbeam has been launched! [target_atom ? "Towards: [target_atom.name]" : ""]", source = src, action = NOTIFY_ORBIT, header = "Somethings burning!") + notify_ghosts("An ICARUS sunbeam has been launched! [target_atom ? "Towards: [target_atom.name]" : ""]", + source = src, + action = NOTIFY_ORBIT, + header = "Somethings burning!", + ) soundloop = new(src, TRUE) /obj/effect/sunbeam/Destroy(force) diff --git a/modular_skyrat/modules/awaymissions_skyrat/mothership_astrum/abductor_ai.dm b/modular_skyrat/modules/awaymissions_skyrat/mothership_astrum/abductor_ai.dm index 8d33efb03d5fae..19726907ae7cc9 100644 --- a/modular_skyrat/modules/awaymissions_skyrat/mothership_astrum/abductor_ai.dm +++ b/modular_skyrat/modules/awaymissions_skyrat/mothership_astrum/abductor_ai.dm @@ -3,7 +3,7 @@ */ /datum/ai_controller/basic_controller/abductor blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = HARD_CRIT, ) diff --git a/modular_skyrat/modules/barsigns/code/barsigns.dm b/modular_skyrat/modules/barsigns/code/barsigns.dm index 05193a0e337296..a8b9a8da449dab 100644 --- a/modular_skyrat/modules/barsigns/code/barsigns.dm +++ b/modular_skyrat/modules/barsigns/code/barsigns.dm @@ -1,228 +1,298 @@ -/datum/barsign/topmen +// Modularly set the correct icon file +/obj/machinery/barsign/update_icon_state() + . = ..() + // uses tg icon file + if(!istype(chosen_sign, /datum/barsign/skyrat) || icon_state == "empty") + icon = initial(icon) + return + + // uses modular icon file + if(istype(chosen_sign, /datum/barsign/skyrat/large)) + icon = SKYRAT_LARGE_BARSIGN_FILE + //Tannhauser Icon File + else if(istype(chosen_sign, /datum/barsign/skyrat/tan)) + icon = TAN_BAR_SIGNS + else + icon = SKYRAT_BARSIGN_FILE + +/datum/barsign/skyrat/topmen name = "Top Men" - icon = "topmen" + icon_state = "topmen" + neon_color = "#C2AACA" -/datum/barsign/spaceballgrille +/datum/barsign/skyrat/spaceballgrille name = "Spaceball Grille" - icon = "spaceballgrille" + icon_state = "spaceballgrille" + neon_color = "#827973" -/datum/barsign/clubee +/datum/barsign/skyrat/clubee name = "Club Bee" - icon = "clubee" + icon_state = "clubee" + neon_color = "#F2EEEE" -/datum/barsign/thesun +/datum/barsign/skyrat/thesun name = "The Sun" - icon = "thesun" + icon_state = "thesun" + neon_color = "#F8F0B8" -/datum/barsign/limbo +/datum/barsign/skyrat/limbo name = "The Limbo" - icon = "limbo" + icon_state = "limbo" desc = "A popular haunt for lost souls. The mood lighting is killer!" + neon_color = "#777777" -/datum/barsign/meadbay +/datum/barsign/skyrat/meadbay name = "Meadbay" - icon = "meadbay" + icon_state = "meadbay" + neon_color = "#EBB823" -/datum/barsign/cindikate +/datum/barsign/skyrat/cindikate name = "Cindi Kate's" - icon = "cindikate" + icon_state = "cindikate" + neon_color = "#FF3403" -/datum/barsign/theclownshead +/datum/barsign/skyrat/theclownshead name = "The Clown's Head" - icon = "theclownshead" + icon_state = "theclownshead" desc = "Home of Headdy, the honking clown head!" + neon_color = "#FFD800" -/datum/barsign/theorchard +/datum/barsign/skyrat/theorchard name = "The Orchard" - icon = "theorchard" + icon_state = "theorchard" + neon_color = "#CFFF47" -/datum/barsign/thesaucyclown +/datum/barsign/skyrat/thesaucyclown name = "The Saucy Clown" - icon = "thesaucyclown" + icon_state = "thesaucyclown" desc = "A known gathering site for the annual clown courtship rituals." + neon_color = "#FF66CC" -/datum/barsign/thedamnwall +/datum/barsign/skyrat/thedamnwall name = "The Damn Wall" - icon = "thedamnwall" + icon_state = "thedamnwall" desc = "When you're up against a wall, it's best to have stout friends and stout liquor right there beside you." + neon_color = "#CC3333" -/datum/barsign/whiskeyimplant +/datum/barsign/skyrat/whiskeyimplant name = "Whiskey Implant" - icon = "whiskeyimplant" + icon_state = "whiskeyimplant" + neon_color = "#E9F517" -/datum/barsign/carpecarp +/datum/barsign/skyrat/carpecarp name = "Carpe Carp" - icon = "carpecarp" + icon_state = "carpecarp" + neon_color = "#C717FE" -/datum/barsign/robustroadhouse +/datum/barsign/skyrat/robustroadhouse name = "Robust Roadhouse" - icon = "robustroadhouse" + icon_state = "robustroadhouse" + neon_color = "#F7A804" -/datum/barsign/theredshirt +/datum/barsign/skyrat/theredshirt name = "The Redshirt" - icon = "theredshirt" + icon_state = "theredshirt" + neon_color = "#FF92E0" -/datum/barsign/maltesefalconmk2 +/datum/barsign/skyrat/maltesefalconmk2 name = "Maltese Falcon MK2" - icon = "maltesefalconmk2" + icon_state = "maltesefalconmk2" desc = "The Maltese Falcon mark two, now extra hard boiled." + neon_color = "#E30000" -/datum/barsign/thecavernmk2 +/datum/barsign/skyrat/thecavernmk2 name = "The Cavern MK2" - icon = "thecavernmk2" + icon_state = "thecavernmk2" desc = "Fine drinks while listening to some fine tunes." + neon_color = "#AA9393" -/datum/barsign/lv426 +/datum/barsign/skyrat/lv426 name = "LV-426" - icon = "lv426" + icon_state = "lv426" desc = "Drinking with fancy facemasks is clearly more important than going to medbay." + neon_color = "#00F206" -/datum/barsign/zocalo +/datum/barsign/skyrat/zocalo name = "Zocalo" - icon = "zocalo" + icon_state = "zocalo" desc = "Anteriormente ubicado en Spessmerica." + neon_color = "#E5AF1C" -/datum/barsign/fourtheemprah +/datum/barsign/skyrat/fourtheemprah name = "4 The Emprah" - icon = "4theemprah" + icon_state = "4theemprah" desc = "Enjoyed by fanatics, heretics, and brain-damaged patrons alike." + neon_color = "#E5AF1C" -/datum/barsign/ishimura +/datum/barsign/skyrat/ishimura name = "Ishimura" - icon = "ishimura" + icon_state = "ishimura" desc = "Well known for their quality brownstar and delicious crackers." + neon_color = "#FF0000" -/datum/barsign/tardis +/datum/barsign/skyrat/tardis name = "Tardis" - icon = "tardis" + icon_state = "tardis" desc = "This establishment has been through at least 5,343 iterations." + neon_color = "#2739AA" -/datum/barsign/quarks +/datum/barsign/skyrat/quarks name = "Quark's" - icon = "quarks" + icon_state = "quarks" desc = "Frequenters of this establishment are often seen wearing meson scanners; how quaint." + neon_color = "#10E500" -/datum/barsign/tenforward +/datum/barsign/skyrat/tenforward name = "Ten Forward" - icon = "tenforward" + icon_state = "tenforward" + neon_color = "#E5AF1C" -/datum/barsign/thepranicngpony +/datum/barsign/skyrat/theprancingpony name = "The Prancing Pony" - icon = "thepranicngpony" + icon_state = "theprancingpony" desc = "Ok, we don't take to kindly to you short folk pokin' round looking for some ranger scum." + neon_color = "#FF9100" -/datum/barsign/vault13 +/datum/barsign/skyrat/vault13 name = "Vault 13" - icon = "vault13" + icon_state = "vault13" desc = "Coincidence is intentional." + neon_color = "#FFA800" -/* -/datum/barsign/thehive +/datum/barsign/skyrat/thehive name = "The Hive" - icon = "thehive" -*/ + icon_state = "thehive" + neon_color = "#FFC62A" -/datum/barsign/cantina +/datum/barsign/skyrat/cantina name = "Chalmun's Cantina" - icon = "cantina" + icon_state = "cantina" desc = "The bar was founded on the principles of originality; they have the same music playing 24/7." + neon_color = "#0078FF" -/datum/barsign/milliways42 +/datum/barsign/skyrat/milliways42 name = "Milliways 42" - icon = "milliways42" + icon_state = "milliways42" desc = "It's not really the end; it's the beginning, meaning, and answer for all your beverage needs." + neon_color = "#FF00F6" -/datum/barsign/timeofeve +/datum/barsign/skyrat/timeofeve name = "The Time of Eve" - icon = "thetimeofeve" + icon_state = "thetimeofeve" desc = "Vintage drinks from 2453!." + neon_color = "#EB52F8" -/datum/barsign/spaceasshole +/datum/barsign/skyrat/spaceasshole name = "Space Asshole" - icon = "spaceasshole" + icon_state = "spaceasshole" desc = "Open since 2125, Not much has changed since then; the engineers still release the singulo and the damn miners still are more likely to cave your face in that deliver ores." + neon_color = "#FF0000" -/datum/barsign/birdcage +/datum/barsign/skyrat/birdcage name = "The Bird Cage" - icon = "birdcage" + icon_state = "birdcage" desc = "Caw." + neon_color = "#FFD21E" -/datum/barsign/narsie +/datum/barsign/skyrat/narsie name = "Narsie Bistro" - icon = "narsiebistro" + icon_state = "narsiebistro" desc = "The last pub before the World's End." + neon_color = "#FF0000" -/datum/barsign/fallout +/datum/barsign/skyrat/fallout name = "The Booze Bunker" - icon = "boozebunker" + icon_state = "boozebunker" desc = "Never duck for cover without a drink!" + neon_color = "#FCC41B" -/datum/barsign/brokendreams +/datum/barsign/skyrat/brokendreams name = "The Cafe of Broken Dreams" - icon = "brokendreams" + icon_state = "brokendreams" desc = "Try our new dogmeat sliders!" + neon_color = "#E8E8A5" -/datum/barsign/toolboxtavern +/datum/barsign/skyrat/toolboxtavern name = "Toolbox Tavern" - icon = "toolboxtavern" + icon_state = "toolboxtavern" desc = "Free lodging with every Screwdriver purchased!" + neon_color = "" -/datum/barsign/blueoyster +/datum/barsign/skyrat/blueoyster name = "The Blue Oyster" - icon = "blueoyster" + icon_state = "blueoyster" desc = "The totally heterosexual bar for totally heterosexual men, just come inside and see." + neon_color = "" -/datum/barsign/foreign +/datum/barsign/skyrat/foreign name = "Foreign Food Sign" - icon = "foreign" + icon_state = "foreign" desc = "A sign written in some dead language advertising some non-descript foreign food." + neon_color = "" -/datum/barsign/commie +/datum/barsign/skyrat/commie name = "Prole's Preferred" - icon = "commie" + icon_state = "commie" desc = "The only bar you will ever need, comrade!" + neon_color = "#E46F6F" -/datum/barsign/brokenheros +/datum/barsign/skyrat/brokenheros name = "The Bar of Broken Heros" - icon = "brokenheros" + icon_state = "brokenheros" desc = "Do you enjoy hurting other people?" + neon_color = "" -/datum/barsign/sociallubricator +/datum/barsign/skyrat/sociallubricator name = "The Social Lubricator" - icon = "sociallubricator" + icon_state = "sociallubricator" desc = "The perfect thing to make you like people you hate." + neon_color = "" -/datum/barsign/chemlab +/datum/barsign/skyrat/chemlab name = "The Chem Lab" - icon = "chemlab" + icon_state = "chemlab" desc = "Try our new plasma martinis!" + neon_color = "" -/datum/barsign/mime +/datum/barsign/skyrat/mime name = "Moonshine Mime" - icon = "mime" + icon_state = "mime" desc = "Silent, not stirred." + neon_color = "" -/datum/barsign/clown +/datum/barsign/skyrat/clown name = "Honking Clown" - icon = "clown" + icon_state = "clown" desc = "Bananas not included." + neon_color = "" -/datum/barsign/progressive +/datum/barsign/skyrat/progressive name = "A Modern and Progressive Tavern" - icon = "progressive" + icon_state = "progressive" desc = "Whatever that means." + neon_color = "#DB9B9A" -/datum/barsign/va11halla +/datum/barsign/skyrat/va11halla name = "VA-11 HALL-A" - icon = "va11halla" + icon_state = "va11halla" desc = "Not as dangerous as N1-RV Ann-A." + neon_color = "#FB3F7D" -/datum/barsign/squatopia +/datum/barsign/skyrat/squatopia name = "Squatopia" - icon = "squatopia" + icon_state = "squatopia" desc = "The crystal belonged to my father. He was murdered." + neon_color = "#CC0033" -/datum/barsign/bug +/datum/barsign/skyrat/bug name = "The Hungry Bug" - icon = "hungrybug" + icon_state = "hungrybug" desc = "Stop by and enjoy some of the Hole's famous gyoza!" + neon_color = "#E2B001" + +// 96x96 signs + +/datum/barsign/skyrat/large/cyberslyph + name = "Cyberslyph" + icon_state = "cyberslyph" + neon_color = "#00FFFF" diff --git a/modular_skyrat/modules/barsigns/icons/barsigns.dmi b/modular_skyrat/modules/barsigns/icons/barsigns.dmi index 81091896ad9949..5bd7d1d9d744b3 100644 Binary files a/modular_skyrat/modules/barsigns/icons/barsigns.dmi and b/modular_skyrat/modules/barsigns/icons/barsigns.dmi differ diff --git a/modular_skyrat/modules/barsigns/icons/barsigns96x96.dmi b/modular_skyrat/modules/barsigns/icons/barsigns96x96.dmi new file mode 100644 index 00000000000000..8555459396150f Binary files /dev/null and b/modular_skyrat/modules/barsigns/icons/barsigns96x96.dmi differ diff --git a/modular_skyrat/modules/better_vox/code/vox_species.dm b/modular_skyrat/modules/better_vox/code/vox_species.dm index 8297588001cc44..4d3f1b237c9586 100644 --- a/modular_skyrat/modules/better_vox/code/vox_species.dm +++ b/modular_skyrat/modules/better_vox/code/vox_species.dm @@ -8,7 +8,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_MUTANT_COLORS, ) diff --git a/modular_skyrat/modules/black_mesa/code/mobs/headcrab.dm b/modular_skyrat/modules/black_mesa/code/mobs/headcrab.dm index 75e473b919643e..e7afbf7aae7475 100644 --- a/modular_skyrat/modules/black_mesa/code/mobs/headcrab.dm +++ b/modular_skyrat/modules/black_mesa/code/mobs/headcrab.dm @@ -40,14 +40,10 @@ /mob/living/simple_animal/hostile/blackmesa/xen/headcrab/Initialize(mapload) . = ..() - charge = new /datum/action/cooldown/mob_cooldown/charge/basic_charge() + charge = new(src) charge.Grant(src) charge.cooldown_time = 0 -/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/Destroy() - QDEL_NULL(charge) - return ..() - /mob/living/simple_animal/hostile/blackmesa/xen/headcrab/Shoot(atom/targeted_atom) throw_at(targeted_atom, throw_at_range, throw_at_speed) playsound( diff --git a/modular_skyrat/modules/black_mesa/code/mobs/houndeye.dm b/modular_skyrat/modules/black_mesa/code/mobs/houndeye.dm index f7e4c70a6ce235..ee0ee204d3e5d4 100644 --- a/modular_skyrat/modules/black_mesa/code/mobs/houndeye.dm +++ b/modular_skyrat/modules/black_mesa/code/mobs/houndeye.dm @@ -39,11 +39,11 @@ /mob/living/simple_animal/hostile/blackmesa/xen/houndeye/Initialize(mapload) . = ..() - charge = new /datum/action/cooldown/mob_cooldown/charge/basic_charge() + charge = new(src) charge.Grant(src) /mob/living/simple_animal/hostile/blackmesa/xen/houndeye/Destroy() - QDEL_NULL(charge) + charge = null return ..() /mob/living/simple_animal/hostile/blackmesa/xen/houndeye/OpenFire() diff --git a/modular_skyrat/modules/bodyparts/code/moth_bodyparts.dm b/modular_skyrat/modules/bodyparts/code/moth_bodyparts.dm index 80dadd5005a839..3f55ec933938da 100644 --- a/modular_skyrat/modules/bodyparts/code/moth_bodyparts.dm +++ b/modular_skyrat/modules/bodyparts/code/moth_bodyparts.dm @@ -12,6 +12,7 @@ icon_state = "moth_chest_m" limb_id = SPECIES_MOTH is_dimorphic = TRUE + wing_types = list(/obj/item/organ/external/wings/functional/moth/megamoth, /obj/item/organ/external/wings/functional/moth/mothra) /obj/item/bodypart/arm/left/moth icon = BODYPART_ICON_MOTH diff --git a/modular_skyrat/modules/bodyparts/code/snail_bodyparts.dm b/modular_skyrat/modules/bodyparts/code/snail_bodyparts.dm index 3dae7d44d8322d..9a4c166922cd44 100644 --- a/modular_skyrat/modules/bodyparts/code/snail_bodyparts.dm +++ b/modular_skyrat/modules/bodyparts/code/snail_bodyparts.dm @@ -1,3 +1,5 @@ +// MODULAR SNAIL OVERRIDES + /obj/item/bodypart/head/snail icon_greyscale = DEFAULT_BODYPART_ICON_ORGANIC head_flags = HEAD_HAIR|HEAD_FACIAL_HAIR|HEAD_EYESPRITES|HEAD_EYECOLOR|HEAD_DEBRAIN @@ -7,12 +9,20 @@ /obj/item/bodypart/arm/left/snail icon_greyscale = DEFAULT_BODYPART_ICON_ORGANIC + unarmed_damage_low = 1 // Roundstart Snails - Lowest possible punch damage. if this is set to 0, punches will always miss. + unarmed_damage_high = 5 // Roundstart Snails - A Bit More damage. /obj/item/bodypart/arm/right/snail icon_greyscale = DEFAULT_BODYPART_ICON_ORGANIC + unarmed_damage_low = 1 + unarmed_damage_high = 5 /obj/item/bodypart/leg/left/snail icon_greyscale = DEFAULT_BODYPART_ICON_ORGANIC + unarmed_damage_low = 1. + unarmed_damage_high = 5 /obj/item/bodypart/leg/right/snail icon_greyscale = DEFAULT_BODYPART_ICON_ORGANIC + unarmed_damage_low = 1 + unarmed_damage_high = 5 diff --git a/modular_skyrat/modules/clock_cult/code/items/clockwork_slab.dm b/modular_skyrat/modules/clock_cult/code/items/clockwork_slab.dm index 0f4efdd56927ca..8f8f51379ea662 100644 --- a/modular_skyrat/modules/clock_cult/code/items/clockwork_slab.dm +++ b/modular_skyrat/modules/clock_cult/code/items/clockwork_slab.dm @@ -119,7 +119,7 @@ GLOBAL_LIST_INIT(clockwork_slabs, list()) qdel(quick_bound_scriptures[position]) //Put the quickbound action onto the slab, the slab should grant when picked up - var/datum/action/innate/clockcult/quick_bind/quickbound = new + var/datum/action/innate/clockcult/quick_bind/quickbound = new(src) quickbound.scripture = spell quickbound.slab_weakref = WEAKREF(src) quick_bound_scriptures[position] = quickbound diff --git a/modular_skyrat/modules/clock_cult/code/items/integration_cog.dm b/modular_skyrat/modules/clock_cult/code/items/integration_cog.dm index 9fa27cddafd68f..a906f8a3b50316 100644 --- a/modular_skyrat/modules/clock_cult/code/items/integration_cog.dm +++ b/modular_skyrat/modules/clock_cult/code/items/integration_cog.dm @@ -47,7 +47,12 @@ addtimer(CALLBACK(src, PROC_REF(finish_setup), cogger_apc), SET_UP_TIME) send_clock_message(null, span_brass(span_bold("[user] has installed an integration cog into [cogger_apc].")), msg_ghosts = FALSE) - notify_ghosts("[user] has installed an integration cog into [cogger_apc]", source = user, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Integration cog") + notify_ghosts("[user] has installed an integration cog into [cogger_apc]", + source = user, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Integration cog", + ) /// Finish setting up the cog 5 minutes after insertion diff --git a/modular_skyrat/modules/clock_cult/code/mobs/clockwork_marauder.dm b/modular_skyrat/modules/clock_cult/code/mobs/clockwork_marauder.dm index 08ef285d89cf95..dcf1b0a556f75c 100644 --- a/modular_skyrat/modules/clock_cult/code/mobs/clockwork_marauder.dm +++ b/modular_skyrat/modules/clock_cult/code/mobs/clockwork_marauder.dm @@ -48,7 +48,7 @@ GLOBAL_LIST_EMPTY(clockwork_marauders) if(length(loot)) AddElement(/datum/element/death_drops, loot) - var/datum/action/innate/clockcult/comm/communicate = new + var/datum/action/innate/clockcult/comm/communicate = new(src) communicate.Grant(src) GLOB.clockwork_marauders += src @@ -119,7 +119,7 @@ GLOBAL_LIST_EMPTY(clockwork_marauders) /datum/ai_controller/basic_controller/clockwork_marauder blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = HARD_CRIT, ) diff --git a/modular_skyrat/modules/clock_cult/code/outpost_of_cogs.dm b/modular_skyrat/modules/clock_cult/code/outpost_of_cogs.dm index 09a45e67d797c8..a5b0439908ce06 100644 --- a/modular_skyrat/modules/clock_cult/code/outpost_of_cogs.dm +++ b/modular_skyrat/modules/clock_cult/code/outpost_of_cogs.dm @@ -43,7 +43,12 @@ atom_area = get_area(atom_turf) send_clock_message(null, "A portal has been opened at [atom_area] to our holy city, it is a glorious day in the name of Ratvar.", "", msg_ghosts = FALSE) - notify_ghosts("A portal has been opened at [atom_area] to our holy city, it is a glorious day in the name of Ratvar.", source = atom_area, action = NOTIFY_JUMP, flashwindow = FALSE, header = "Portal to Reebe") + notify_ghosts("A portal has been opened at [atom_area] to our holy city, it is a glorious day in the name of Ratvar.", + source = atom_area, + action = NOTIFY_JUMP, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Portal to Reebe", + ) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reebe_station_warning), atom_area, portal), 5 MINUTES) diff --git a/modular_skyrat/modules/clock_cult/code/scriptures/_scripture.dm b/modular_skyrat/modules/clock_cult/code/scriptures/_scripture.dm index ad8f096188b181..e37db5b30ddfcb 100644 --- a/modular_skyrat/modules/clock_cult/code/scriptures/_scripture.dm +++ b/modular_skyrat/modules/clock_cult/code/scriptures/_scripture.dm @@ -261,7 +261,7 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) /datum/scripture/slab/New() . = ..() - pointed_spell = new + pointed_spell = new(src) pointed_spell.name = src.name pointed_spell.deactive_msg = "" pointed_spell.parent_scripture = src diff --git a/modular_skyrat/modules/clock_cult/code/structures/technologists_lectern.dm b/modular_skyrat/modules/clock_cult/code/structures/technologists_lectern.dm index 01ce5c1a3093f0..676ec9de62e2b7 100644 --- a/modular_skyrat/modules/clock_cult/code/structures/technologists_lectern.dm +++ b/modular_skyrat/modules/clock_cult/code/structures/technologists_lectern.dm @@ -65,8 +65,12 @@ primary_researcher = FALSE log_game("A research ritual of [selected_research] was cancelled by deconstruction of [src].") send_clock_message(null, "A research ritual has been disrupted in [get_area(src)]! All research data has been lost.", msg_ghosts = FALSE) - notify_ghosts("A research ritual was disrupted in [get_area(src)]", source = get_turf(src), action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Research ritual cancelled") - + notify_ghosts("A research ritual was disrupted in [get_area(src)]", + source = get_turf(src), + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Research ritual cancelled", + ) return ..() @@ -295,7 +299,12 @@ playsound(target_turf, 'modular_skyrat/modules/clock_cult/sound/machinery/ark_deathrattle.ogg', 80, FALSE, pressure_affected = FALSE) research_sigil = new(target_turf) send_clock_message(null, "A research ritual has begun in [get_area(src)], ensure nobody stops it until it is completed in [DisplayTimeText(selected_research.time_to_research)]!", msg_ghosts = FALSE) - notify_ghosts("[owner] has begun a research ritual in [get_area(src)]", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Research ritual") + notify_ghosts("[owner] has begun a research ritual in [get_area(src)]", + source = src, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Research ritual" + ) log_game("[owner] began a research ritual of [selected_research.name] in [get_area(src)].") research_timer_id = addtimer(CALLBACK(src, PROC_REF(finish_research), owner), selected_research.time_to_research, TIMER_STOPPABLE) @@ -337,7 +346,12 @@ return send_clock_message(null, "The research ritual in [get_area(src)] has completed, rejoice!", msg_ghosts = FALSE) - notify_ghosts("A research ritual in [get_area(src)] has been completed", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Research ritual completed") + notify_ghosts("A research ritual in [get_area(src)] has been completed", + source = src, + action = NOTIFY_ORBIT, + notify_flags = NOTIFY_CATEGORY_NOFLASH, + header = "Research ritual completed", + ) log_game("Finished a research ritual of [selected_research.name] in [get_area(src)].") researching = FALSE diff --git a/modular_skyrat/modules/company_imports/code/armament_datums/nri_military_surplus.dm b/modular_skyrat/modules/company_imports/code/armament_datums/nri_military_surplus.dm index 6b42acec49785c..840d7685de4a80 100644 --- a/modular_skyrat/modules/company_imports/code/armament_datums/nri_military_surplus.dm +++ b/modular_skyrat/modules/company_imports/code/armament_datums/nri_military_surplus.dm @@ -38,6 +38,36 @@ item_type = /obj/item/clothing/suit/armor/vest/cin_surplus_vest cost = PAYCHECK_COMMAND +/datum/armament_entry/company_import/nri_surplus/clothing/police_uniform + item_type = /obj/item/clothing/under/colonial/nri_police + cost = PAYCHECK_CREW + restricted = TRUE + +/datum/armament_entry/company_import/nri_surplus/clothing/police_cloak + item_type = /obj/item/clothing/neck/cloak/colonial/nri_police + cost = PAYCHECK_CREW + restricted = TRUE + +/datum/armament_entry/company_import/nri_surplus/clothing/police_cap + item_type = /obj/item/clothing/head/hats/colonial/nri_police + cost = PAYCHECK_CREW + restricted = TRUE + +/datum/armament_entry/company_import/nri_surplus/clothing/police_mask + item_type = /obj/item/clothing/mask/gas/nri_police + cost = PAYCHECK_CREW*2 + restricted = TRUE + +/datum/armament_entry/company_import/nri_surplus/clothing/police_vest + item_type = /obj/item/clothing/head/helmet/nri_police + cost = PAYCHECK_COMMAND + restricted = TRUE + +/datum/armament_entry/company_import/nri_surplus/clothing/police_helmet + item_type = /obj/item/clothing/suit/armor/vest/nri_police + cost = PAYCHECK_COMMAND + restricted = TRUE + // Random surplus store tier stuff, flags, old rations, multitools you'll never use, so on /datum/armament_entry/company_import/nri_surplus/misc diff --git a/modular_skyrat/modules/cortical_borer/code/cortical_borer.dm b/modular_skyrat/modules/cortical_borer/code/cortical_borer.dm index 258cd9463d67b9..4c35890f8d27fa 100644 --- a/modular_skyrat/modules/cortical_borer/code/cortical_borer.dm +++ b/modular_skyrat/modules/cortical_borer/code/cortical_borer.dm @@ -221,7 +221,7 @@ GLOBAL_LIST_EMPTY(cortical_borers) reagent_holder = new /obj/item/reagent_containers/borer(src) for(var/action_type in known_abilities) - var/datum/action/attack_action = new action_type() + var/datum/action/attack_action = new action_type(src) attack_action.Grant(src) if(mind) diff --git a/modular_skyrat/modules/cortical_borer/code/cortical_borer_egg.dm b/modular_skyrat/modules/cortical_borer/code/cortical_borer_egg.dm index 29829dac8b063f..49af4f3a5bab8b 100644 --- a/modular_skyrat/modules/cortical_borer/code/cortical_borer_egg.dm +++ b/modular_skyrat/modules/cortical_borer/code/cortical_borer_egg.dm @@ -41,7 +41,12 @@ forceMove(host_egg) var/area/src_area = get_area(src) if(src_area) - notify_ghosts("A cortical borer egg has been laid in \the [src_area.name].", source = src, action = NOTIFY_PLAY, flashwindow = FALSE, ignore_key = POLL_IGNORE_DRONE, notify_suiciders = FALSE) + notify_ghosts("A cortical borer egg has been laid in \the [src_area.name].", + source = src, + action = NOTIFY_PLAY, + notify_flags = NOTIFY_CATEGORY_NOFLASH & ~GHOST_NOTIFY_NOTIFY_SUICIDERS, + ignore_key = POLL_IGNORE_DRONE, + ) /obj/item/borer_egg name = "borer egg" diff --git a/modular_skyrat/modules/cortical_borer/code/evolution/evolution_diveworm.dm b/modular_skyrat/modules/cortical_borer/code/evolution/evolution_diveworm.dm index 5a07e43d31315e..b04370d6c29bde 100644 --- a/modular_skyrat/modules/cortical_borer/code/evolution/evolution_diveworm.dm +++ b/modular_skyrat/modules/cortical_borer/code/evolution/evolution_diveworm.dm @@ -107,5 +107,5 @@ /datum/borer_evolution/diveworm/empowered_offspring/on_evolve(mob/living/basic/cortical_borer/cortical_owner) . = ..() - var/datum/action/cooldown/borer/empowered_offspring/attack_action = new() + var/datum/action/cooldown/borer/empowered_offspring/attack_action = new(cortical_owner) attack_action.Grant(cortical_owner) diff --git a/modular_skyrat/modules/cortical_borer/code/evolution/evolution_hivelord.dm b/modular_skyrat/modules/cortical_borer/code/evolution/evolution_hivelord.dm index ca5e11883524d2..be06cc5d7f4154 100644 --- a/modular_skyrat/modules/cortical_borer/code/evolution/evolution_hivelord.dm +++ b/modular_skyrat/modules/cortical_borer/code/evolution/evolution_hivelord.dm @@ -12,7 +12,7 @@ /datum/borer_evolution/hivelord/produce_offspring/on_evolve(mob/living/basic/cortical_borer/cortical_owner) . = ..() - var/datum/action/cooldown/borer/produce_offspring/attack_action = new() + var/datum/action/cooldown/borer/produce_offspring/attack_action = new(cortical_owner) attack_action.Grant(cortical_owner) // T2 @@ -25,7 +25,7 @@ /datum/borer_evolution/hivelord/blood_chemical/on_evolve(mob/living/basic/cortical_borer/cortical_owner) . = ..() - var/datum/action/cooldown/borer/learn_bloodchemical/attack_action = new() + var/datum/action/cooldown/borer/learn_bloodchemical/attack_action = new(cortical_owner) attack_action.Grant(cortical_owner) // T3 @@ -51,7 +51,7 @@ /datum/borer_evolution/hivelord/stealth_mode/on_evolve(mob/living/basic/cortical_borer/cortical_owner) . = ..() - var/datum/action/cooldown/borer/stealth_mode/attack_action = new() + var/datum/action/cooldown/borer/stealth_mode/attack_action = new(cortical_owner) attack_action.Grant(cortical_owner) // T5 diff --git a/modular_skyrat/modules/cortical_borer/code/evolution/evolution_symbiote.dm b/modular_skyrat/modules/cortical_borer/code/evolution/evolution_symbiote.dm index 2cdc66addbb416..4eb5005883711b 100644 --- a/modular_skyrat/modules/cortical_borer/code/evolution/evolution_symbiote.dm +++ b/modular_skyrat/modules/cortical_borer/code/evolution/evolution_symbiote.dm @@ -12,7 +12,7 @@ /datum/borer_evolution/symbiote/willing_host/on_evolve(mob/living/basic/cortical_borer/cortical_owner) . = ..() - var/datum/action/cooldown/borer/willing_host/attack_action = new() + var/datum/action/cooldown/borer/willing_host/attack_action = new(cortical_owner) attack_action.Grant(cortical_owner) // T2 @@ -107,6 +107,6 @@ /datum/borer_evolution/symbiote/revive_host/on_evolve(mob/living/basic/cortical_borer/cortical_owner) . = ..() - var/datum/action/cooldown/borer/revive_host/attack_action = new() + var/datum/action/cooldown/borer/revive_host/attack_action = new(cortical_owner) attack_action.Grant(cortical_owner) diff --git a/modular_skyrat/modules/customization/modules/clothing/~donator/donator_clothing.dm b/modular_skyrat/modules/customization/modules/clothing/~donator/donator_clothing.dm index 262316c5da5bf7..789c416331a9f8 100644 --- a/modular_skyrat/modules/customization/modules/clothing/~donator/donator_clothing.dm +++ b/modular_skyrat/modules/customization/modules/clothing/~donator/donator_clothing.dm @@ -374,32 +374,26 @@ supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON // Donation reward for TheOOZ -/obj/item/clothing/mask/animal/kindle +/obj/item/clothing/mask/animal/wolf name = "wolf mask" - desc = "A dark mask in the shape of a wolf's head.
The material feels like it's made entirely out of inexpensive plastic." + desc = "A dark mask in the shape of a wolf's head." icon = 'modular_skyrat/master_files/icons/donator/obj/clothing/masks.dmi' icon_state = "kindle" worn_icon = 'modular_skyrat/master_files/icons/donator/mob/clothing/mask.dmi' inhand_icon_state = "gasmask_captain" animal_type = "wolf" - animal_sounds = list("Awoo!", "Woof.", "Arf!") - animal_sounds_alt_probability = 15 - animal_sounds_alt = list("Join us!", "Wear the mask.") - curse_spawn_sound = 'modular_skyrat/master_files/sound/effects/wolfhead_curse.ogg' - cursed = FALSE - - supports_variations_flags = NONE - clothing_flags = MASKINTERNALS | VOICEBOX_DISABLED | VOICEBOX_TOGGLABLE - flags_inv = HIDEFACIALHAIR | HIDESNOUT + unique_death = 'modular_skyrat/master_files/sound/effects/wolfhead_curse.ogg' visor_flags_inv = HIDEFACIALHAIR | HIDESNOUT + flags_cover = MASKCOVERSMOUTH | MASKCOVERSEYES | PEPPERPROOF + visor_flags_cover = MASKCOVERSMOUTH | MASKCOVERSEYES | PEPPERPROOF + clothing_flags = VOICEBOX_DISABLED | MASKINTERNALS | BLOCK_GAS_SMOKE_EFFECT | GAS_FILTERING alternate_worn_layer = ABOVE_BODY_FRONT_HEAD_LAYER - w_class = WEIGHT_CLASS_SMALL + use_radio_beeps_tts = TRUE -/obj/item/clothing/mask/animal/kindle/make_cursed() +/obj/item/clothing/mask/animal/wolf/Initialize(mapload) . = ..() - clothing_flags = initial(clothing_flags) - name = "\proper the accursed wolf mask" - desc = "The mask which belongs to Nanotrasen's Outpost Captain Kindle, it is the symbol of her alleged cult.
It looks like a [animal_type] mask, but closer inspection reveals it's melded onto this person's face!" + var/obj/item/clothing/mask/gas/sechailer/sechailer_type = /obj/item/clothing/mask/gas/sechailer + voice_filter = initial(sechailer_type.voice_filter) // Donation reward for Random516 /obj/item/clothing/head/drake_skull @@ -1492,7 +1486,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/poster/contraband/korpstech, 32) // Donation reward for MaSvedish /obj/item/clothing/mask/holocigarette/masvedishcigar name = "holocigar" - desc = "A soft buzzing device that, using holodeck technology, replicates a slow burn cigar. Now with less-shock technology." + desc = "A soft buzzing device that, using holodeck technology, replicates a slow burn cigar. Now with less-shock technology. It has a small inscription of 'MG' on the golden label." icon = 'modular_skyrat/master_files/icons/donator/obj/clothing/masks.dmi' worn_icon = 'modular_skyrat/master_files/icons/donator/mob/clothing/mask.dmi' lefthand_file = 'modular_skyrat/master_files/icons/donator/mob/inhands/donator_left.dmi' diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ipc.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ipc.dm index 8e19d245eee2b1..8b71ed81001a18 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ipc.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ipc.dm @@ -18,6 +18,10 @@ name = "Blank" icon_state = "blank" +/datum/sprite_accessory/screen/blank_white + name = "Blank White" + icon_state = "blankwhite" + /datum/sprite_accessory/screen/pink name = "Pink" icon_state = "pink" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm index b87946aaf37c88..357e827e744a3a 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm @@ -182,11 +182,6 @@ GLOBAL_LIST_EMPTY(customizable_races) species_human.apply_overlay(BODY_LAYER) handle_mutant_bodyparts(species_human) -//I wag in death -/datum/species/spec_death(gibbed, mob/living/carbon/human/H) - if(H) - stop_wagging_tail(H) - /datum/species/spec_stun(mob/living/carbon/human/H,amount) if(H) stop_wagging_tail(H) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm index c226914c1e7336..19492ef44561fb 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm @@ -22,7 +22,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_WATER_BREATHING, TRAIT_SLICK_SKIN, diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm index 910c49229b7b80..80aa57ca8cacff 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm @@ -4,7 +4,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_WATER_BREATHING, TRAIT_MUTANT_COLORS, diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/dwarf.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/dwarf.dm index 1d15db5f5aed15..76c3bb57fec929 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/dwarf.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/dwarf.dm @@ -6,7 +6,6 @@ TRAIT_DWARF,TRAIT_SNOB, TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_USES_SKINTONES, ) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm index 13f496d57109db..6f721354cd50c4 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm @@ -12,7 +12,6 @@ TRAIT_NOBREATH, TRAIT_OXYIMMUNE, TRAIT_VIRUSIMMUNE, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_DRINKS_BLOOD, TRAIT_USES_SKINTONES, diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm index 76d1feab513a7b..41f3715e8ca4b3 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm @@ -4,7 +4,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_MUTANT_COLORS, ) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm index ef6afc7788db04..50f2cbec142971 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm @@ -4,7 +4,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_MUTANT_COLORS, ) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm index 213e9bfbc91a09..dd938a43e21a06 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm @@ -48,7 +48,6 @@ inherent_traits = list( TRAIT_NO_UNDERWEAR, TRAIT_MUTANT_COLORS, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_TACKLING_TAILED_DEFENDER, ) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm index 6e7d9ae4f2c8bc..801695b42743d0 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm @@ -4,7 +4,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_MUTANT_COLORS, ) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm index 80dc243d476a03..6628060ee92e64 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm @@ -7,7 +7,6 @@ ) inherent_traits = list( TRAIT_HAS_MARKINGS, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_TACKLING_WINGED_ATTACKER, TRAIT_ANTENNAE, TRAIT_MUTANT_COLORS, diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm index aa9d14b5e5a5a0..47cd5be08c0861 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm @@ -4,7 +4,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_MUTANT_COLORS, ) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm index abc27ee7f69697..e5739b23624d69 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm @@ -4,7 +4,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_HATED_BY_DOGS, TRAIT_MUTANT_COLORS, diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm index 13d460bc109f6d..c744097639af87 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm @@ -4,7 +4,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_MUTANT_COLORS, ) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm index f5bb77bb668599..059019f249e493 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm @@ -7,7 +7,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_MUTANT_COLORS, ) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm index e1d819db3e0362..62e001c5f74b55 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm @@ -4,7 +4,6 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_MUTANT_COLORS, ) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm index acbf904da439f5..b4dbe25250388d 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm @@ -6,12 +6,11 @@ inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_LITERATE, TRAIT_MUTANT_COLORS, ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID - mutanttongue = /obj/item/organ/internal/tongue/xeno + mutanttongue = /obj/item/organ/internal/tongue/xeno_hybrid mutant_bodyparts = list() default_mutant_bodyparts = list( "tail" = "Xenomorph Tail", diff --git a/modular_skyrat/modules/encounters/code/nri_raiders.dm b/modular_skyrat/modules/encounters/code/nri_raiders.dm index 7ea6847ff4ead9..e6c77180d4ecfa 100644 --- a/modular_skyrat/modules/encounters/code/nri_raiders.dm +++ b/modular_skyrat/modules/encounters/code/nri_raiders.dm @@ -107,6 +107,7 @@ GLOBAL_VAR(first_officer) var/obj/item/card/id/id_card = equipped.wear_id if(istype(id_card)) id_card.registered_name = equipped.real_name + id_card.update_icon() id_card.update_label() handlebank(equipped) @@ -114,13 +115,13 @@ GLOBAL_VAR(first_officer) /datum/outfit/pirate/nri/officer name = "NRI Field Officer" - head = /obj/item/clothing/head/beret/sec/nri + head = /obj/item/clothing/head/hats/colonial/nri_police glasses = /obj/item/clothing/glasses/sunglasses ears = /obj/item/radio/headset/guild/command mask = null - neck = /obj/item/clothing/neck/security_cape/armplate + neck = /obj/item/clothing/neck/cloak/colonial/nri_police - uniform = /obj/item/clothing/under/costume/nri/captain + uniform = /obj/item/clothing/under/colonial/nri_police suit = null gloves = /obj/item/clothing/gloves/combat @@ -129,49 +130,52 @@ GLOBAL_VAR(first_officer) belt = /obj/item/storage/belt/security/nri back = /obj/item/storage/backpack/satchel/leather - backpack_contents = list(/obj/item/storage/box/nri_survival_pack/raider = 1, /obj/item/ammo_box/magazine/m9mm_aps = 3, /obj/item/gun/ballistic/automatic/pistol/nri = 1, /obj/item/crucifix = 1, /obj/item/clothing/mask/gas/hecu2 = 1, /obj/item/modular_computer/pda/security = 1) + backpack_contents = list( + /obj/item/storage/box/nri_survival_pack/raider = 1, + /obj/item/ammo_box/magazine/m9mm_aps = 3, + /obj/item/gun/ballistic/automatic/pistol/nri = 1, + /obj/item/crucifix = 1, + /obj/item/clothing/mask/gas/nri_police = 1, + /obj/item/modular_computer/pda/nri_police = 1, + ) l_pocket = /obj/item/folder/blue/nri_cop r_pocket = /obj/item/storage/pouch/ammo - id = /obj/item/card/id/advanced - id_trim = /datum/id_trim/nri_raider/officer - -/datum/id_trim/nri_raider/officer - assignment = "NRI Field Officer" - -/datum/outfit/pirate/nri/marine - name = "NRI Marine" - - head = null - glasses = /obj/item/clothing/glasses/sunglasses - ears = /obj/item/radio/headset/guild - mask = null - - uniform = /obj/item/clothing/under/costume/nri - suit = null - - gloves = /obj/item/clothing/gloves/combat - - shoes = /obj/item/clothing/shoes/combat - - belt = /obj/item/storage/belt/security/nri - back = /obj/item/storage/backpack/satchel/leather - backpack_contents = list(/obj/item/storage/box/nri_survival_pack/raider = 1, /obj/item/crucifix = 1, /obj/item/ammo_box/magazine/m9mm = 3, /obj/item/clothing/mask/gas/hecu2 = 1, /obj/item/modular_computer/pda/security = 1) - l_pocket = /obj/item/gun/ballistic/automatic/pistol - r_pocket = /obj/item/storage/pouch/ammo + id = /obj/item/card/id/advanced/nri_police + id_trim = /datum/id_trim/nri_police + +/obj/item/modular_computer/pda/nri_police + name = "\improper NRI police PDA" + device_theme = PDA_THEME_TERMINAL + greyscale_colors = "#363655#7878f7" + comp_light_luminosity = 6.3 //Matching a flashlight + comp_light_color = "#5c20aa" //Simulated ultraviolet light for finding blood and :flushed: + starting_programs = list( + /datum/computer_file/program/records/security, + /datum/computer_file/program/crew_manifest, + /datum/computer_file/program/robocontrol, + ) + inserted_item = /obj/item/pen/fourcolor - id = /obj/item/card/id/advanced - id_trim = /datum/id_trim/nri_raider +/obj/item/card/id/advanced/nri_police + name = "\improper NRI police identification card" + desc = "A retro-looking card model modified to work with the modern identification systems." + icon = 'modular_skyrat/master_files/icons/obj/card.dmi' + icon_state = "card_nri_police" + assigned_icon_state = "assigned_nri_police" -/datum/id_trim/nri_raider - assignment = "NRI Marine" +/datum/id_trim/nri_police + assignment = "NRI Field Officer" trim_icon = 'modular_skyrat/master_files/icons/obj/card.dmi' - trim_state = "trim_nri" - department_color = COLOR_RED_LIGHT - subdepartment_color = COLOR_COMMAND_BLUE - sechud_icon_state = "hud_nri" + trim_state = "trim_nri_police" + department_color = COLOR_NRI_POLICE_BLUE + subdepartment_color = COLOR_NRI_POLICE_SILVER + sechud_icon_state = "hud_nri_police" access = list(ACCESS_SYNDICATE, ACCESS_MAINT_TUNNELS) +/obj/item/gun/energy/e_gun/advtaser/normal + w_class = WEIGHT_CLASS_NORMAL + /obj/effect/mob_spawn/ghost_role/human/nri_raider name = "NRI Raider sleeper" desc = "Cozy. You get the feeling you aren't supposed to be here, though..." @@ -183,7 +187,7 @@ GLOBAL_VAR(first_officer) you_are_text = "You are a Novaya Rossiyskaya Imperiya task force." flavour_text = "The station has refused to pay the fine for breaking Imperial regulations, you are here to recover the debt. Do so by demanding the funds. Force approach is usually recommended, but isn't the only method." important_text = "Allowed races are humans, Akulas, IPCs. Follow your field officer's orders. Important mention - while you are listed as the pirates gamewise, you really aren't lore-and-everything-else-wise. Roleplay accordingly." - outfit = /datum/outfit/pirate/nri/marine + outfit = /datum/outfit/pirate/nri restricted_species = list(/datum/species/human, /datum/species/akula, /datum/species/synthetic) random_appearance = FALSE show_flavor = TRUE @@ -255,8 +259,10 @@ GLOBAL_VAR(first_officer) var/obj/item/card/id/advanced/card = spawned_human.get_idcard() if(GLOB.first_officer == spawned_human) card.assignment = pick(NRI_LEADER_JOB_LIST) + card.trim.sechud_icon_state = "hud_nri_police_lead" else card.assignment = pick(NRI_JOB_LIST) + card.trim.sechud_icon_state = "hud_nri_police" card.update_label() @@ -344,13 +350,6 @@ GLOBAL_VAR(first_officer) command_name = "NRI Enforcer-Class Starship Telegram" report_sound = ANNOUNCER_NRI_RAIDERS -/obj/item/storage/belt/military/nri/captain/pirate_officer/PopulateContents() - generate_items_inside(list( - /obj/item/knife/combat = 1, - /obj/item/grenade/smokebomb = 1, - /obj/item/grenade/flashbang = 1, - ),src) - /obj/item/storage/belt/security/nri/PopulateContents() generate_items_inside(list( /obj/item/knife/combat = 1, diff --git a/modular_skyrat/modules/horrorform/code/true_changeling.dm b/modular_skyrat/modules/horrorform/code/true_changeling.dm index 4765f9f9df6ebb..6d7831cd3b2a33 100644 --- a/modular_skyrat/modules/horrorform/code/true_changeling.dm +++ b/modular_skyrat/modules/horrorform/code/true_changeling.dm @@ -35,7 +35,6 @@ butcher_results = list(/obj/item/food/meat/slab/human = 15) //It's a pretty big dude. Actually killing one is a feat. gold_core_spawnable = FALSE //Should stay exclusive to changelings tbh, otherwise makes it much less significant to sight one var/datum/action/innate/turn_to_human - var/datum/action/innate/devour var/transformed_time = 0 var/playstyle_string = span_infoplain("We have entered our true form! We are unbelievably powerful, and regenerate life at a steady rate. However, most of \ our abilities are useless in this form, and we must utilise the abilities that we have gained as a result of our transformation. Currently, we are incapable of returning to a human. \ @@ -51,10 +50,9 @@ /mob/living/simple_animal/hostile/true_changeling/Initialize(mapload) . = ..() to_chat(src, playstyle_string) - turn_to_human = new /datum/action/innate/turn_to_human - devour = new /datum/action/innate/devour + turn_to_human = new(src) turn_to_human.Grant(src) - devour.Grant(src) + GRANT_ACTION(/datum/action/innate/devour) ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) /mob/living/simple_animal/hostile/true_changeling/Life() diff --git a/modular_skyrat/modules/hydra/code/neutral.dm b/modular_skyrat/modules/hydra/code/neutral.dm index aea55dcc14736e..fe4165a33bf873 100644 --- a/modular_skyrat/modules/hydra/code/neutral.dm +++ b/modular_skyrat/modules/hydra/code/neutral.dm @@ -10,8 +10,8 @@ /datum/quirk/hydra/add(client/client_source) var/mob/living/carbon/human/hydra = quirk_holder - var/datum/action/innate/hydra/spell = new - var/datum/action/innate/hydrareset/resetspell = new + var/datum/action/innate/hydra/spell = new(hydra) + var/datum/action/innate/hydrareset/resetspell = new(hydra) spell.Grant(hydra) spell.owner = hydra resetspell.Grant(hydra) diff --git a/modular_skyrat/modules/implants/code/medical_designs.dm b/modular_skyrat/modules/implants/code/medical_designs.dm index fe795717df30e3..3197d96c5b7206 100644 --- a/modular_skyrat/modules/implants/code/medical_designs.dm +++ b/modular_skyrat/modules/implants/code/medical_designs.dm @@ -45,14 +45,14 @@ name = "Photon Projector Implant" desc = "An integrated projector mounted onto a user's arm that is able to be used as a powerful flash." id = "ci-flash" - build_type = MECHFAB + build_type = PROTOLATHE | AWAY_LATHE | MECHFAB materials = list (/datum/material/iron = SHEET_MATERIAL_AMOUNT * 2, /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/silver = HALF_SHEET_MATERIAL_AMOUNT) construction_time = 200 build_path = /obj/item/organ/internal/cyberimp/arm/flash category = list( RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_IMPLANTS_COMBAT ) - departmental_flags = DEPARTMENT_BITFLAG_SECURITY + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL /datum/design/cyberimp_botany name = "Botany Arm Implant" @@ -71,12 +71,12 @@ name = "Night Vision Eyes" desc = "These cybernetic eyes will give you Night Vision. Big, mean, and green." id = "ci-nv" - build_type = MECHFAB | PROTOLATHE + build_type = PROTOLATHE | MECHFAB construction_time = 60 materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 6, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 6, /datum/material/silver = SMALL_MATERIAL_AMOUNT * 6, /datum/material/gold = SMALL_MATERIAL_AMOUNT * 6, /datum/material/uranium = HALF_SHEET_MATERIAL_AMOUNT,) build_path = /obj/item/organ/internal/eyes/night_vision/cyber category = list( - RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_IMPLANTS_COMBAT + RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_IMPLANTS_UTILITY ) departmental_flags = DEPARTMENT_BITFLAG_MEDICAL @@ -84,7 +84,7 @@ name = "CNS Jumpstarter Implant" desc = "This implant will automatically attempt to jolt you awake from unconsciousness, with a short cooldown between jolts. Conflicts with the CNS Rebooter." id = "ci-antisleep" - build_type = MECHFAB | PROTOLATHE + build_type = PROTOLATHE | MECHFAB construction_time = 60 materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 6, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 6, /datum/material/silver = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/gold = SMALL_MATERIAL_AMOUNT * 5) build_path = /obj/item/organ/internal/cyberimp/brain/anti_sleep @@ -131,3 +131,17 @@ RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_IMPLANTS_MISC ) departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SERVICE + +/datum/design/cyberimp_thermals + name = "Thermal Eyes" + id = "ci-thermals" + build_type = AWAY_LATHE | MECHFAB + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + +/datum/design/cyberimp_reviver + name = "Reviver Implant" + id = "ci-reviver" + category = list( + RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_IMPLANTS_COMBAT + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL diff --git a/modular_skyrat/modules/implants/code/medical_nodes.dm b/modular_skyrat/modules/implants/code/medical_nodes.dm index 4eb34b69568320..a329693e8e5a3b 100644 --- a/modular_skyrat/modules/implants/code/medical_nodes.dm +++ b/modular_skyrat/modules/implants/code/medical_nodes.dm @@ -16,9 +16,10 @@ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) /datum/techweb_node/adv_cyber_implants + design_ids = list("ci-nv", "ci-nutrimentplus", "ci-surgery", "ci-toolset") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500) /datum/techweb_node/combat_cyber_implants - design_ids = list("ci-nv", "ci-antidrop", "ci-antistun", "ci-antisleep", "ci-thrusters", "ci-mantis", "ci-flash") + design_ids = list("ci-antidrop", "ci-antistun", "ci-antisleep", "ci-thrusters", "ci-mantis", "ci-flash", "ci-reviver") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 12000) diff --git a/modular_skyrat/modules/loadouts/loadout_items/donator/personal/donator_personal.dm b/modular_skyrat/modules/loadouts/loadout_items/donator/personal/donator_personal.dm index 1cdba770f6301b..6ae9361cfc3c5f 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/donator/personal/donator_personal.dm +++ b/modular_skyrat/modules/loadouts/loadout_items/donator/personal/donator_personal.dm @@ -178,9 +178,9 @@ item_path = /obj/item/clothing/under/wetsuit_norm ckeywhitelist = list("ChillyLobster") -/datum/loadout_item/mask/kindle_mask - name = "Kindle's mask" - item_path = /obj/item/clothing/mask/animal/kindle +/datum/loadout_item/mask/wolf_mask + name = "Wolf mask" + item_path = /obj/item/clothing/mask/animal/wolf ckeywhitelist = list("theooz") /datum/loadout_item/head/drake_skull @@ -667,7 +667,7 @@ /datum/loadout_item/pocket_items/masvedishcigar name = "Holocigar" item_path = /obj/item/clothing/mask/holocigarette/masvedishcigar - ckeywhitelist = list("masvedish", "lutowski", "lawful", "anyacers", "apolloafk", "avianaviator", "notdhu", "plejek") + // Asked it to be public, and as such has no whitelist. /datum/loadout_item/suit/lt3_armor name = "Silver Jacket Mk II" diff --git a/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm b/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm index ee748ca1f0c262..2d65996cfe532d 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm +++ b/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm @@ -124,6 +124,11 @@ GLOBAL_LIST_INIT(loadout_miscunders, generate_loadout_items(/datum/loadout_item/ item_path = /obj/item/clothing/under/rank/security/peacekeeper restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY) +/datum/loadout_item/under/jumpsuit/imperial_police_uniform + name = "Imperial Police Uniform" + item_path = /obj/item/clothing/under/colonial/nri_police + restricted_roles = list(JOB_SECURITY_OFFICER, JOB_DETECTIVE) + /datum/loadout_item/under/jumpsuit/disco name = "Superstar Cop Uniform" item_path = /obj/item/clothing/under/rank/security/detective/disco @@ -396,11 +401,11 @@ GLOBAL_LIST_INIT(loadout_miscunders, generate_loadout_items(/datum/loadout_item/ /datum/loadout_item/under/miscellaneous/medium_skirt name = "Medium Colourable Skirt" - item_path = /obj/item/clothing/under/skyrat/medium_skirt + item_path = /obj/item/clothing/under/dress/skirt/skyrat/medium /datum/loadout_item/under/miscellaneous/long_skirt name = "Long Colourable Skirt" - item_path = /obj/item/clothing/under/skyrat/long_skirt + item_path = /obj/item/clothing/under/dress/skirt/skyrat/long /datum/loadout_item/under/miscellaneous/denim_skirt name = "Jean Skirt" diff --git a/modular_skyrat/modules/loadouts/loadout_ui/loadout_manager.dm b/modular_skyrat/modules/loadouts/loadout_ui/loadout_manager.dm index b3187589972dd8..9524a6f5f776c3 100644 --- a/modular_skyrat/modules/loadouts/loadout_ui/loadout_manager.dm +++ b/modular_skyrat/modules/loadouts/loadout_ui/loadout_manager.dm @@ -210,6 +210,11 @@ /datum/loadout_manager/proc/set_item_name(datum/loadout_item/item) var/current_name = "" var/current_desc = "" + + if(!(item.item_path in owner.prefs.loadout_list)) + to_chat(owner, span_warning("Select the item before attempting to name it!")) + return + if(INFO_NAMED in owner.prefs.loadout_list[item.item_path]) current_name = owner.prefs.loadout_list[item.item_path][INFO_NAMED] if(INFO_DESCRIBED in owner.prefs.loadout_list[item.item_path]) @@ -220,10 +225,6 @@ if(QDELETED(src) || QDELETED(owner) || QDELETED(owner.prefs)) return - if(!(item.item_path in owner.prefs.loadout_list)) - to_chat(owner, span_warning("Select the item before attempting to name to it!")) - return - if(input_name) owner.prefs.loadout_list[item.item_path][INFO_NAMED] = input_name else diff --git a/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm b/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm index a28737520b5fdc..1a0c730c68c3c1 100644 --- a/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm +++ b/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm @@ -578,7 +578,7 @@ If the fault has become uncontrollable, extreme heat therapy is recommended." severity = WOUND_SEVERITY_CRITICAL - wound_flags = (ACCEPTS_GAUZE|MANGLES_INTERIOR|CAN_BE_GRASPED|SPLINT_OVERLAY) + wound_flags = (ACCEPTS_GAUZE|MANGLES_EXTERIOR|CAN_BE_GRASPED|SPLINT_OVERLAY) sound_effect = 'modular_skyrat/modules/medical/sound/robotic_slash_T3.ogg' diff --git a/modular_skyrat/modules/modular_implants/code/nifsofts/base_types/action_granter.dm b/modular_skyrat/modules/modular_implants/code/nifsofts/base_types/action_granter.dm index f43b6d1d058c58..64a941f0936300 100644 --- a/modular_skyrat/modules/modular_implants/code/nifsofts/base_types/action_granter.dm +++ b/modular_skyrat/modules/modular_implants/code/nifsofts/base_types/action_granter.dm @@ -11,7 +11,7 @@ /datum/nifsoft/action_granter/activate() . = ..() if(active) - granted_action = new action_to_grant + granted_action = new action_to_grant(linked_mob) granted_action.Grant(linked_mob) return diff --git a/modular_skyrat/modules/modular_implants/code/nifsofts/hivemind.dm b/modular_skyrat/modules/modular_implants/code/nifsofts/hivemind.dm index 7f722dcb343a1b..347004f71830e5 100644 --- a/modular_skyrat/modules/modular_implants/code/nifsofts/hivemind.dm +++ b/modular_skyrat/modules/modular_implants/code/nifsofts/hivemind.dm @@ -34,7 +34,7 @@ GLOBAL_LIST_EMPTY(hivemind_users) linker_action_path = /datum/action/innate/hivemind_config, \ ) - keyboard_action = new + keyboard_action = new(linked_mob) keyboard_action.Grant(linked_mob) active_network = user_network diff --git a/modular_skyrat/modules/modular_implants/code/nifsofts/soulcatcher.dm b/modular_skyrat/modules/modular_implants/code/nifsofts/soulcatcher.dm index 5b03931941a617..716e7e9513c94d 100644 --- a/modular_skyrat/modules/modular_implants/code/nifsofts/soulcatcher.dm +++ b/modular_skyrat/modules/modular_implants/code/nifsofts/soulcatcher.dm @@ -21,7 +21,7 @@ /datum/nifsoft/soulcatcher/New() . = ..() - soulcatcher_action = new + soulcatcher_action = new(linked_mob) soulcatcher_action.Grant(linked_mob) soulcatcher_action.parent_nifsoft = WEAKREF(src) diff --git a/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_component.dm b/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_component.dm index 9046e31ecab984..8c14385430a24a 100644 --- a/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_component.dm +++ b/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_component.dm @@ -466,5 +466,5 @@ GLOBAL_LIST_EMPTY(soulcatchers) if(locate(/datum/action/innate/join_soulcatcher) in actions) return - var/datum/action/innate/join_soulcatcher/new_join_action = new + var/datum/action/innate/join_soulcatcher/new_join_action = new(src) new_join_action.Grant(src) diff --git a/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_mob.dm b/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_mob.dm index 8ae004b9667706..5127fdfe8d46d3 100644 --- a/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_mob.dm +++ b/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_mob.dm @@ -45,10 +45,10 @@ if(!outside_hearing) ADD_TRAIT(src, TRAIT_DEAF, INNATE_TRAIT) - var/datum/action/innate/leave_soulcatcher/leave_action = new + var/datum/action/innate/leave_soulcatcher/leave_action = new(src) leave_action.Grant(src) - var/datum/action/innate/soulcatcher_user/soulcatcher_action = new + var/datum/action/innate/soulcatcher_user/soulcatcher_action = new(src) soulcatcher_action.Grant(src) var/datum/component/soulcatcher_user/user_component = AddComponent(/datum/component/soulcatcher_user) soulcatcher_action.soulcatcher_user_component = WEAKREF(user_component) diff --git a/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_tgui.dm b/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_tgui.dm index 5dbd31631ec311..6233f906fb342a 100644 --- a/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_tgui.dm +++ b/modular_skyrat/modules/modular_implants/code/soulcatcher/soulcatcher_tgui.dm @@ -126,7 +126,7 @@ return TRUE if("modify_name") - var/new_name = tgui_input_text(usr,"Choose a new name to send messages as", name, target_room.room_description, multiline = TRUE) + var/new_name = tgui_input_text(usr,"Choose a new name to send messages as", name, target_room.outside_voice, multiline = TRUE) if(!new_name) return FALSE diff --git a/modular_skyrat/modules/modular_vending/code/clothesmate.dm b/modular_skyrat/modules/modular_vending/code/clothesmate.dm index 585844629a40a5..f8635e69a2fff2 100644 --- a/modular_skyrat/modules/modular_vending/code/clothesmate.dm +++ b/modular_skyrat/modules/modular_vending/code/clothesmate.dm @@ -82,8 +82,8 @@ /obj/item/clothing/under/suit/skyrat/inferno/skirt = 3, /obj/item/clothing/under/suit/skyrat/helltaker = 3, /obj/item/clothing/under/suit/skyrat/helltaker/skirt = 3, - /obj/item/clothing/under/skyrat/medium_skirt = 5, - /obj/item/clothing/under/skyrat/long_skirt = 5, + /obj/item/clothing/under/dress/skirt/skyrat/medium = 5, + /obj/item/clothing/under/dress/skirt/skyrat/long = 5, ), ), diff --git a/modular_skyrat/modules/modular_weapons/code/company_and_or_faction_based/trappiste_fabriek/gunsets.dm b/modular_skyrat/modules/modular_weapons/code/company_and_or_faction_based/trappiste_fabriek/gunsets.dm index 41607663a508ef..8c96bc5a563d68 100644 --- a/modular_skyrat/modules/modular_weapons/code/company_and_or_faction_based/trappiste_fabriek/gunsets.dm +++ b/modular_skyrat/modules/modular_weapons/code/company_and_or_faction_based/trappiste_fabriek/gunsets.dm @@ -32,3 +32,11 @@ weapon_to_spawn = /obj/item/gun/ballistic/automatic/pistol/trappiste/no_mag extra_to_spawn = /obj/item/ammo_box/magazine/c585trappiste_pistol + +// Gunset for the Takbok Revolver + +/obj/item/storage/toolbox/guncase/skyrat/pistol/trappiste_small_case/takbok + name = "Trappiste 'Takbok' gunset" + + weapon_to_spawn = /obj/item/gun/ballistic/revolver/takbok + extra_to_spawn = /obj/item/ammo_box/c585trappiste diff --git a/modular_skyrat/modules/mold/code/mold_mobs.dm b/modular_skyrat/modules/mold/code/mold_mobs.dm index c7ba1226435e34..3e539b6472b0a8 100644 --- a/modular_skyrat/modules/mold/code/mold_mobs.dm +++ b/modular_skyrat/modules/mold/code/mold_mobs.dm @@ -83,7 +83,7 @@ /datum/ai_controller/basic_controller/oil_shambler blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance @@ -147,7 +147,7 @@ /datum/ai_controller/basic_controller/diseased_rat blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance @@ -204,7 +204,7 @@ /datum/ai_controller/basic_controller/electric_mosquito blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance @@ -276,7 +276,7 @@ /datum/ai_controller/basic_controller/centaur blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, ) ai_movement = /datum/ai_movement/basic_avoidance diff --git a/modular_skyrat/modules/morefermentplants/code/beans.dm b/modular_skyrat/modules/morefermentplants/code/beans.dm index 37991220cad9f7..ec047a95025f69 100644 --- a/modular_skyrat/modules/morefermentplants/code/beans.dm +++ b/modular_skyrat/modules/morefermentplants/code/beans.dm @@ -1,5 +1,2 @@ -/obj/item/food/grown/soybeans - distill_reagent = /datum/reagent/consumable/soy_latte - /obj/item/food/grown/koibeans distill_reagent = /datum/reagent/consumable/ethanol/mush_crush diff --git a/modular_skyrat/modules/moretraitoritems/code/syndicate.dm b/modular_skyrat/modules/moretraitoritems/code/syndicate.dm index 93561ec72da1fa..7f352bb5603b4d 100644 --- a/modular_skyrat/modules/moretraitoritems/code/syndicate.dm +++ b/modular_skyrat/modules/moretraitoritems/code/syndicate.dm @@ -140,8 +140,8 @@ wound = 5 //More items -/obj/item/guardiancreator/tech/choose/traitor/opfor - allowling = TRUE +/obj/item/guardian_creator/tech/choose/traitor/opfor + allow_changeling = TRUE /obj/item/codeword_granter name = "codeword manual" diff --git a/modular_skyrat/modules/morewizardstuffs/spells/bloodcrawl_potion.dm b/modular_skyrat/modules/morewizardstuffs/spells/bloodcrawl_potion.dm index d3164d93360770..e48d95d9789e37 100644 --- a/modular_skyrat/modules/morewizardstuffs/spells/bloodcrawl_potion.dm +++ b/modular_skyrat/modules/morewizardstuffs/spells/bloodcrawl_potion.dm @@ -6,7 +6,7 @@ /obj/item/bloodcrawl_bottle/attack_self(mob/user) to_chat(user, span_notice("You drink the contents of [src].")) - var/datum/action/cooldown/spell/jaunt/bloodcrawl/new_spell = new () + var/datum/action/cooldown/spell/jaunt/bloodcrawl/new_spell = new(user) new_spell.Grant(user) user.log_message("learned the spell bloodcrawl ([new_spell])", LOG_ATTACK, color="orange") qdel(src) diff --git a/modular_skyrat/modules/mutants/code/mutant_event.dm b/modular_skyrat/modules/mutants/code/mutant_event.dm index d6b191a7e1e0e5..bc2327a2097dd3 100644 --- a/modular_skyrat/modules/mutants/code/mutant_event.dm +++ b/modular_skyrat/modules/mutants/code/mutant_event.dm @@ -24,7 +24,9 @@ break if(try_to_mutant_infect(iterating_human, TRUE)) infectees++ - notify_ghosts("[iterating_human] has been infected by the HNZ-1 pathogen!", source = iterating_human) + notify_ghosts("[iterating_human] has been infected by the HNZ-1 pathogen!", + source = iterating_human, + ) /datum/round_event/mutant_infestation/announce(fake) alert_sound_to_playing(sound('modular_skyrat/modules/alerts/sound/alerts/alert2.ogg'), override_volume = TRUE) diff --git a/modular_skyrat/modules/nanotrasen_rep/code/nanotrasen_consultant.dm b/modular_skyrat/modules/nanotrasen_rep/code/nanotrasen_consultant.dm index 02524eafb6fa67..f40bb161957f5a 100644 --- a/modular_skyrat/modules/nanotrasen_rep/code/nanotrasen_consultant.dm +++ b/modular_skyrat/modules/nanotrasen_rep/code/nanotrasen_consultant.dm @@ -54,7 +54,7 @@ head = /obj/item/clothing/head/nanotrasen_consultant backpack_contents = list( /obj/item/melee/baton/telescopic = 1, - /obj/item/storage/toolbox/guncase/skyrat/pistol/trappiste_small_case/skild = 1, + /obj/item/choice_beacon/ntc = 1, ) skillchips = list(/obj/item/skillchip/disk_verifier) @@ -152,3 +152,20 @@ new /obj/item/storage/photo_album/personal(src) new /obj/item/bedsheet/centcom(src) new /obj/item/storage/bag/garment/nanotrasen_consultant(src) + +//Choice Beacon, I hope in the future they're going to be given proper unique gun but this will do. + + +/obj/item/choice_beacon/ntc + name = "gunset beacon" + desc = "A single use beacon to deliver a gunset of your choice. Please only call this in your office" + company_source = "Trappiste Fabriek Company" + company_message = span_bold("Supply Pod incoming please stand by") + +/obj/item/choice_beacon/ntc/generate_display_names() + var/static/list/selectable_gun_types = list( + "Takbok" = /obj/item/storage/toolbox/guncase/skyrat/pistol/trappiste_small_case/takbok, + "Skild" = /obj/item/storage/toolbox/guncase/skyrat/pistol/trappiste_small_case/skild, + ) + + return selectable_gun_types diff --git a/modular_skyrat/modules/novaya_ert/code/police_outfit.dm b/modular_skyrat/modules/novaya_ert/code/police_outfit.dm new file mode 100644 index 00000000000000..c34e390df578cd --- /dev/null +++ b/modular_skyrat/modules/novaya_ert/code/police_outfit.dm @@ -0,0 +1,49 @@ +/obj/item/clothing/under/colonial/nri_police + name = "imperial police outfit" + desc = "Fancy blue durathread shirt and a pair of cotton-blend pants with a black synthleather belt. A time-tested design first employed by the NRI police's \ + precursor organisation, Rim-world Colonial Militia, now utilised by them as a tribute." + icon_state = "under_police" + armor_type = /datum/armor/clothing_under/rank_security + strip_delay = 5 SECONDS + sensor_mode = SENSOR_COORDS + random_sensor = FALSE + can_adjust = FALSE + +/obj/item/clothing/neck/cloak/colonial/nri_police + name = "imperial police cloak" + desc = "A cloak made from heavy tarpaulin. Nigh wind- and waterproof thanks to its design. The signature white rectangle of the NRI police covers the garment's back." + icon_state = "cloak_police" + +/obj/item/clothing/head/hats/colonial/nri_police + name = "imperial police cap" + desc = "A puffy cap made out of tarpaulin covered by some textile. It is sturdy and comfortable, and seems to retain its form very well.
\ + Silver NRI police insignia is woven right above its visor." + icon_state = "cap_police" + armor_type = /datum/armor/cosmetic_sec + +/obj/item/clothing/mask/gas/nri_police + name = "imperial police mask" + desc = "A close-fitting tactical mask." + icon = 'modular_skyrat/modules/novaya_ert/icons/mask.dmi' + worn_icon = 'modular_skyrat/modules/novaya_ert/icons/wornmask.dmi' + worn_icon_digi = 'modular_skyrat/modules/novaya_ert/icons/wornmask_digi.dmi' + icon_state = "nri_police" + inhand_icon_state = "swat" + flags_inv = HIDEFACIALHAIR | HIDEFACE | HIDESNOUT + visor_flags_inv = 0 + flags_cover = MASKCOVERSMOUTH | MASKCOVERSEYES | PEPPERPROOF + visor_flags_cover = MASKCOVERSMOUTH | MASKCOVERSEYES | PEPPERPROOF + +/obj/item/clothing/head/helmet/nri_police + name = "imperial police helmet" + desc = "Thick-looking tactical helmet made out of shaped Plasteel. Colored dark blue, similar to one imperial police is commonly using." + icon_state = "police_helmet" + icon = 'modular_skyrat/modules/novaya_ert/icons/armor.dmi' + worn_icon = 'modular_skyrat/modules/novaya_ert/icons/wornarmor.dmi' + +/obj/item/clothing/suit/armor/vest/nri_police + name = "imperial police plate carrier" + desc = "A reasonably heavy, yet comfortable armor vest comprised of a bunch of dense plates. Colored dark blue and bears a reflective stripe on the front and back." + icon_state = "police_vest" + icon = 'modular_skyrat/modules/novaya_ert/icons/armor.dmi' + worn_icon = 'modular_skyrat/modules/novaya_ert/icons/wornarmor.dmi' diff --git a/modular_skyrat/modules/novaya_ert/icons/armor.dmi b/modular_skyrat/modules/novaya_ert/icons/armor.dmi new file mode 100644 index 00000000000000..fe291dd60416fd Binary files /dev/null and b/modular_skyrat/modules/novaya_ert/icons/armor.dmi differ diff --git a/modular_skyrat/modules/novaya_ert/icons/mask.dmi b/modular_skyrat/modules/novaya_ert/icons/mask.dmi new file mode 100644 index 00000000000000..3f2f2692126281 Binary files /dev/null and b/modular_skyrat/modules/novaya_ert/icons/mask.dmi differ diff --git a/modular_skyrat/modules/novaya_ert/icons/mod.dmi b/modular_skyrat/modules/novaya_ert/icons/mod.dmi index dc529a8ecab068..f84d26bf2145d3 100644 Binary files a/modular_skyrat/modules/novaya_ert/icons/mod.dmi and b/modular_skyrat/modules/novaya_ert/icons/mod.dmi differ diff --git a/modular_skyrat/modules/novaya_ert/icons/wornarmor.dmi b/modular_skyrat/modules/novaya_ert/icons/wornarmor.dmi new file mode 100644 index 00000000000000..299cd1c9000140 Binary files /dev/null and b/modular_skyrat/modules/novaya_ert/icons/wornarmor.dmi differ diff --git a/modular_skyrat/modules/novaya_ert/icons/wornmask.dmi b/modular_skyrat/modules/novaya_ert/icons/wornmask.dmi new file mode 100644 index 00000000000000..c35c56883ef4f5 Binary files /dev/null and b/modular_skyrat/modules/novaya_ert/icons/wornmask.dmi differ diff --git a/modular_skyrat/modules/novaya_ert/icons/wornmask_digi.dmi b/modular_skyrat/modules/novaya_ert/icons/wornmask_digi.dmi new file mode 100644 index 00000000000000..c35c56883ef4f5 Binary files /dev/null and b/modular_skyrat/modules/novaya_ert/icons/wornmask_digi.dmi differ diff --git a/modular_skyrat/modules/novaya_ert/icons/wornmod.dmi b/modular_skyrat/modules/novaya_ert/icons/wornmod.dmi index f2a0a55b925678..0ac1a2618ad3fc 100644 Binary files a/modular_skyrat/modules/novaya_ert/icons/wornmod.dmi and b/modular_skyrat/modules/novaya_ert/icons/wornmod.dmi differ diff --git a/modular_skyrat/modules/novaya_ert/readme.md b/modular_skyrat/modules/novaya_ert/readme.md index 9acbfc774bde98..590056df8a3311 100644 --- a/modular_skyrat/modules/novaya_ert/readme.md +++ b/modular_skyrat/modules/novaya_ert/readme.md @@ -1,14 +1,15 @@ -## Title: Novaya Rossiyskaya Imperiya ERT +## Title: Novaya Rossiyskaya Imperiya Module -MODULE ID: NRI ERT +MODULE ID: NRI STUFF ### Description: -A new style ERT for our Russian downstream, requested by them! It's a cool looking Russian style space ERT with guns and vodka! +Everything mainly NRI-related, from various cosmetic clothing to guns to ERTs. ### Credits: Gandalf2k15 - Code and some icons. Stalkeros - Code and some icons. +Zydras - NRI police clothing, stun gun and NRI holobarriers icons. Ramirez - Icons and idea. Flavrius - Icons + misc. -Paxilmaniac - Surplus weapons and armor +Paxilmaniac - Surplus weapons and armor. diff --git a/modular_skyrat/modules/opposing_force/code/equipment/gadgets.dm b/modular_skyrat/modules/opposing_force/code/equipment/gadgets.dm index 0a81d7fb918329..6b35ace50968f0 100644 --- a/modular_skyrat/modules/opposing_force/code/equipment/gadgets.dm +++ b/modular_skyrat/modules/opposing_force/code/equipment/gadgets.dm @@ -22,7 +22,7 @@ item_type = /obj/item/storage/box/syndie_kit/nuke /datum/opposing_force_equipment/gadget/holoparasite - item_type = /obj/item/guardiancreator/tech/choose/traitor + item_type = /obj/item/guardian_creator/tech/choose/traitor admin_note = "Lets a ghost take control of a guardian spirit bound to the user. RRs both the ghost and user on death." /datum/opposing_force_equipment/gadget/stimpack diff --git a/modular_skyrat/modules/organs/code/stomach.dm b/modular_skyrat/modules/organs/code/stomach.dm index 366c8d17355f9b..03bdc1b9df7c42 100644 --- a/modular_skyrat/modules/organs/code/stomach.dm +++ b/modular_skyrat/modules/organs/code/stomach.dm @@ -5,3 +5,12 @@ icon_state = "stomach_big" maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD metabolism_efficiency = 0.07 + +/obj/item/organ/internal/stomach/synth/oversized + name = "huge synthetic bio-reactor" + desc = "Typically found in huge synthetics, this monstrous engine has been developed to be highly efficient, made to provide an enormous amount of power to an enormous machine." + icon = 'modular_skyrat/modules/organs/icons/stomach.dmi' + icon_state = "stomach_big_synth" //ugly placeholder sorry im not an artist hehe + maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD + metabolism_efficiency = 0.07 + diff --git a/modular_skyrat/modules/organs/code/tongue.dm b/modular_skyrat/modules/organs/code/tongue.dm index 5d5e6bf3748c39..54ef552356b4a5 100644 --- a/modular_skyrat/modules/organs/code/tongue.dm +++ b/modular_skyrat/modules/organs/code/tongue.dm @@ -71,12 +71,19 @@ disliked_foodtypes = CLOTH | GRAIN | FRIED toxic_foodtypes = DAIRY -/obj/item/organ/internal/tongue/xeno // like lizard tongue but without taste sensitivity modifiers - name = "xenomorph tongue" - desc = "A fleshy muscle mostly used for hissing." +/obj/item/organ/internal/tongue/xeno_hybrid + name = "alien tongue" + desc = "According to leading xenobiologists the evolutionary benefit of having a second mouth in your mouth is \"that it looks badass\"." + icon_state = "tonguexeno" say_mod = "hisses" + taste_sensitivity = 10 liked_foodtypes = MEAT +/obj/item/organ/internal/tongue/xeno_hybrid/Initialize(mapload) + . = ..() + var/obj/item/organ/internal/tongue/alien/alien_tongue_type = /obj/item/organ/internal/tongue/alien + voice_filter = initial(alien_tongue_type.voice_filter) + /obj/item/organ/internal/tongue/skrell name = "skrell tongue" desc = "A fleshy muscle mostly used for warbling." diff --git a/modular_skyrat/modules/organs/icons/stomach.dmi b/modular_skyrat/modules/organs/icons/stomach.dmi index 2b1ccf4be5b85f..69ef103ebaa1ee 100644 Binary files a/modular_skyrat/modules/organs/icons/stomach.dmi and b/modular_skyrat/modules/organs/icons/stomach.dmi differ diff --git a/modular_skyrat/modules/oversized/code/oversized_quirk.dm b/modular_skyrat/modules/oversized/code/oversized_quirk.dm index 7fce40299d9935..a2470d56b8cbcb 100644 --- a/modular_skyrat/modules/oversized/code/oversized_quirk.dm +++ b/modular_skyrat/modules/oversized/code/oversized_quirk.dm @@ -39,9 +39,14 @@ return old_stomach.Remove(human_holder, special = TRUE) qdel(old_stomach) - var/obj/item/organ/internal/stomach/oversized/new_stomach = new //YOU LOOK HUGE, THAT MUST MEAN YOU HAVE HUGE GUTS! RIP AND TEAR YOUR HUGE GUTS! - new_stomach.Insert(human_holder, special = TRUE) - to_chat(human_holder, span_warning("You feel your massive stomach rumble!")) + if(issynthetic(human_holder)) + var/obj/item/organ/internal/stomach/synth/oversized/new_synth_stomach = new //YOU LOOK HUGE, THAT MUST MEAN YOU HAVE HUGE reactor! RIP AND TEAR YOUR HUGE reactor! + new_synth_stomach.Insert(human_holder, special = TRUE) + to_chat(human_holder, span_warning("You feel your massive engine rumble!")) + else + var/obj/item/organ/internal/stomach/oversized/new_stomach = new //YOU LOOK HUGE, THAT MUST MEAN YOU HAVE HUGE GUTS! RIP AND TEAR YOUR HUGE GUTS! + new_stomach.Insert(human_holder, special = TRUE) + to_chat(human_holder, span_warning("You feel your massive stomach rumble!")) /datum/quirk/oversized/remove() var/mob/living/carbon/human/human_holder = quirk_holder diff --git a/modular_skyrat/modules/paycheck_rations/code/quirk.dm b/modular_skyrat/modules/paycheck_rations/code/quirk.dm new file mode 100644 index 00000000000000..14b6d4b140b3f3 --- /dev/null +++ b/modular_skyrat/modules/paycheck_rations/code/quirk.dm @@ -0,0 +1,78 @@ +/datum/quirk/item_quirk/ration_system + name = "Ration Ticket Receiver" + desc = "Due to some circumstance of your life, you have enrolled in the ration tickets program, \ + which will halve all of your paychecks in exchange for granting you ration tickets, which can be \ + redeemed at a cargo console for food and other items." + icon = FA_ICON_DONATE + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_HIDE_FROM_SCAN + value = 0 + hardcore_value = 0 + +/datum/quirk/item_quirk/ration_system/add_unique(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + if(!human_holder.account_id) + return + var/datum/bank_account/account = SSeconomy.bank_accounts_by_id["[human_holder.account_id]"] + + var/obj/new_ticket_book = new /obj/item/storage/ration_ticket_book(get_turf(human_holder)) + give_item_to_holder( + new_ticket_book, + list( + LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, + LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, + LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, + LOCATION_HANDS = ITEM_SLOT_HANDS, + ), + ) + account.tracked_ticket_book = WEAKREF(new_ticket_book) + account.payday_modifier = 0.5 + to_chat(client_source.mob, span_notice("You remember to keep close hold of your ticket book, it can't be replaced if lost and all of your ration tickets are placed there!")) + +// Edits to bank accounts to make the above possible + +/datum/bank_account + /// Tracks a linked ration ticket book. If we have one of these, then we'll put tickets in it every payday. + var/datum/weakref/tracked_ticket_book + /// Tracks if the last ticket we got was for luxury items, if this is true we get a normal food ticket + var/last_ticket_luxury = TRUE + +/datum/bank_account/payday(amount_of_paychecks, free = FALSE) + . = ..() + if(!.) + return + if(isnull(tracked_ticket_book)) + return + make_ration_ticket() + +/// Attempts to create a ration ticket book in the card holder's hand, and failing that, the drop location of the card +/datum/bank_account/proc/make_ration_ticket() + if(!(SSeconomy.times_fired % 3 == 0)) + return + + if(!bank_cards.len) + return + + var/obj/item/storage/ration_ticket_book/ticket_book = tracked_ticket_book.resolve() + if(!ticket_book) + tracked_ticket_book = null + return + + var/obj/item/created_ticket + for(var/obj/card in bank_cards) + // We want to only make one ticket pr account per payday + if(created_ticket) + continue + var/ticket_to_make + if(!last_ticket_luxury) + ticket_to_make = /obj/item/paper/paperslip/ration_ticket/luxury + else + ticket_to_make = /obj/item/paper/paperslip/ration_ticket + created_ticket = new ticket_to_make(card) + last_ticket_luxury = !last_ticket_luxury + if(!ticket_book.atom_storage.can_insert(created_ticket, messages = FALSE)) + qdel(created_ticket) + bank_card_talk("ERROR: Failed to place ration ticket in ticket book, ensure book is not full.") + // We can stop here, its joever for trying to place tickets in the book this payday. You snooze you lose! + return + created_ticket.forceMove(ticket_book) + bank_card_talk("A new [last_ticket_luxury ? "luxury item" : "standard"] ration ticket has been placed in your ticket book.") diff --git a/modular_skyrat/modules/paycheck_rations/code/rationpacks.dm b/modular_skyrat/modules/paycheck_rations/code/rationpacks.dm new file mode 100644 index 00000000000000..a1effed97b5dc6 --- /dev/null +++ b/modular_skyrat/modules/paycheck_rations/code/rationpacks.dm @@ -0,0 +1,110 @@ +/obj/item/storage/box/spaceman_ration + name = "unlabeled ration container" + desc = "You get the feeling you sholdn't have been sent this one?" + icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi' + icon_state = "plants" + illustration = null + /// How many storage slots this has, yes I'm being lazy + var/box_storage_slots = 1 + +/obj/item/storage/box/spaceman_ration/Initialize(mapload) + . = ..() + atom_storage.max_slots = box_storage_slots + +/obj/item/storage/box/spaceman_ration/PopulateContents() + return + +// Contains your daily need of plants, yum! + +/obj/item/storage/box/spaceman_ration/plants + name = "produce ration container" + desc = "Contains your allotted ration of produce, which in this case should be peas and a potato." + box_storage_slots = 2 + +/obj/item/storage/box/spaceman_ration/plants/PopulateContents() + new /obj/item/food/grown/peas(src) + new /obj/item/food/grown/potato(src) + +// Alternate diet, themed around martian food a bit more + +/obj/item/storage/box/spaceman_ration/plants/alternate + desc = "Contains your allotted ration of produce, which in this case should be cabbage and an onion." + icon_state = "plants_alt" + +/obj/item/storage/box/spaceman_ration/plants/alternate/PopulateContents() + new /obj/item/food/grown/cabbage(src) + new /obj/item/food/grown/onion(src) + +// For the moths amogus + +/obj/item/storage/box/spaceman_ration/plants/mothic + desc = "Contains your allotted ration of produce, which in this case should be chili and a potato." + icon_state = "plants_moth" + +/obj/item/storage/box/spaceman_ration/plants/mothic/PopulateContents() + new /obj/item/food/grown/chili(src) + new /obj/item/food/grown/potato(src) + +// For the lizards amongus + +/obj/item/storage/box/spaceman_ration/plants/lizard + desc = "Contains your allotted ration of produce, which in this case should be two korta nuts and two potatoes." + icon_state = "plants_lizard" + box_storage_slots = 4 + +/obj/item/storage/box/spaceman_ration/plants/lizard/PopulateContents() + new /obj/item/food/grown/korta_nut(src) + new /obj/item/food/grown/korta_nut(src) + new /obj/item/food/grown/potato(src) + new /obj/item/food/grown/potato(src) + +// Contains your allotted meats, tasty! + +/obj/item/storage/box/spaceman_ration/meats + name = "meat ration container" + desc = "Contains your allotted ration of meat, which in this case should be preserved pork and a random side option." + icon_state = "meats" + +/obj/item/storage/box/spaceman_ration/meats/PopulateContents() + new /obj/item/food/meat/slab/pig(src) + var/secondary_meat = pick(/obj/item/food/raw_sausage, /obj/item/food/meat/slab/chicken, /obj/item/food/meat/slab/meatproduct) + new secondary_meat(src) + +// Seafood variant + +/obj/item/storage/box/spaceman_ration/meats/fish + desc = "Contains your allotted ration of meat, which in this case should be preserved pork and a random seafood side option." + icon_state = "meats_fish" + +/obj/item/storage/box/spaceman_ration/meats/fish/PopulateContents() + new /obj/item/food/meat/slab/pig(src) + var/secondary_meat = pick(/obj/item/food/meat/slab/rawcrab, /obj/item/food/fishmeat) + new secondary_meat(src) + +// For the lizards amongus + +/obj/item/storage/box/spaceman_ration/meats/lizard + desc = "Contains your allotted ration of meat, which in this case should be preserved pork and a random seafood side option." + icon_state = "meats_lizard" + +/obj/item/storage/box/spaceman_ration/meats/lizard/PopulateContents() + new /obj/item/food/fishmeat/moonfish(src) + var/secondary_meat = pick(/obj/item/food/raw_tiziran_sausage, /obj/item/food/liver_pate) + new secondary_meat(src) + +// Paper sack that spawns a random two slices of bread + +/obj/item/storage/box/papersack/ration_bread_slice + name = "bread and cheese ration bag" + desc = "A dusty old paper sack that should ideally contain your ration of bread and cheese." + +/obj/item/storage/box/papersack/ration_bread_slice/Initialize(mapload) + . = ..() + atom_storage.max_slots = 3 + +/obj/item/storage/box/papersack/ration_bread_slice/PopulateContents() + var/bread_slice = pick(/obj/item/food/breadslice/plain, /obj/item/food/breadslice/reispan, /obj/item/food/breadslice/root) + new bread_slice(src) + new bread_slice(src) + var/cheese_slice = pick(/obj/item/food/cheese/wedge, /obj/item/food/cheese/firm_cheese_slice, /obj/item/food/cheese/cheese_curds, /obj/item/food/cheese/mozzarella) + new cheese_slice(src) diff --git a/modular_skyrat/modules/paycheck_rations/code/reagents.dm b/modular_skyrat/modules/paycheck_rations/code/reagents.dm new file mode 100644 index 00000000000000..eefcce274af050 --- /dev/null +++ b/modular_skyrat/modules/paycheck_rations/code/reagents.dm @@ -0,0 +1,73 @@ +/obj/item/reagent_containers/condiment/flour/small_ration + name = "small flour sack" + desc = "A maritime ration-sized portion of flour, containing just enough to make a single good loaf of bread to fuel the day." + icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi' + list_reagents = list(/datum/reagent/consumable/flour = 15) + +/obj/item/reagent_containers/condiment/rice/small_ration + name = "small rice sack" + desc = "A maritime ration-sized portion of rice, containing just enough to make the universe's saddest rice dish." + icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi' + list_reagents = list(/datum/reagent/consumable/rice = 10) + +/obj/item/reagent_containers/condiment/sugar/small_ration + name = "small sugar sack" + desc = "A maritime ration-sized portion of sugar, containing just enough to make the day just a tiny bit sweeter." + icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi' + list_reagents = list(/datum/reagent/consumable/sugar = 10) + +/obj/item/reagent_containers/condiment/small_ration_korta_flour + name = "small korta flour sack" + desc = "A maritime ration-sized portion of korta flour, containing just enough to make a single good loaf of bread to fuel the day." + icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi' + icon_state = "flour_korta" + inhand_icon_state = "carton" + lefthand_file = 'icons/mob/inhands/items/drinks_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/drinks_righthand.dmi' + list_reagents = list(/datum/reagent/consumable/korta_flour = 10) + fill_icon_thresholds = null + +/obj/item/reagent_containers/condiment/soymilk/small_ration + name = "small soy milk" + desc = "It's soy milk. White and nutritious goodness! This one is significantly smaller than normal cartons; just enough to make some rootdough with." + icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi' + list_reagents = list(/datum/reagent/consumable/soymilk = 15) + +/obj/item/reagent_containers/cup/glass/bottle/small/tiny + name = "tiny glass bottle" + volume = 10 + +/obj/item/reagent_containers/cup/glass/bottle/small/tiny/Initialize(mapload, vol) + . = ..() + transform = transform.Scale(0.75, 0.75) + +/obj/item/reagent_containers/cup/glass/bottle/small/tiny/lime_juice + name = "tiny lime juice bottle" + desc = "A maritime ration-sized bottle of lime juice, containing enough to keep the scurvy away while on long voyages." + list_reagents = list(/datum/reagent/consumable/limejuice = 10) + +/obj/item/reagent_containers/cup/glass/bottle/small/tiny/vinegar + name = "tiny vinegar bottle" + desc = "A maritime ration-sized bottle of vinegar, containing enough to... Well, we're not entirely sure, but law mandates you're given this, so..." + list_reagents = list(/datum/reagent/consumable/vinegar = 10) + +/obj/item/reagent_containers/cup/glass/bottle/small/tiny/coffee + name = "tiny coffee powder bottle" + desc = "A maritime ration-sized bottle of coffee powder, containing enough to make a morning's brew." + list_reagents = list(/datum/reagent/toxin/coffeepowder = 10) + +/obj/item/reagent_containers/cup/glass/bottle/small/tiny/tea + name = "tiny tea powder bottle" + desc = "A maritime ration-sized bottle of tea powder, containing enough to make a morning's tea." + list_reagents = list(/datum/reagent/toxin/teapowder = 10) + +/obj/item/reagent_containers/cup/glass/bottle/small/tiny/honey + name = "tiny honey bottle" + desc = "A maritime ration-sized bottle of honey, a minuscule amount for a minuscule sweetening to your day." + list_reagents = list(/datum/reagent/consumable/honey = 5) + +/obj/item/reagent_containers/cup/glass/bottle/small/tiny/caramel + name = "tiny caramel bottle" + desc = "A maritime ration-sized bottle of caramel, in the past these used to be something called 'treacle', which was \ + the tar left over from refining sugar. Nowadays, governments are rich enough to just send caramel instead." + list_reagents = list(/datum/reagent/consumable/caramel = 10) diff --git a/modular_skyrat/modules/paycheck_rations/code/ticket_book.dm b/modular_skyrat/modules/paycheck_rations/code/ticket_book.dm new file mode 100644 index 00000000000000..09c5cb1fbb3396 --- /dev/null +++ b/modular_skyrat/modules/paycheck_rations/code/ticket_book.dm @@ -0,0 +1,14 @@ +/obj/item/storage/ration_ticket_book + name = "ration ticket book" + desc = "A small booklet able to hold all your ration tickets. More will be available here as your paychecks come in." + icon = 'modular_skyrat/modules/paycheck_rations/icons/tickets.dmi' + icon_state = "ticket_book" + w_class = WEIGHT_CLASS_SMALL + +/obj/item/storage/ration_ticket_book/Initialize(mapload) + . = ..() + atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL + atom_storage.max_slots = 4 + atom_storage.set_holdable(list( + /obj/item/paper/paperslip/ration_ticket, + )) diff --git a/modular_skyrat/modules/paycheck_rations/code/tickets.dm b/modular_skyrat/modules/paycheck_rations/code/tickets.dm new file mode 100644 index 00000000000000..26940e1bcc5d65 --- /dev/null +++ b/modular_skyrat/modules/paycheck_rations/code/tickets.dm @@ -0,0 +1,219 @@ +/obj/item/paper/paperslip/ration_ticket + name = "ration ticket - standard" + desc = "A little slip of paper that'll slot right into any cargo console and put your alotted food ration on the next shuttle to the station." + icon = 'modular_skyrat/modules/paycheck_rations/icons/tickets.dmi' + icon_state = "ticket_food" + default_raw_text = "Redeem this ticket in the nearest supply console to receive benefits." + color = COLOR_OFF_WHITE + show_written_words = FALSE + /// The finalized list of items we send once the ticket is used, don't define here, the procs will do it + var/list/items_we_deliver = list() + +/obj/item/paper/paperslip/ration_ticket/attack_atom(obj/machinery/computer/cargo/object_we_attack, mob/living/user, params) + if(!istype(object_we_attack)) + return ..() + if(!object_we_attack.is_operational || !user.can_perform_action(object_we_attack)) + return ..() + + try_to_make_ration_order_list(object_we_attack, user) + +/// Attempts to fill out the order list with items of the user's choosing, will stop in its tracks if it fails +/obj/item/paper/paperslip/ration_ticket/proc/try_to_make_ration_order_list(obj/machinery/computer/cargo/object_we_attack, mob/living/user) + forceMove(object_we_attack) + playsound(object_we_attack, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + + // List of meat options we get + var/list/radial_meat_options = list( + "Standard Meats" = image(icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi', icon_state = "meats"), + "Seafood Meats" = image(icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi', icon_state = "meats_fish"), + "Tizirian Meats" = image(icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi', icon_state = "meats_lizard"), + ) + + var/meats_choice = show_radial_menu(user, object_we_attack, radial_meat_options, require_near = TRUE) + + if(!meats_choice) + object_we_attack.balloon_alert(user, "no selection made") + forceMove(drop_location(object_we_attack)) + playsound(object_we_attack, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + return + + switch(meats_choice) + if("Standard Meats") + items_we_deliver += /obj/item/storage/box/spaceman_ration/meats + if("Seafood Meats") + items_we_deliver += /obj/item/storage/box/spaceman_ration/meats/fish + if("Tizirian Meats") + items_we_deliver += /obj/item/storage/box/spaceman_ration/meats/lizard + + // List of produce options we get + var/list/radial_produce_options = list( + "Standard Produce" = image(icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi', icon_state = "plants"), + "Alternative Produce" = image(icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi', icon_state = "plants_alt"), + "Mothic Produce" = image(icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi', icon_state = "plants_moth"), + "Tizirian Produce" = image(icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi', icon_state = "plants_lizard"), + ) + + var/produce_choice = show_radial_menu(user, object_we_attack, radial_produce_options, require_near = TRUE) + + if(!produce_choice) + object_we_attack.balloon_alert(user, "no selection made") + // Reset the list if we fail + items_we_deliver = list() + forceMove(drop_location(object_we_attack)) + playsound(object_we_attack, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + return + + switch(produce_choice) + if("Standard Produce") + items_we_deliver += /obj/item/storage/box/spaceman_ration/plants + if("Alternative Produce") + items_we_deliver += /obj/item/storage/box/spaceman_ration/plants/alternate + if("Mothic Produce") + items_we_deliver += /obj/item/storage/box/spaceman_ration/plants/mothic + if("Tizirian Produce") + items_we_deliver += /obj/item/storage/box/spaceman_ration/plants/lizard + + items_we_deliver += /obj/item/storage/box/papersack/ration_bread_slice + + // List of flour options we get + var/list/radial_flour_options = list( + "Standard Flour" = image(icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi', icon_state = "flour"), + "Korta Flour" = image(icon = 'modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi', icon_state = "flour_korta"), + ) + + var/flour_choice = show_radial_menu(user, object_we_attack, radial_flour_options, require_near = TRUE) + + if(!flour_choice) + object_we_attack.balloon_alert(user, "no selection made") + // Reset the list if we fail + items_we_deliver = list() + forceMove(drop_location(object_we_attack)) + playsound(object_we_attack, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + return + + switch(flour_choice) + if("Standard Flour") + items_we_deliver += /obj/item/reagent_containers/condiment/flour/small_ration + if("Korta Flour") + items_we_deliver += /obj/item/reagent_containers/condiment/small_ration_korta_flour + items_we_deliver += /obj/item/reagent_containers/condiment/soymilk/small_ration + + items_we_deliver += /obj/item/reagent_containers/condiment/rice/small_ration + items_we_deliver += /obj/item/reagent_containers/condiment/sugar/small_ration + items_we_deliver += /obj/item/reagent_containers/cup/glass/bottle/small/tiny/lime_juice + items_we_deliver += /obj/item/reagent_containers/cup/glass/bottle/small/tiny/vinegar + + items_we_deliver += /obj/item/reagent_containers/cup/glass/waterbottle + + var/random_drink = pick( \ + /obj/item/reagent_containers/cup/glass/waterbottle/tea, \ + /obj/item/reagent_containers/cup/glass/waterbottle/tea/mushroom, \ + /obj/item/reagent_containers/cup/glass/waterbottle/tea/astra, \ + /obj/item/reagent_containers/cup/glass/coffee, \ + ) + items_we_deliver += random_drink + + make_the_actual_order(object_we_attack, user) + +/// Takes the list of things to deliver and puts it into a cargo order +/obj/item/paper/paperslip/ration_ticket/proc/make_the_actual_order(obj/machinery/computer/cargo/object_we_attack, mob/user) + var/datum/supply_pack/custom/ration_pack/ration_pack = new( + purchaser = user, \ + cost = 0, \ + contains = items_we_deliver, + ) + var/datum/supply_order/new_order = new( + pack = ration_pack, + orderer = user, + orderer_rank = "Ration Ticket", + orderer_ckey = user.ckey, + reason = "", + paying_account = null, + department_destination = null, + coupon = null, + charge_on_purchase = FALSE, + manifest_can_fail = FALSE, + can_be_cancelled = FALSE, + ) + object_we_attack.say("Ration order placed! It will arrive on the next cargo shuttle!") + SSshuttle.shopping_list += new_order + qdel(src) + +/datum/supply_pack/custom/ration_pack + name = "rations order" + crate_name = "ration delivery crate" + access = list() + crate_type = /obj/structure/closet/crate/cardboard + +/datum/supply_pack/custom/ration_pack/New(purchaser, cost, list/contains) + . = ..() + name = "[purchaser]'s Rations Order" + crate_name = "[purchaser]'s ration delivery crate" + src.cost = cost + src.contains = contains + +// Ticket for some luxury items, which you get every second paycheck + +/obj/item/paper/paperslip/ration_ticket/luxury + name = "ration ticket - luxury" + desc = "A little slip of paper that'll slot right into any cargo console and put your alotted ration of luxury goods on the next cargo shuttle to the station." + icon_state = "ticket_luxury" + +/// Attempts to fill out the order list with items of the user's choosing, will stop in its tracks if it fails +/obj/item/paper/paperslip/ration_ticket/luxury/try_to_make_ration_order_list(obj/machinery/computer/cargo/object_we_attack, mob/living/user) + forceMove(object_we_attack) + playsound(object_we_attack, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + + // List of meat options we get + var/list/radial_alcohol_options = list( + "Navy Rum" = image(icon = 'modular_skyrat/master_files/icons/obj/drinks.dmi', icon_state = "navy_rum"), + "Ginger Beer" = image(icon = 'modular_skyrat/master_files/icons/obj/drinks.dmi', icon_state = "gingie_beer"), + "Kortara" = image(icon = 'modular_skyrat/master_files/icons/obj/drinks.dmi', icon_state = "kortara"), + ) + + var/alcohol_choice = show_radial_menu(user, object_we_attack, radial_alcohol_options, require_near = TRUE) + + if(!alcohol_choice) + object_we_attack.balloon_alert(user, "no selection made") + forceMove(drop_location(object_we_attack)) + return + + switch(alcohol_choice) + if("Navy Rum") + items_we_deliver += /obj/item/reagent_containers/cup/soda_cans/skyrat/navy_rum + items_we_deliver += /obj/item/reagent_containers/cup/soda_cans/skyrat/navy_rum + if("Ginger Beer") + items_we_deliver += /obj/item/reagent_containers/cup/soda_cans/skyrat/ginger_beer + items_we_deliver += /obj/item/reagent_containers/cup/soda_cans/skyrat/ginger_beer + if("Kortara") + items_we_deliver += /obj/item/reagent_containers/cup/soda_cans/skyrat/kortara + items_we_deliver += /obj/item/reagent_containers/cup/soda_cans/skyrat/kortara + + // List of produce options we get + var/list/radial_consumables_options = list( + "Cigarettes" = image(icon = 'icons/obj/cigarettes.dmi', icon_state = "robust"), + "Coffee Powder" = image(icon = 'icons/obj/food/cartridges.dmi', icon_state = "cartridge_blend"), + "Tea Powder" = image(icon = 'icons/obj/service/hydroponics/harvest.dmi', icon_state = "tea_aspera_leaves"), + ) + + var/consumables_choice = show_radial_menu(user, object_we_attack, radial_consumables_options, require_near = TRUE) + + if(!consumables_choice) + object_we_attack.balloon_alert(user, "no selection made") + // Reset the list if we fail + items_we_deliver = list() + forceMove(drop_location(object_we_attack)) + return + + switch(consumables_choice) + if("Cigarettes") + items_we_deliver += /obj/item/storage/fancy/cigarettes/cigpack_robust + if("Coffee Powder") + items_we_deliver += /obj/item/reagent_containers/cup/glass/bottle/small/tiny/coffee + if("Tea Powder") + items_we_deliver += /obj/item/reagent_containers/cup/glass/bottle/small/tiny/tea + + items_we_deliver += /obj/item/reagent_containers/cup/glass/bottle/small/tiny/honey + items_we_deliver += /obj/item/reagent_containers/cup/glass/bottle/small/tiny/caramel + + make_the_actual_order(object_we_attack, user) diff --git a/modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi b/modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi new file mode 100644 index 00000000000000..e87a6a9cb58f10 Binary files /dev/null and b/modular_skyrat/modules/paycheck_rations/icons/food_containers.dmi differ diff --git a/modular_skyrat/modules/paycheck_rations/icons/tickets.dmi b/modular_skyrat/modules/paycheck_rations/icons/tickets.dmi new file mode 100644 index 00000000000000..c0e9435f286fb8 Binary files /dev/null and b/modular_skyrat/modules/paycheck_rations/icons/tickets.dmi differ diff --git a/modular_skyrat/modules/primitive_catgirls/code/spawner.dm b/modular_skyrat/modules/primitive_catgirls/code/spawner.dm index 5cbe1d682c0a3a..2e2d9ec0d17207 100644 --- a/modular_skyrat/modules/primitive_catgirls/code/spawner.dm +++ b/modular_skyrat/modules/primitive_catgirls/code/spawner.dm @@ -19,6 +19,7 @@ var/datum/team/primitive_catgirls/team restricted_species = list(/datum/species/human/felinid/primitive) + quirks_enabled = TRUE random_appearance = FALSE loadout_enabled = FALSE uses = 9 diff --git a/modular_skyrat/modules/primitive_cooking_additions/code/big_mortar.dm b/modular_skyrat/modules/primitive_cooking_additions/code/big_mortar.dm index 5e8215d41cc31e..0ee1202ef720af 100644 --- a/modular_skyrat/modules/primitive_cooking_additions/code/big_mortar.dm +++ b/modular_skyrat/modules/primitive_cooking_additions/code/big_mortar.dm @@ -139,14 +139,29 @@ ///Juices the passed target item, and transfers any contained chems to the mortar as well /obj/structure/large_mortar/proc/juice_target_item(obj/item/to_be_juiced, mob/living/carbon/human/user) - to_be_juiced.juice(src.reagents, user) + if(to_be_juiced.flags_1 & HOLOGRAM_1) + to_chat(user, span_notice("You try to juice [to_be_juiced], but it fades away!")) + qdel(to_be_juiced) + return + + if(!to_be_juiced.juice(src.reagents, user)) + to_chat(user, span_danger("You fail to juice [to_be_juiced].")) to_chat(user, span_notice("You juice [to_be_juiced] into a liquid.")) QDEL_NULL(to_be_juiced) ///Grinds the passed target item, and transfers any contained chems to the mortar as well /obj/structure/large_mortar/proc/grind_target_item(obj/item/to_be_ground, mob/living/carbon/human/user) - to_be_ground.grind(src.reagents, user) + if(to_be_ground.flags_1 & HOLOGRAM_1) + to_chat(user, span_notice("You try to grind [to_be_ground], but it fades away!")) + qdel(to_be_ground) + return + + if(!to_be_ground.grind(src.reagents, user)) + if(isstack(to_be_ground)) + to_chat(usr, span_notice("[src] attempts to grind as many pieces of [to_be_ground] as possible.")) + else + to_chat(user, span_danger("You fail to grind [to_be_ground].")) to_chat(user, span_notice("You break [to_be_ground] into a fine powder.")) QDEL_NULL(to_be_ground) diff --git a/modular_skyrat/modules/primitive_production/code/ceramics.dm b/modular_skyrat/modules/primitive_production/code/ceramics.dm index 49d71494393b3d..ab360765ac34d8 100644 --- a/modular_skyrat/modules/primitive_production/code/ceramics.dm +++ b/modular_skyrat/modules/primitive_production/code/ceramics.dm @@ -1,5 +1,29 @@ #define DEFAULT_SPIN (4 SECONDS) +/* + * Clay Bricks + */ + +/obj/item/stack/sheet/mineral/clay + name = "clay brick" + desc = "A heavy clay brick." + singular_name = "clay brick" + icon = 'modular_skyrat/modules/primitive_production/icons/prim_fun.dmi' + icon_state = "sheet-clay" + inhand_icon_state = null + throw_speed = 3 + throw_range = 5 + merge_type = /obj/item/stack/sheet/mineral/clay + +GLOBAL_LIST_INIT(clay_recipes, list ( \ + new/datum/stack_recipe("clay range", /obj/machinery/primitive_stove, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_MISC), \ + new/datum/stack_recipe("clay oven", /obj/machinery/oven/stone, 10, time = 5 SECONDS, one_per_turf = FALSE, on_solid_ground = TRUE, category = CAT_MISC) \ + )) + +/obj/item/stack/sheet/mineral/clay/get_main_recipes() + . = ..() + . += GLOB.clay_recipes + /obj/structure/water_source/puddle/attackby(obj/item/O, mob/user, params) if(istype(O, /obj/item/stack/ore/glass)) var/obj/item/stack/ore/glass/glass_item = O @@ -131,7 +155,7 @@ name = "ceramic brick" desc = "A dense block of clay, ready to be fired into a brick!" icon = 'modular_skyrat/modules/primitive_production/icons/prim_fun.dmi' - icon_state = "clay_brick" + icon_state = "sheet-clay" forge_item = /obj/item/stack/sheet/mineral/clay /obj/structure/throwing_wheel diff --git a/modular_skyrat/modules/primitive_production/icons/prim_fun.dmi b/modular_skyrat/modules/primitive_production/icons/prim_fun.dmi index 0f6e0725611356..1caf775d6829a6 100644 Binary files a/modular_skyrat/modules/primitive_production/icons/prim_fun.dmi and b/modular_skyrat/modules/primitive_production/icons/prim_fun.dmi differ diff --git a/modular_skyrat/modules/reagent_forging/code/crafting_bench_recipes.dm b/modular_skyrat/modules/reagent_forging/code/crafting_bench_recipes.dm index 1a9001cc154aa3..b9aede74f74bd1 100644 --- a/modular_skyrat/modules/reagent_forging/code/crafting_bench_recipes.dm +++ b/modular_skyrat/modules/reagent_forging/code/crafting_bench_recipes.dm @@ -120,7 +120,7 @@ recipe_name = "seed mesh" recipe_requirements = list( /obj/item/forging/complete/plate = 1, - /obj/item/forging/complete/chain = 4, + /obj/item/forging/complete/chain = 2, ) resulting_item = /obj/item/seed_mesh required_good_hits = 10 diff --git a/modular_skyrat/modules/reagent_forging/code/forge_weapons.dm b/modular_skyrat/modules/reagent_forging/code/forge_weapons.dm index cdc6a96ef00ee3..c30aeb2ffc2c03 100644 --- a/modular_skyrat/modules/reagent_forging/code/forge_weapons.dm +++ b/modular_skyrat/modules/reagent_forging/code/forge_weapons.dm @@ -4,6 +4,7 @@ righthand_file = 'modular_skyrat/modules/reagent_forging/icons/mob/forge_weapon_r.dmi' worn_icon = 'modular_skyrat/modules/reagent_forging/icons/mob/forge_weapon_worn.dmi' material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + obj_flags = UNIQUE_RENAME skyrat_obj_flags = ANVIL_REPAIR /obj/item/forging/reagent_weapon/Initialize(mapload) diff --git a/modular_skyrat/modules/synths/code/species/synthetic.dm b/modular_skyrat/modules/synths/code/species/synthetic.dm index 1630d14e1f27eb..124985d73daf22 100644 --- a/modular_skyrat/modules/synths/code/species/synthetic.dm +++ b/modular_skyrat/modules/synths/code/species/synthetic.dm @@ -5,7 +5,6 @@ inherent_biotypes = MOB_ROBOTIC | MOB_HUMANOID inherent_traits = list( TRAIT_CAN_STRIP, - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_ADVANCEDTOOLUSER, TRAIT_RADIMMUNE, TRAIT_NOBREATH, @@ -63,7 +62,6 @@ var/datum/action/innate/monitor_change/screen /// This is the screen that is given to the user after they get revived. On death, their screen is temporarily set to BSOD before it turns off, hence the need for this var. var/saved_screen = "Blank" - wing_types = list(/obj/item/organ/external/wings/functional/robotic) /datum/species/synthetic/spec_life(mob/living/carbon/human/human) . = ..() @@ -81,12 +79,6 @@ playsound(transformer.loc, 'sound/machines/chime.ogg', 50, TRUE) transformer.visible_message(span_notice("[transformer]'s [screen ? "monitor lights up" : "eyes flicker to life"]!"), span_notice("All systems nominal. You're back online!")) -/datum/species/synthetic/spec_death(gibbed, mob/living/carbon/human/transformer) - . = ..() - saved_screen = screen - switch_to_screen(transformer, "BSOD") - addtimer(CALLBACK(src, PROC_REF(switch_to_screen), transformer, "Blank"), 5 SECONDS) - /datum/species/synthetic/on_species_gain(mob/living/carbon/human/transformer) . = ..() @@ -98,9 +90,11 @@ if(eyes) eyes.eye_icon_state = "None" - screen = new + screen = new(transformer) screen.Grant(transformer) + RegisterSignal(transformer, COMSIG_LIVING_DEATH, PROC_REF(bsod_death)) // screen displays bsod on death, if they have one + return if(eyes) @@ -150,6 +144,19 @@ if(screen) screen.Remove(human) + UnregisterSignal(human, COMSIG_LIVING_DEATH) + +/** + * Makes the IPC screen switch to BSOD followed by a blank screen + * + * Arguments: + * * transformer - The human that will be affected by the screen change (read: IPC). + * * screen_name - The name of the screen to switch the ipc_screen mutant bodypart to. Defaults to BSOD. + */ +/datum/species/synthetic/proc/bsod_death(mob/living/carbon/human/transformer, screen_name = "BSOD") + saved_screen = screen // remember the old screen in case of revival + switch_to_screen(transformer, screen_name) + addtimer(CALLBACK(src, PROC_REF(switch_to_screen), transformer, "Blank"), 5 SECONDS) /** * Simple proc to switch the screen of a monitor-enabled synth, while updating their appearance. diff --git a/modular_skyrat/modules/xenoarch/code/modules/research/xenoarch/xenoarch_item.dm b/modular_skyrat/modules/xenoarch/code/modules/research/xenoarch/xenoarch_item.dm index a5d94890ee2220..f70d56f4920516 100644 --- a/modular_skyrat/modules/xenoarch/code/modules/research/xenoarch/xenoarch_item.dm +++ b/modular_skyrat/modules/xenoarch/code/modules/research/xenoarch/xenoarch_item.dm @@ -173,7 +173,6 @@ CELL_LINE_TABLE_FROG, CELL_LINE_TABLE_WALKING_MUSHROOM, CELL_LINE_TABLE_QUEEN_BEE, - CELL_LINE_TABLE_LEAPER, CELL_LINE_TABLE_MEGA_ARACHNID) AddElement(/datum/element/swabable, pick_celltype, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) diff --git a/modular_skyrat/modules/xenos_skyrat_redo/code/base_skyrat_xeno.dm b/modular_skyrat/modules/xenos_skyrat_redo/code/base_skyrat_xeno.dm index e098f01769b104..4b1f325c39387a 100644 --- a/modular_skyrat/modules/xenos_skyrat_redo/code/base_skyrat_xeno.dm +++ b/modular_skyrat/modules/xenos_skyrat_redo/code/base_skyrat_xeno.dm @@ -5,8 +5,6 @@ icon = 'modular_skyrat/modules/xenos_skyrat_redo/icons/big_xenos.dmi' rotate_on_lying = FALSE base_pixel_x = -16 //All of the xeno sprites are 64x64, and we want them to be level with the tile they are on, much like oversized quirk users - /// Holds the ability for quick resting without using the ic panel, and without editing xeno huds - var/datum/action/cooldown/alien/skyrat/sleepytime/rest_button mob_size = MOB_SIZE_LARGE layer = LARGE_MOB_LAYER //above most mobs, but below speechbubbles plane = GAME_PLANE_UPPER_FOV_HIDDEN @@ -17,8 +15,6 @@ var/alt_inhands_file = 'modular_skyrat/modules/xenos_skyrat_redo/icons/big_xenos.dmi' /// Setting this will give a xeno generic_evolve set to evolve them into this type var/next_evolution - /// Holds the ability for evolving into whatever type next_evolution is set to - var/datum/action/cooldown/alien/skyrat/generic_evolve/evolve_ability /// Keeps track of if a xeno has evolved recently, if so then we prevent them from evolving until that time is up var/has_evolved_recently = FALSE /// How long xenos should be unable to evolve after recently evolving @@ -35,24 +31,15 @@ . = ..() AddComponent(/datum/component/seethrough_mob) - rest_button = new /datum/action/cooldown/alien/skyrat/sleepytime() - rest_button.Grant(src) - + GRANT_ACTION(/datum/action/cooldown/alien/skyrat/sleepytime) if(next_evolution) - evolve_ability = new /datum/action/cooldown/alien/skyrat/generic_evolve() - evolve_ability.Grant(src) + GRANT_ACTION(/datum/action/cooldown/alien/skyrat/generic_evolve) pixel_x = -16 ADD_TRAIT(src, TRAIT_XENO_HEAL_AURA, TRAIT_XENO_INNATE) real_name = "alien [caste]" -/mob/living/carbon/alien/adult/skyrat/Destroy() - QDEL_NULL(rest_button) - if(evolve_ability) - QDEL_NULL(evolve_ability) - return ..() - /// Called when a larva or xeno evolves, adds a configurable timer on evolving again to the xeno /mob/living/carbon/alien/adult/skyrat/proc/has_just_evolved() if(has_evolved_recently) diff --git a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/defender.dm b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/defender.dm index 8c5b1f3fc03afc..5b79b7a8934380 100644 --- a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/defender.dm +++ b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/defender.dm @@ -9,29 +9,20 @@ icon_state = "aliendefender" melee_damage_lower = 25 melee_damage_upper = 30 - /// Holds the basic charge ability that the defender will be granted - var/datum/action/cooldown/mob_cooldown/charge/basic_charge/defender/charge - /// Holds the wrecking ball tail sweep that the defender will be granted - var/datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/tail_sweep next_evolution = /mob/living/carbon/alien/adult/skyrat/warrior /mob/living/carbon/alien/adult/skyrat/defender/Initialize(mapload) . = ..() - tail_sweep = new /datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep() - tail_sweep.Grant(src) - - charge = new /datum/action/cooldown/mob_cooldown/charge/basic_charge/defender() - charge.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep, + /datum/action/cooldown/mob_cooldown/charge/basic_charge/defender, + ) + grant_actions_by_list(innate_actions) REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) add_movespeed_modifier(/datum/movespeed_modifier/alien_heavy) -/mob/living/carbon/alien/adult/skyrat/defender/Destroy() - QDEL_NULL(charge) - QDEL_NULL(tail_sweep) - return ..() - /mob/living/carbon/alien/adult/skyrat/defender/create_internal_organs() organs += new /obj/item/organ/internal/alien/plasmavessel/small ..() diff --git a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/drone.dm b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/drone.dm index ee3b7214da9cf7..7958984aea9e27 100644 --- a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/drone.dm +++ b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/drone.dm @@ -7,20 +7,13 @@ maxHealth = 200 health = 200 icon_state = "aliendrone" - /// Holds the healing aura ability the drone will be granted - var/datum/action/cooldown/alien/skyrat/heal_aura/heal_aura_ability melee_damage_lower = 15 melee_damage_upper = 20 next_evolution = /mob/living/carbon/alien/adult/skyrat/praetorian /mob/living/carbon/alien/adult/skyrat/drone/Initialize(mapload) . = ..() - heal_aura_ability = new /datum/action/cooldown/alien/skyrat/heal_aura() - heal_aura_ability.Grant(src) - -/mob/living/carbon/alien/adult/skyrat/drone/Destroy() - QDEL_NULL(heal_aura_ability) - return ..() + GRANT_ACTION(/datum/action/cooldown/alien/skyrat/heal_aura) /mob/living/carbon/alien/adult/skyrat/drone/create_internal_organs() organs += new /obj/item/organ/internal/alien/plasmavessel @@ -59,6 +52,8 @@ return TRUE /datum/action/cooldown/alien/skyrat/heal_aura/proc/aura_deactivate() + if(!aura_active) + return aura_active = FALSE QDEL_NULL(aura_healing_component) owner.balloon_alert(owner, "healing aura ended") diff --git a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/praetorian.dm b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/praetorian.dm index 45d5bd471c973c..a34376970e77a5 100644 --- a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/praetorian.dm +++ b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/praetorian.dm @@ -7,30 +7,22 @@ maxHealth = 400 health = 400 icon_state = "alienpraetorian" - /// Holds the improved healing aura ability to be granted to the praetorian later - var/datum/action/cooldown/alien/skyrat/heal_aura/juiced/heal_aura_ability - /// Holds the less lethal tail sweep ability to be granted to the praetorian later - var/datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/hard_throwing/tail_sweep melee_damage_lower = 25 melee_damage_upper = 30 next_evolution = /mob/living/carbon/alien/adult/skyrat/queen /mob/living/carbon/alien/adult/skyrat/praetorian/Initialize(mapload) . = ..() - heal_aura_ability = new /datum/action/cooldown/alien/skyrat/heal_aura/juiced() - heal_aura_ability.Grant(src) - - tail_sweep = new /datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/hard_throwing() - tail_sweep.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/alien/skyrat/heal_aura/juiced, + /datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/hard_throwing, + ) + grant_actions_by_list(innate_actions) REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) add_movespeed_modifier(/datum/movespeed_modifier/alien_big) -/mob/living/carbon/alien/adult/skyrat/praetorian/Destroy() - QDEL_NULL(heal_aura_ability) - return ..() - /mob/living/carbon/alien/adult/skyrat/praetorian/create_internal_organs() organs += new /obj/item/organ/internal/alien/plasmavessel/large organs += new /obj/item/organ/internal/alien/neurotoxin/spitter diff --git a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/queen.dm b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/queen.dm index 26497fc78c79b7..3c60e970958725 100644 --- a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/queen.dm +++ b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/queen.dm @@ -7,30 +7,21 @@ maxHealth = 500 health = 500 icon_state = "alienqueen" - /// Holds the less lethal tail sweep ability to be granted to the queen later - var/datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/hard_throwing/tail_sweep - /// Holds the queen screech ability to be granted to her later - var/datum/action/cooldown/alien/skyrat/queen_screech/screech melee_damage_lower = 30 melee_damage_upper = 35 /mob/living/carbon/alien/adult/skyrat/queen/Initialize(mapload) . = ..() - tail_sweep = new /datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/hard_throwing() - tail_sweep.Grant(src) - - screech = new /datum/action/cooldown/alien/skyrat/queen_screech() - screech.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/hard_throwing, + /datum/action/cooldown/alien/skyrat/queen_screech, + ) + grant_actions_by_list(innate_actions) REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) add_movespeed_modifier(/datum/movespeed_modifier/alien_big) -/mob/living/carbon/alien/adult/skyrat/queen/Destroy() - QDEL_NULL(tail_sweep) - QDEL_NULL(screech) - return ..() - /mob/living/carbon/alien/adult/skyrat/queen/create_internal_organs() organs += new /obj/item/organ/internal/alien/plasmavessel/large/queen organs += new /obj/item/organ/internal/alien/resinspinner diff --git a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/ravager.dm b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/ravager.dm index 4f872be7342014..00e469883a440d 100644 --- a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/ravager.dm +++ b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/ravager.dm @@ -9,35 +9,20 @@ maxHealth = 350 health = 350 icon_state = "alienravager" - /// Holds the triple charge ability to be granted to the ravager later - var/datum/action/cooldown/mob_cooldown/charge/triple_charge/ravager/triple_charge - /// Holds the slicing tail sweep ability to be granted to the ravager later - var/datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/slicing/tailsweep_slice - /// Holds the endure ability to be granted to the ravager later - var/datum/action/cooldown/alien/skyrat/literally_too_angry_to_die/you_cant_hurt_me_jack melee_damage_lower = 30 melee_damage_upper = 35 /mob/living/carbon/alien/adult/skyrat/ravager/Initialize(mapload) . = ..() - tailsweep_slice = new /datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/slicing() - tailsweep_slice.Grant(src) - - you_cant_hurt_me_jack = new /datum/action/cooldown/alien/skyrat/literally_too_angry_to_die() - you_cant_hurt_me_jack.Grant(src) - - triple_charge = new /datum/action/cooldown/mob_cooldown/charge/triple_charge/ravager() - triple_charge.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/slicing, + /datum/action/cooldown/alien/skyrat/literally_too_angry_to_die, + /datum/action/cooldown/mob_cooldown/charge/triple_charge/ravager, + ) + grant_actions_by_list(innate_actions) REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) -/mob/living/carbon/alien/adult/skyrat/ravager/Destroy() - //QDEL_NULL(triple_charge) - QDEL_NULL(tailsweep_slice) - QDEL_NULL(you_cant_hurt_me_jack) - QDEL_NULL(triple_charge) - return ..() - /mob/living/carbon/alien/adult/skyrat/ravager/create_internal_organs() organs += new /obj/item/organ/internal/alien/plasmavessel ..() diff --git a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/rouny.dm b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/rouny.dm index 5a7cb614fb52c9..81ef781ff31055 100644 --- a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/rouny.dm +++ b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/rouny.dm @@ -20,15 +20,11 @@ /mob/living/carbon/alien/adult/skyrat/runner/Initialize(mapload) . = ..() AddComponent(/datum/component/tackler, stamina_cost = 0, base_knockdown = 2, range = 10, speed = 2, skill_mod = 7, min_distance = 0) - evade_ability = new /datum/action/cooldown/alien/skyrat/evade() + evade_ability = new(src) evade_ability.Grant(src) add_movespeed_modifier(/datum/movespeed_modifier/alien_quick) -/mob/living/carbon/alien/adult/skyrat/runner/Destroy() - QDEL_NULL(evade_ability) - return ..() - /mob/living/carbon/alien/adult/skyrat/runner/create_internal_organs() organs += new /obj/item/organ/internal/alien/plasmavessel/small/tiny ..() diff --git a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/warrior.dm b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/warrior.dm index 885df34df686f5..1a483472792256 100644 --- a/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/warrior.dm +++ b/modular_skyrat/modules/xenos_skyrat_redo/code/xeno_types/warrior.dm @@ -9,34 +9,20 @@ icon_state = "alienwarrior" melee_damage_lower = 30 melee_damage_upper = 35 - /// Holds the charge ability that will be given to the warrior later - var/datum/action/cooldown/mob_cooldown/charge/basic_charge/defender/charge - /// Holds the tail sweep ability that will be given to the warrior later - var/datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep/tail_sweep - /// Holds the agility ability that will be given to the warrior later - var/datum/action/cooldown/alien/skyrat/warrior_agility/agility /mob/living/carbon/alien/adult/skyrat/warrior/Initialize(mapload) . = ..() - tail_sweep = new /datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep() - tail_sweep.Grant(src) - - charge = new /datum/action/cooldown/mob_cooldown/charge/basic_charge/defender() - charge.Grant(src) - - agility = new /datum/action/cooldown/alien/skyrat/warrior_agility() - agility.Grant(src) + var/static/list/innate_actions = list( + /datum/action/cooldown/spell/aoe/repulse/xeno/skyrat_tailsweep, + /datum/action/cooldown/mob_cooldown/charge/basic_charge/defender, + /datum/action/cooldown/alien/skyrat/warrior_agility, + ) + grant_actions_by_list(innate_actions) REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) add_movespeed_modifier(/datum/movespeed_modifier/alien_big) -/mob/living/carbon/alien/adult/skyrat/warrior/Destroy() - QDEL_NULL(charge) - QDEL_NULL(tail_sweep) - QDEL_NULL(agility) - return ..() - /mob/living/carbon/alien/adult/skyrat/warrior/create_internal_organs() organs += new /obj/item/organ/internal/alien/plasmavessel ..() diff --git a/modular_tannhauser/_skyrat_override/modules/barsigns/code/game/objects/structures/barsigns.dm b/modular_tannhauser/_skyrat_override/modules/barsigns/code/game/objects/structures/barsigns.dm index 598bfa7ed857aa..ff00e194a75b57 100644 --- a/modular_tannhauser/_skyrat_override/modules/barsigns/code/game/objects/structures/barsigns.dm +++ b/modular_tannhauser/_skyrat_override/modules/barsigns/code/game/objects/structures/barsigns.dm @@ -1,34 +1,29 @@ //OVERRIDE FILE BEGIN - - datum/barsign/cybersylph - name = "Cyber Sylph's" - icon = "cybersylph" - desc = "A cafe renowed for its out-of-boundaries futuristic insignia." - // Tanhauser Gate Bar Signs -/datum/barsign/orcacomand +/datum/barsign/skyrat/tan/orcacomand name = "Orca Dive Bar" - icon = "orcacomand" - desc = "This sign is of a Killer Whale falling from a great hight with a potted plant. The whale seems to have the rank of Comander for some reason." + icon_state = "orcacomand" + desc = "This sign is of a Killer Whale falling from a great hight with a potted plant. Beware the splash zone." -/datum/barsign/zestbar +/datum/barsign/skyrat/tan/zestbar name = "Best Zest Bar" - icon = "zestbar" + icon_state = "zestbar" desc = "Be sure to ask your bartender about the best panda zest, Yes the best is blue and we will not tell you." -/datum/barsign/losttime +/datum/barsign/skyrat/tan/losttime name = "Lost Time Bar" - icon = "losttime" + icon_state = "losttime" desc = "Your not sure how long you have realy spent in this place." -/datum/barsign/collective +/datum/barsign/skyrat/tan/collective name = "Cherdenko Collective" - icon = "collective" + icon_state = "collective" desc = "With all the ham you think this should be on the door to the meat locker" -/datum/barsign/haurbus - name = "Man Pool" - icon = "haurbus" - desc = "Came as you were, Leave as something New!! Warning, Nanotrassen is not responsible for any TF on Premisses. TF is not guarenteeed with every libation. Certain terms and restrictions may apply" +/datum/barsign/skyrat/tan/haurbus + name = "Mana Pool" + icon_state = "haurbus" + desc = "Come as you were, Leave as something New!! Warning, Nanotrassen is not responsible for any TF on Premisses. TF is not guarenteeed with every libation. Certain terms and restrictions may apply" + diff --git a/modular_tannhauser/_skyrat_override/modules/barsigns/icons/tanbars.dmi b/modular_tannhauser/_skyrat_override/modules/barsigns/icons/tanbars.dmi new file mode 100644 index 00000000000000..6789b1abc44b2a Binary files /dev/null and b/modular_tannhauser/_skyrat_override/modules/barsigns/icons/tanbars.dmi differ diff --git a/sound/items/frog_statue_release.ogg b/sound/items/frog_statue_release.ogg new file mode 100644 index 00000000000000..de7d3547778a90 Binary files /dev/null and b/sound/items/frog_statue_release.ogg differ diff --git a/sound/misc/salute.ogg b/sound/misc/salute.ogg new file mode 100644 index 00000000000000..76521a63540eca Binary files /dev/null and b/sound/misc/salute.ogg differ diff --git a/strings/names/guardian_descriptions.txt b/strings/names/guardian_descriptions.txt new file mode 100644 index 00000000000000..678ec61fef63ac --- /dev/null +++ b/strings/names/guardian_descriptions.txt @@ -0,0 +1,24 @@ +Black +Blazing +Bloody +Blue +Bronze +Dawn +Dusk +Gold +Green +Grey +Iron +Midnight +Orange +Pink +Plastitanium +Purple +Red +Shimmering +Shining +Silver +Sparkling +Steel +White +Yellow diff --git a/strings/names/guardian_gamepieces.txt b/strings/names/guardian_gamepieces.txt new file mode 100644 index 00000000000000..10a99cf38fb4a7 --- /dev/null +++ b/strings/names/guardian_gamepieces.txt @@ -0,0 +1,13 @@ +Ace +Bishop +Club +Diamond +Heart +Jack +Joker +King +Knight +Pawn +Queen +Rook +Spade diff --git a/strings/names/guardian_tarot.txt b/strings/names/guardian_tarot.txt new file mode 100644 index 00000000000000..5772c90d7ae85a --- /dev/null +++ b/strings/names/guardian_tarot.txt @@ -0,0 +1,23 @@ +Chariot +Death +Devil +Emperor +Empress +Fool +Fortune +Hangman +Hermit +Hierophant +Judgement +Justice +Lover +Magician +Moon +Priestess +Star +Strength +Sun +Temperance +Tower +Wheel +World diff --git a/strings/tips.txt b/strings/tips.txt index 75d0e4d1851290..8461c0bb71e41d 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -94,6 +94,7 @@ As a Security Officer, mindshield implants can only prevent someone from being t As a Security Officer, remember that correlation does not equal causation. Someone may have just been at the wrong place at the wrong time! As a Security Officer, remember that you can attach a sec-lite to your disabler or your helmet! As a Security Officer, your sechuds or HUDsunglasses can not only see crewmates' job assignments and criminal status, but also if they are mindshield implanted. You can tell by the flashing blue outline around their job icon. Use this to your advantage in a revolution to definitively tell who is on your side! +As a Security Officer, you have a special pen in your PDA that you can use to prompt people to surrender. This will stun them without the need to use a baton! As a Service Cyborg, your spray can knocks people down. However, it is blocked by masks and glasses. As a Shaft Miner, always have a GPS on you, so a fellow miner or cyborg can come to save you if you die. As a Shaft Miner, every monster on Lavaland has a pattern you can exploit to minimize damage from the encounters. diff --git a/tgstation.dme b/tgstation.dme index 09f62371631ddb..a85523071ad4f6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -156,6 +156,7 @@ #include "code\__DEFINES\nitrile.dm" #include "code\__DEFINES\nuclear_bomb.dm" #include "code\__DEFINES\obj_flags.dm" +#include "code\__DEFINES\observers.dm" #include "code\__DEFINES\overlays.dm" #include "code\__DEFINES\pai.dm" #include "code\__DEFINES\paintings.dm" @@ -230,6 +231,7 @@ #include "code\__DEFINES\time.dm" #include "code\__DEFINES\tools.dm" #include "code\__DEFINES\toys.dm" +#include "code\__DEFINES\trader.dm" #include "code\__DEFINES\traits.dm" #include "code\__DEFINES\transport.dm" #include "code\__DEFINES\tts.dm" @@ -258,6 +260,7 @@ #include "code\__DEFINES\ai\pets.dm" #include "code\__DEFINES\ai\simplemob.dm" #include "code\__DEFINES\ai\tourist.dm" +#include "code\__DEFINES\ai\trader.dm" #include "code\__DEFINES\ai\vending.dm" #include "code\__DEFINES\ai\ventcrawling.dm" #include "code\__DEFINES\atmospherics\atmos_core.dm" @@ -360,6 +363,7 @@ #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_arcade.dm" #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_basic.dm" #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_carbon.dm" +#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_guardian.dm" #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_living.dm" #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_main.dm" #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_silicon.dm" @@ -381,6 +385,7 @@ #include "code\__DEFINES\~skyrat_defines\augment.dm" #include "code\__DEFINES\~skyrat_defines\automapper.dm" #include "code\__DEFINES\~skyrat_defines\banning.dm" +#include "code\__DEFINES\~skyrat_defines\barsigns.dm" #include "code\__DEFINES\~skyrat_defines\baton_upgrades.dm" #include "code\__DEFINES\~skyrat_defines\cargo_import_companies.dm" #include "code\__DEFINES\~skyrat_defines\cells.dm" @@ -453,7 +458,7 @@ #include "code\__DEFINES\~skyrat_defines\_HELPERS\atmos_mapping_helpers.dm" #include "code\__DEFINES\~skyrat_defines\_HELPERS\lighting.dm" #include "code\__DEFINES\~skyrat_defines\_HELPERS\offset_index.dm" -#include "code\__DEFINES\~tannhauser_defines\jobs.dm" +#include "code\__DEFINES\~tannhauser_defines\barsigns.dm" #include "code\__HELPERS\_auxtools_api.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_planes.dm" @@ -653,10 +658,19 @@ #include "code\_onclick\hud\screentip.dm" #include "code\_onclick\hud\parallax\parallax.dm" #include "code\_onclick\hud\parallax\random_layer.dm" -#include "code\_onclick\hud\rendering\plane_master.dm" #include "code\_onclick\hud\rendering\plane_master_controller.dm" #include "code\_onclick\hud\rendering\plane_master_group.dm" #include "code\_onclick\hud\rendering\render_plate.dm" +#include "code\_onclick\hud\rendering\plane_masters\_plane_master.dm" +#include "code\_onclick\hud\rendering\plane_masters\camera_static.dm" +#include "code\_onclick\hud\rendering\plane_masters\clickcatcher.dm" +#include "code\_onclick\hud\rendering\plane_masters\core_game_planes.dm" +#include "code\_onclick\hud\rendering\plane_masters\default.dm" +#include "code\_onclick\hud\rendering\plane_masters\in_world_chat.dm" +#include "code\_onclick\hud\rendering\plane_masters\lighting.dm" +#include "code\_onclick\hud\rendering\plane_masters\parallax.dm" +#include "code\_onclick\hud\rendering\plane_masters\pipecrawl.dm" +#include "code\_onclick\hud\rendering\plane_masters\simple_plane_masters.dm" #include "code\controllers\admin.dm" #include "code\controllers\controller.dm" #include "code\controllers\failsafe.dm" @@ -726,11 +740,11 @@ #include "code\controllers\subsystem\pai.dm" #include "code\controllers\subsystem\parallax.dm" #include "code\controllers\subsystem\pathfinder.dm" -#include "code\controllers\subsystem\persistence.dm" #include "code\controllers\subsystem\persistent_paintings.dm" #include "code\controllers\subsystem\ping.dm" #include "code\controllers\subsystem\points_of_interest.dm" #include "code\controllers\subsystem\profiler.dm" +#include "code\controllers\subsystem\queuelinks.dm" #include "code\controllers\subsystem\radiation.dm" #include "code\controllers\subsystem\radio.dm" #include "code\controllers\subsystem\radioactive_nebula.dm" @@ -773,6 +787,16 @@ #include "code\controllers\subsystem\movement\movement.dm" #include "code\controllers\subsystem\movement\movement_types.dm" #include "code\controllers\subsystem\movement\spacedrift.dm" +#include "code\controllers\subsystem\persistence\_persistence.dm" +#include "code\controllers\subsystem\persistence\counter_delamination.dm" +#include "code\controllers\subsystem\persistence\counter_tram_hits.dm" +#include "code\controllers\subsystem\persistence\custom_outfits.dm" +#include "code\controllers\subsystem\persistence\engravings.dm" +#include "code\controllers\subsystem\persistence\photo_albums.dm" +#include "code\controllers\subsystem\persistence\recipes.dm" +#include "code\controllers\subsystem\persistence\scars.dm" +#include "code\controllers\subsystem\persistence\tattoos.dm" +#include "code\controllers\subsystem\persistence\trophies.dm" #include "code\controllers\subsystem\processing\acid.dm" #include "code\controllers\subsystem\processing\ai_basic_avoidance.dm" #include "code\controllers\subsystem\processing\ai_behaviors.dm" @@ -885,6 +909,7 @@ #include "code\datums\actions\mobs\meteors.dm" #include "code\datums\actions\mobs\mobcooldown.dm" #include "code\datums\actions\mobs\open_mob_commands.dm" +#include "code\datums\actions\mobs\personality_commune.dm" #include "code\datums\actions\mobs\projectileattack.dm" #include "code\datums\actions\mobs\sign_language.dm" #include "code\datums\actions\mobs\sneak.dm" @@ -906,17 +931,18 @@ #include "code\datums\ai\basic_mobs\basic_ai_behaviors\basic_attacking.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\climb_tree.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\find_parent.dm" -#include "code\datums\ai\basic_mobs\basic_ai_behaviors\nearest_targetting.dm" +#include "code\datums\ai\basic_mobs\basic_ai_behaviors\nearest_targeting.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\pick_up_item.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\run_away_from_target.dm" +#include "code\datums\ai\basic_mobs\basic_ai_behaviors\set_travel_destination.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\step_towards_turf.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\stop_and_stare.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\targeted_mob_ability.dm" -#include "code\datums\ai\basic_mobs\basic_ai_behaviors\targetting.dm" +#include "code\datums\ai\basic_mobs\basic_ai_behaviors\targeting.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\tipped_reaction.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\travel_towards.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\ventcrawling.dm" -#include "code\datums\ai\basic_mobs\basic_ai_behaviors\wounded_targetting.dm" +#include "code\datums\ai\basic_mobs\basic_ai_behaviors\wounded_targeting.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\write_on_paper.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\attack_adjacent_target.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\attack_obstacle_in_path.dm" @@ -927,10 +953,12 @@ #include "code\datums\ai\basic_mobs\basic_subtrees\find_paper_and_write.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_parent.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\flee_target.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\go_for_swim.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\maintain_distance.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\mine_walls.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\move_to_cardinal.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\opportunistic_ventcrawler.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\prepare_travel_to_destination.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\ranged_skirmish.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\run_emote.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\shapechange_ambush.dm" @@ -950,11 +978,11 @@ #include "code\datums\ai\basic_mobs\pet_commands\fetch.dm" #include "code\datums\ai\basic_mobs\pet_commands\pet_command_planning.dm" #include "code\datums\ai\basic_mobs\pet_commands\pet_follow_friend.dm" -#include "code\datums\ai\basic_mobs\pet_commands\pet_use_targetted_ability.dm" +#include "code\datums\ai\basic_mobs\pet_commands\pet_use_targeted_ability.dm" #include "code\datums\ai\basic_mobs\pet_commands\play_dead.dm" -#include "code\datums\ai\basic_mobs\targetting_datums\basic_targetting_datum.dm" -#include "code\datums\ai\basic_mobs\targetting_datums\dont_target_friends.dm" -#include "code\datums\ai\basic_mobs\targetting_datums\with_object.dm" +#include "code\datums\ai\basic_mobs\targeting_strategies\basic_targeting_strategy.dm" +#include "code\datums\ai\basic_mobs\targeting_strategies\dont_target_friends.dm" +#include "code\datums\ai\basic_mobs\targeting_strategies\with_object.dm" #include "code\datums\ai\cursed\cursed_behaviors.dm" #include "code\datums\ai\cursed\cursed_controller.dm" #include "code\datums\ai\cursed\cursed_subtrees.dm" @@ -1080,10 +1108,12 @@ #include "code\datums\components\curse_of_polymorph.dm" #include "code\datums\components\customizable_reagent_holder.dm" #include "code\datums\components\damage_aura.dm" +#include "code\datums\components\damage_chain.dm" #include "code\datums\components\deadchat_control.dm" #include "code\datums\components\death_linked.dm" #include "code\datums\components\dejavu.dm" #include "code\datums\components\deployable.dm" +#include "code\datums\components\direct_explosive_trap.dm" #include "code\datums\components\drift.dm" #include "code\datums\components\earprotection.dm" #include "code\datums\components\echolocation.dm" @@ -1096,6 +1126,7 @@ #include "code\datums\components\engraved.dm" #include "code\datums\components\evolutionary_leap.dm" #include "code\datums\components\explodable.dm" +#include "code\datums\components\explode_on_attack.dm" #include "code\datums\components\faction_granter.dm" #include "code\datums\components\fertile_egg.dm" #include "code\datums\components\fishing_spot.dm" @@ -1131,6 +1162,7 @@ #include "code\datums\components\knockoff.dm" #include "code\datums\components\label.dm" #include "code\datums\components\leash.dm" +#include "code\datums\components\life_link.dm" #include "code\datums\components\light_eater.dm" #include "code\datums\components\ling_decoy_brain.dm" #include "code\datums\components\lock_on_cursor.dm" @@ -1157,6 +1189,7 @@ #include "code\datums\components\pellet_cloud.dm" #include "code\datums\components\phylactery.dm" #include "code\datums\components\pinata.dm" +#include "code\datums\components\plundering_attacks.dm" #include "code\datums\components\pricetag.dm" #include "code\datums\components\punchcooldown.dm" #include "code\datums\components\puzzgrid.dm" @@ -1164,7 +1197,9 @@ #include "code\datums\components\radioactive_emitter.dm" #include "code\datums\components\radioactive_exposure.dm" #include "code\datums\components\ranged_attacks.dm" +#include "code\datums\components\ranged_mob_full_auto.dm" #include "code\datums\components\reagent_refiller.dm" +#include "code\datums\components\recharging_attacks.dm" #include "code\datums\components\redirect_attack_hand_from_turf.dm" #include "code\datums\components\reflection.dm" #include "code\datums\components\regenerator.dm" @@ -1286,7 +1321,6 @@ #include "code\datums\components\plumbing\_plumbing.dm" #include "code\datums\components\plumbing\chemical_acclimator.dm" #include "code\datums\components\plumbing\filter.dm" -#include "code\datums\components\plumbing\IV_drip.dm" #include "code\datums\components\plumbing\reaction_chamber.dm" #include "code\datums\components\plumbing\splitter.dm" #include "code\datums\components\riding\riding.dm" @@ -1294,6 +1328,7 @@ #include "code\datums\components\riding\riding_vehicle.dm" #include "code\datums\components\style\style.dm" #include "code\datums\components\style\style_meter.dm" +#include "code\datums\components\trader\trader.dm" #include "code\datums\diseases\_disease.dm" #include "code\datums\diseases\_MobProcs.dm" #include "code\datums\diseases\adrenal_crisis.dm" @@ -1362,6 +1397,7 @@ #include "code\datums\elements\ai_flee_while_injured.dm" #include "code\datums\elements\ai_held_item.dm" #include "code\datums\elements\ai_retaliate.dm" +#include "code\datums\elements\ai_swap_combat_mode.dm" #include "code\datums\elements\ai_target_damagesource.dm" #include "code\datums\elements\amputating_limbs.dm" #include "code\datums\elements\animal_variety.dm" @@ -1481,7 +1517,6 @@ #include "code\datums\elements\strippable.dm" #include "code\datums\elements\structure_repair.dm" #include "code\datums\elements\swabbable.dm" -#include "code\datums\elements\tear_wall.dm" #include "code\datums\elements\temporary_atom.dm" #include "code\datums\elements\tenacious.dm" #include "code\datums\elements\tiny_mob_hunter.dm" @@ -1569,7 +1604,6 @@ #include "code\datums\looping_sounds\music.dm" #include "code\datums\looping_sounds\vents.dm" #include "code\datums\looping_sounds\weather.dm" -#include "code\datums\mapgen\_MapGenerator.dm" #include "code\datums\mapgen\CaveGenerator.dm" #include "code\datums\mapgen\JungleGenerator.dm" #include "code\datums\mapgen\biomes\_biome.dm" @@ -2241,6 +2275,7 @@ #include "code\game\objects\items\extinguisher.dm" #include "code\game\objects\items\fireaxe.dm" #include "code\game\objects\items\flamethrower.dm" +#include "code\game\objects\items\frog_statue.dm" #include "code\game\objects\items\gift.dm" #include "code\game\objects\items\gun_maintenance.dm" #include "code\game\objects\items\hand_items.dm" @@ -2298,6 +2333,7 @@ #include "code\game\objects\items\virgin_mary.dm" #include "code\game\objects\items\wall_mounted.dm" #include "code\game\objects\items\weaponry.dm" +#include "code\game\objects\items\wiki_manuals.dm" #include "code\game\objects\items\AI_modules\_AI_modules.dm" #include "code\game\objects\items\AI_modules\freeform.dm" #include "code\game\objects\items\AI_modules\full_lawsets.dm" @@ -2395,6 +2431,7 @@ #include "code\game\objects\items\granters\crafting\death_sandwich.dm" #include "code\game\objects\items\granters\crafting\desserts.dm" #include "code\game\objects\items\granters\crafting\pipegun.dm" +#include "code\game\objects\items\granters\crafting\rebarxbowsyndie.dm" #include "code\game\objects\items\granters\crafting\regal_condor.dm" #include "code\game\objects\items\granters\magic\_spell_granter.dm" #include "code\game\objects\items\granters\magic\barnyard.dm" @@ -3009,20 +3046,20 @@ #include "code\modules\antagonists\heretic\items\heretic_necks.dm" #include "code\modules\antagonists\heretic\items\hunter_rifle.dm" #include "code\modules\antagonists\heretic\items\keyring.dm" -#include "code\modules\antagonists\heretic\items\lintel.dm" +#include "code\modules\antagonists\heretic\items\labyrinth_handbook.dm" #include "code\modules\antagonists\heretic\items\madness_mask.dm" #include "code\modules\antagonists\heretic\knowledge\ash_lore.dm" #include "code\modules\antagonists\heretic\knowledge\blade_lore.dm" #include "code\modules\antagonists\heretic\knowledge\cosmic_lore.dm" #include "code\modules\antagonists\heretic\knowledge\flesh_lore.dm" #include "code\modules\antagonists\heretic\knowledge\general_side.dm" -#include "code\modules\antagonists\heretic\knowledge\knock_lore.dm" +#include "code\modules\antagonists\heretic\knowledge\lock_lore.dm" #include "code\modules\antagonists\heretic\knowledge\rust_lore.dm" #include "code\modules\antagonists\heretic\knowledge\side_ash_flesh.dm" #include "code\modules\antagonists\heretic\knowledge\side_blade_rust.dm" #include "code\modules\antagonists\heretic\knowledge\side_cosmos_ash.dm" #include "code\modules\antagonists\heretic\knowledge\side_flesh_void.dm" -#include "code\modules\antagonists\heretic\knowledge\side_knock_flesh.dm" +#include "code\modules\antagonists\heretic\knowledge\side_lock_flesh.dm" #include "code\modules\antagonists\heretic\knowledge\side_rust_cosmos.dm" #include "code\modules\antagonists\heretic\knowledge\side_void_blade.dm" #include "code\modules\antagonists\heretic\knowledge\starting_lore.dm" @@ -3073,7 +3110,7 @@ #include "code\modules\antagonists\heretic\status_effects\ghoul.dm" #include "code\modules\antagonists\heretic\status_effects\mark_effects.dm" #include "code\modules\antagonists\heretic\structures\carving_knife.dm" -#include "code\modules\antagonists\heretic\structures\knock_final.dm" +#include "code\modules\antagonists\heretic\structures\lock_final.dm" #include "code\modules\antagonists\heretic\structures\mawed_crucible.dm" #include "code\modules\antagonists\highlander\highlander.dm" #include "code\modules\antagonists\hypnotized\hypnotized.dm" @@ -3377,6 +3414,7 @@ #include "code\modules\bitrunning\components\avatar_connection.dm" #include "code\modules\bitrunning\components\bitrunning_points.dm" #include "code\modules\bitrunning\components\netpod_healing.dm" +#include "code\modules\bitrunning\components\virtual_elite_mob.dm" #include "code\modules\bitrunning\objects\byteforge.dm" #include "code\modules\bitrunning\objects\clothing.dm" #include "code\modules\bitrunning\objects\disks.dm" @@ -3395,18 +3433,19 @@ #include "code\modules\bitrunning\server\obj_generation.dm" #include "code\modules\bitrunning\server\quantum_server.dm" #include "code\modules\bitrunning\server\signal_handlers.dm" +#include "code\modules\bitrunning\server\threats.dm" #include "code\modules\bitrunning\server\util.dm" #include "code\modules\bitrunning\virtual_domain\safehouses.dm" #include "code\modules\bitrunning\virtual_domain\virtual_domain.dm" #include "code\modules\bitrunning\virtual_domain\domains\ash_drake.dm" #include "code\modules\bitrunning\virtual_domain\domains\beach_bar.dm" #include "code\modules\bitrunning\virtual_domain\domains\blood_drunk_miner.dm" +#include "code\modules\bitrunning\virtual_domain\domains\breeze_bay.dm" #include "code\modules\bitrunning\virtual_domain\domains\bubblegum.dm" #include "code\modules\bitrunning\virtual_domain\domains\clown_planet.dm" #include "code\modules\bitrunning\virtual_domain\domains\colossus.dm" #include "code\modules\bitrunning\virtual_domain\domains\gondola_asteroid.dm" #include "code\modules\bitrunning\virtual_domain\domains\hierophant.dm" -#include "code\modules\bitrunning\virtual_domain\domains\legion.dm" #include "code\modules\bitrunning\virtual_domain\domains\pipedream.dm" #include "code\modules\bitrunning\virtual_domain\domains\pirates.dm" #include "code\modules\bitrunning\virtual_domain\domains\psyker_shuffle.dm" @@ -4274,6 +4313,7 @@ #include "code\modules\logging\categories\log_category_uplink.dm" #include "code\modules\mafia\_defines.dm" #include "code\modules\mafia\controller.dm" +#include "code\modules\mafia\controller_ui.dm" #include "code\modules\mafia\map_pieces.dm" #include "code\modules\mafia\outfits.dm" #include "code\modules\mafia\abilities\abilities.dm" @@ -4337,6 +4377,7 @@ #include "code\modules\mapfluff\ruins\spaceruin_code\hilbertshotel.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\interdyne.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\listeningstation.dm" +#include "code\modules\mapfluff\ruins\spaceruin_code\meatderelict.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\meateor.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\originalcontent.dm" #include "code\modules\mapfluff\ruins\spaceruin_code\spacehotel.dm" @@ -4471,11 +4512,14 @@ #include "code\modules\mob\living\basic\blob_minions\blobbernaut.dm" #include "code\modules\mob\living\basic\clown\clown.dm" #include "code\modules\mob\living\basic\clown\clown_ai.dm" -#include "code\modules\mob\living\basic\constructs\_construct.dm" -#include "code\modules\mob\living\basic\constructs\artificer.dm" -#include "code\modules\mob\living\basic\constructs\construct_ai.dm" -#include "code\modules\mob\living\basic\constructs\harvester.dm" -#include "code\modules\mob\living\basic\constructs\juggernaut.dm" +#include "code\modules\mob\living\basic\cult\shade.dm" +#include "code\modules\mob\living\basic\cult\constructs\_construct.dm" +#include "code\modules\mob\living\basic\cult\constructs\artificer.dm" +#include "code\modules\mob\living\basic\cult\constructs\construct_ai.dm" +#include "code\modules\mob\living\basic\cult\constructs\harvester.dm" +#include "code\modules\mob\living\basic\cult\constructs\juggernaut.dm" +#include "code\modules\mob\living\basic\cult\constructs\proteon.dm" +#include "code\modules\mob\living\basic\cult\constructs\wraith.dm" #include "code\modules\mob\living\basic\drone\_drone.dm" #include "code\modules\mob\living\basic\drone\drone_say.dm" #include "code\modules\mob\living\basic\drone\drone_tools.dm" @@ -4506,11 +4550,27 @@ #include "code\modules\mob\living\basic\farm_animals\gorilla\gorilla_accessories.dm" #include "code\modules\mob\living\basic\farm_animals\gorilla\gorilla_ai.dm" #include "code\modules\mob\living\basic\farm_animals\gorilla\gorilla_emotes.dm" +#include "code\modules\mob\living\basic\guardian\guardian.dm" +#include "code\modules\mob\living\basic\guardian\guardian_creator.dm" +#include "code\modules\mob\living\basic\guardian\guardian_fluff.dm" +#include "code\modules\mob\living\basic\guardian\guardian_helpers.dm" +#include "code\modules\mob\living\basic\guardian\guardian_verbs.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\assassin.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\charger.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\dextrous.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\explosive.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\gaseous.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\gravitokinetic.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\lightning.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\protector.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\ranged.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\standard.dm" +#include "code\modules\mob\living\basic\guardian\guardian_types\support.dm" +#include "code\modules\mob\living\basic\heretic\_heretic_summon.dm" #include "code\modules\mob\living\basic\heretic\ash_spirit.dm" #include "code\modules\mob\living\basic\heretic\fire_shark.dm" #include "code\modules\mob\living\basic\heretic\flesh_stalker.dm" #include "code\modules\mob\living\basic\heretic\flesh_worm.dm" -#include "code\modules\mob\living\basic\heretic\heretic_summon.dm" #include "code\modules\mob\living\basic\heretic\maid_in_the_mirror.dm" #include "code\modules\mob\living\basic\heretic\raw_prophet.dm" #include "code\modules\mob\living\basic\heretic\rust_walker.dm" @@ -4522,6 +4582,9 @@ #include "code\modules\mob\living\basic\icemoon\ice_whelp\ice_whelp_abilities.dm" #include "code\modules\mob\living\basic\icemoon\ice_whelp\ice_whelp_ai.dm" #include "code\modules\mob\living\basic\jungle\venus_human_trap.dm" +#include "code\modules\mob\living\basic\jungle\leaper\leaper.dm" +#include "code\modules\mob\living\basic\jungle\leaper\leaper_abilities.dm" +#include "code\modules\mob\living\basic\jungle\leaper\leaper_ai.dm" #include "code\modules\mob\living\basic\jungle\mega_arachnid\mega_arachnid.dm" #include "code\modules\mob\living\basic\jungle\mega_arachnid\mega_arachnid_abilities.dm" #include "code\modules\mob\living\basic\jungle\mega_arachnid\mega_arachnid_ai.dm" @@ -4581,8 +4644,13 @@ #include "code\modules\mob\living\basic\pets\dog\corgi.dm" #include "code\modules\mob\living\basic\pets\dog\dog_subtypes.dm" #include "code\modules\mob\living\basic\pets\dog\strippable_items.dm" +#include "code\modules\mob\living\basic\ruin_defender\flesh.dm" +#include "code\modules\mob\living\basic\ruin_defender\living_floor.dm" #include "code\modules\mob\living\basic\ruin_defender\skeleton.dm" #include "code\modules\mob\living\basic\ruin_defender\stickman.dm" +#include "code\modules\mob\living\basic\ruin_defender\wizard\wizard.dm" +#include "code\modules\mob\living\basic\ruin_defender\wizard\wizard_ai.dm" +#include "code\modules\mob\living\basic\ruin_defender\wizard\wizard_spells.dm" #include "code\modules\mob\living\basic\space_fauna\ant.dm" #include "code\modules\mob\living\basic\space_fauna\cat_surgeon.dm" #include "code\modules\mob\living\basic\space_fauna\faithless.dm" @@ -4660,7 +4728,13 @@ #include "code\modules\mob\living\basic\space_fauna\wumborian_fugu\inflation.dm" #include "code\modules\mob\living\basic\space_fauna\wumborian_fugu\wumborian_ai.dm" #include "code\modules\mob\living\basic\space_fauna\wumborian_fugu\wumborian_fugu.dm" +#include "code\modules\mob\living\basic\trader\trader.dm" +#include "code\modules\mob\living\basic\trader\trader_actions.dm" +#include "code\modules\mob\living\basic\trader\trader_ai.dm" +#include "code\modules\mob\living\basic\trader\trader_data.dm" +#include "code\modules\mob\living\basic\trader\trader_items.dm" #include "code\modules\mob\living\basic\trooper\nanotrasen.dm" +#include "code\modules\mob\living\basic\trooper\pirate.dm" #include "code\modules\mob\living\basic\trooper\russian.dm" #include "code\modules\mob\living\basic\trooper\syndicate.dm" #include "code\modules\mob\living\basic\trooper\trooper.dm" @@ -4819,7 +4893,6 @@ #include "code\modules\mob\living\simple_animal\animal_defense.dm" #include "code\modules\mob\living\simple_animal\damage_procs.dm" #include "code\modules\mob\living\simple_animal\parrot.dm" -#include "code\modules\mob\living\simple_animal\shade.dm" #include "code\modules\mob\living\simple_animal\simple_animal.dm" #include "code\modules\mob\living\simple_animal\bot\bot.dm" #include "code\modules\mob\living\simple_animal\bot\bot_announcement.dm" @@ -4838,33 +4911,14 @@ #include "code\modules\mob\living\simple_animal\friendly\cat.dm" #include "code\modules\mob\living\simple_animal\friendly\gondola.dm" #include "code\modules\mob\living\simple_animal\friendly\pet.dm" -#include "code\modules\mob\living\simple_animal\guardian\guardian.dm" -#include "code\modules\mob\living\simple_animal\guardian\guardian_creator.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\assassin.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\charger.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\dextrous.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\explosive.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\gaseous.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\gravitokinetic.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\lightning.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\protector.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\ranged.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\standard.dm" -#include "code\modules\mob\living\simple_animal\guardian\types\support.dm" #include "code\modules\mob\living\simple_animal\hostile\alien.dm" #include "code\modules\mob\living\simple_animal\hostile\dark_wizard.dm" #include "code\modules\mob\living\simple_animal\hostile\hostile.dm" #include "code\modules\mob\living\simple_animal\hostile\illusion.dm" #include "code\modules\mob\living\simple_animal\hostile\mimic.dm" #include "code\modules\mob\living\simple_animal\hostile\ooze.dm" -#include "code\modules\mob\living\simple_animal\hostile\pirate.dm" #include "code\modules\mob\living\simple_animal\hostile\vatbeast.dm" -#include "code\modules\mob\living\simple_animal\hostile\wizard.dm" #include "code\modules\mob\living\simple_animal\hostile\zombie.dm" -#include "code\modules\mob\living\simple_animal\hostile\constructs\constructs.dm" -#include "code\modules\mob\living\simple_animal\hostile\constructs\wraith.dm" -#include "code\modules\mob\living\simple_animal\hostile\jungle\_jungle_mobs.dm" -#include "code\modules\mob\living\simple_animal\hostile\jungle\leaper.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\_megafauna.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\blood_drunk_miner.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\bubblegum.dm" @@ -4887,7 +4941,6 @@ #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\elites\pandora.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\goose.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm" -#include "code\modules\mob\living\simple_animal\hostile\retaliate\trader.dm" #include "code\modules\mob\living\simple_animal\slime\death.dm" #include "code\modules\mob\living\simple_animal\slime\emote.dm" #include "code\modules\mob\living\simple_animal\slime\life.dm" @@ -5064,6 +5117,7 @@ #include "code\modules\plumbing\plumbers\fermenter.dm" #include "code\modules\plumbing\plumbers\filter.dm" #include "code\modules\plumbing\plumbers\grinder_chemical.dm" +#include "code\modules\plumbing\plumbers\iv_drip.dm" #include "code\modules\plumbing\plumbers\pill_press.dm" #include "code\modules\plumbing\plumbers\plumbing_buffer.dm" #include "code\modules\plumbing\plumbers\pumps.dm" @@ -5071,6 +5125,7 @@ #include "code\modules\plumbing\plumbers\splitters.dm" #include "code\modules\plumbing\plumbers\synthesizer.dm" #include "code\modules\plumbing\plumbers\teleporter.dm" +#include "code\modules\plumbing\plumbers\vatgrower.dm" #include "code\modules\point\point.dm" #include "code\modules\power\cable.dm" #include "code\modules\power\cell.dm" @@ -5436,7 +5491,6 @@ #include "code\modules\research\xenobiology\vatgrowing\microscope.dm" #include "code\modules\research\xenobiology\vatgrowing\petri_dish.dm" #include "code\modules\research\xenobiology\vatgrowing\swab.dm" -#include "code\modules\research\xenobiology\vatgrowing\vatgrower.dm" #include "code\modules\research\xenobiology\vatgrowing\samples\_micro_organism.dm" #include "code\modules\research\xenobiology\vatgrowing\samples\_sample.dm" #include "code\modules\research\xenobiology\vatgrowing\samples\cell_lines\common.dm" @@ -5532,7 +5586,6 @@ #include "code\modules\spells\spell_types\self\lichdom.dm" #include "code\modules\spells\spell_types\self\mime_vow.dm" #include "code\modules\spells\spell_types\self\mutate.dm" -#include "code\modules\spells\spell_types\self\personality_commune.dm" #include "code\modules\spells\spell_types\self\rod_form.dm" #include "code\modules\spells\spell_types\self\sanguine_strike.dm" #include "code\modules\spells\spell_types\self\smoke.dm" @@ -5936,6 +5989,7 @@ #include "code\modules\wiremod\datatypes\option.dm" #include "code\modules\wiremod\datatypes\signal.dm" #include "code\modules\wiremod\datatypes\string.dm" +#include "code\modules\wiremod\datatypes\user.dm" #include "code\modules\wiremod\datatypes\composite\assoc_list.dm" #include "code\modules\wiremod\datatypes\composite\composite.dm" #include "code\modules\wiremod\datatypes\composite\list.dm" @@ -6023,6 +6077,7 @@ #include "modular_skyrat\master_files\code\game\gamemodes\dynamic\dynamic_rulesets_midround.dm" #include "modular_skyrat\master_files\code\game\gamemodes\dynamic\dynamic_rulesets_roundstart.dm" #include "modular_skyrat\master_files\code\game\machinery\hologram.dm" +#include "modular_skyrat\master_files\code\game\machinery\limbgrower.dm" #include "modular_skyrat\master_files\code\game\machinery\suit_storage.dm" #include "modular_skyrat\master_files\code\game\machinery\doors\firedoor.dm" #include "modular_skyrat\master_files\code\game\objects\items.dm" @@ -6041,6 +6096,7 @@ #include "modular_skyrat\master_files\code\game\objects\items\RCD.dm" #include "modular_skyrat\master_files\code\game\objects\items\religion.dm" #include "modular_skyrat\master_files\code\game\objects\items\scratchingstone.dm" +#include "modular_skyrat\master_files\code\game\objects\items\wiki_manuals.dm" #include "modular_skyrat\master_files\code\game\objects\items\devices\anomaly_neutralizer.dm" #include "modular_skyrat\master_files\code\game\objects\items\stacks\sheets\sheet_types.dm" #include "modular_skyrat\master_files\code\game\objects\items\storage\backpack.dm" @@ -6243,6 +6299,7 @@ #include "modular_skyrat\master_files\code\modules\mod\mod_types.dm" #include "modular_skyrat\master_files\code\modules\mod\modules\_module.dm" #include "modular_skyrat\master_files\code\modules\mod\modules\modules_antag.dm" +#include "modular_skyrat\master_files\code\modules\mod\modules\modules_supply.dm" #include "modular_skyrat\master_files\code\modules\modular_computers\computers\item\laptop_presets.dm" #include "modular_skyrat\master_files\code\modules\pai\card.dm" #include "modular_skyrat\master_files\code\modules\paperwork\employment_contract.dm" @@ -6268,6 +6325,7 @@ #include "modular_skyrat\master_files\code\modules\reagents\withdrawal\generic_addictions.dm" #include "modular_skyrat\master_files\code\modules\religion\religious_sects.dm" #include "modular_skyrat\master_files\code\modules\research\designs\biogenerator_designs.dm" +#include "modular_skyrat\master_files\code\modules\research\designs\limbgrower_designs.dm" #include "modular_skyrat\master_files\code\modules\research\designs\medical_designs.dm" #include "modular_skyrat\master_files\code\modules\research\designs\misc_designs.dm" #include "modular_skyrat\master_files\code\modules\research\designs\tool_designs.dm" @@ -6278,6 +6336,8 @@ #include "modular_skyrat\master_files\code\modules\surgery\surgery.dm" #include "modular_skyrat\master_files\code\modules\surgery\bodyparts\_bodyparts.dm" #include "modular_skyrat\master_files\code\modules\surgery\organs\tongue.dm" +#include "modular_skyrat\master_files\code\modules\surgery\organs\external\wings\functional_wings.dm" +#include "modular_skyrat\master_files\code\modules\surgery\organs\external\wings\wings.dm" #include "modular_skyrat\master_files\code\modules\surgery\organs\internal\appendix\_appendix.dm" #include "modular_skyrat\master_files\code\modules\vehicles\sealed.dm" #include "modular_skyrat\master_files\code\modules\vehicles\snowmobile.dm" @@ -6391,6 +6451,7 @@ #include "modular_skyrat\modules\ashwalkers\code\items\ashwalker_shaman.dm" #include "modular_skyrat\modules\ashwalkers\code\species\Ashwalkers.dm" #include "modular_skyrat\modules\ashwalkers\code\species\damage_datum.dm" +#include "modular_skyrat\modules\ashwalkers\code\turfs\closed_turfs.dm" #include "modular_skyrat\modules\ashwalkers\code\turfs\icemoon_tiles.dm" #include "modular_skyrat\modules\assault_operatives\code\areas.dm" #include "modular_skyrat\modules\assault_operatives\code\assault_operatives.dm" @@ -6946,6 +7007,7 @@ #include "modular_skyrat\modules\delam_emergency_stop\code\admin_scram.dm" #include "modular_skyrat\modules\delam_emergency_stop\code\delam.dm" #include "modular_skyrat\modules\delam_emergency_stop\code\scram.dm" +#include "modular_skyrat\modules\Department_Budgets\cards.dm" #include "modular_skyrat\modules\departmentization\cargo_technician.dm" #include "modular_skyrat\modules\departmentization\clothing_overrides.dm" #include "modular_skyrat\modules\departmentization\quartermaster.dm" @@ -7530,6 +7592,7 @@ #include "modular_skyrat\modules\novaya_ert\code\id.dm" #include "modular_skyrat\modules\novaya_ert\code\mod_suit.dm" #include "modular_skyrat\modules\novaya_ert\code\outfit.dm" +#include "modular_skyrat\modules\novaya_ert\code\police_outfit.dm" #include "modular_skyrat\modules\novaya_ert\code\shield.dm" #include "modular_skyrat\modules\novaya_ert\code\suit.dm" #include "modular_skyrat\modules\novaya_ert\code\surplus_armor.dm" @@ -7566,6 +7629,11 @@ #include "modular_skyrat\modules\oversized\code\door.dm" #include "modular_skyrat\modules\oversized\code\oversized_quirk.dm" #include "modular_skyrat\modules\panicbunker\code\panicbunker.dm" +#include "modular_skyrat\modules\paycheck_rations\code\quirk.dm" +#include "modular_skyrat\modules\paycheck_rations\code\rationpacks.dm" +#include "modular_skyrat\modules\paycheck_rations\code\reagents.dm" +#include "modular_skyrat\modules\paycheck_rations\code\ticket_book.dm" +#include "modular_skyrat\modules\paycheck_rations\code\tickets.dm" #include "modular_skyrat\modules\pixel_shift\code\pixel_shift_component.dm" #include "modular_skyrat\modules\pixel_shift\code\pixel_shift_keybind.dm" #include "modular_skyrat\modules\pixel_shift\code\pixel_shift_mob.dm" @@ -7814,6 +7882,7 @@ #include "modular_skyrat\modules\xenos_skyrat_redo\code\xeno_types\sentinel.dm" #include "modular_skyrat\modules\xenos_skyrat_redo\code\xeno_types\spitter.dm" #include "modular_skyrat\modules\xenos_skyrat_redo\code\xeno_types\warrior.dm" +#include "modular_tannhauser\_skyrat_override\modules\barsigns\code\game\objects\structures\barsigns.dm" #include "modular_tannhauser\_skyrat_override\modules\DynamicRules\code\dynamics.dm" #include "modular_tannhauser\_skyrat_override\modules\lobby_cam\code\lobby_cam.dm" #include "modular_tannhauser\_skyrat_override\modules\veteran_only\code\job_types.dm" diff --git a/tgui/packages/tgui-dev-server/package.json b/tgui/packages/tgui-dev-server/package.json index 2477641c7e7939..56951b14846f18 100644 --- a/tgui/packages/tgui-dev-server/package.json +++ b/tgui/packages/tgui-dev-server/package.json @@ -4,7 +4,7 @@ "version": "4.3.1", "type": "module", "dependencies": { - "axios": "^0.21.1", + "axios": "^1.6.0", "glob": "^7.1.7", "source-map": "^0.7.3", "stacktrace-parser": "^0.1.10", diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss index 7e0a5830fdc9f7..e3f4ecd2febe0b 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss @@ -506,6 +506,11 @@ em { font-size: 90%; } +.bolditalic { + font-style: italic; + font-weight: bold; +} + .boldnotice { color: #6685f5; font-weight: bold; @@ -705,8 +710,14 @@ em { font-size: 185%; } +.spiderbreacher { + color: #e8b670; + font-weight: bold; + font-size: 140%; +} + .spiderscout { - color: #231d99; + color: #231d98; font-weight: bold; font-size: 120%; } @@ -1056,6 +1067,7 @@ $alert-stripe-colors: ( 'orange': #593400, 'red': #420000, 'purple': #2c0030, + 'grey': #252525, ); $alert-stripe-alternate-colors: ( @@ -1067,28 +1079,31 @@ $alert-stripe-alternate-colors: ( 'orange': #6b4200, 'red': #520000, 'purple': #38003d, + 'grey': #292929, ); $alert-major-header-colors: ( 'default': #33d5ff, 'green': #00ff80, 'blue': #33d5ff, - 'pink': #ff80b3, + 'pink': #ff5297, 'yellow': #fff4e0, 'orange': #feefe7, - 'red': #ffa8c4, + 'red': #ff5297, 'purple': #c7a1f7, + 'grey': #ff5297, ); $alert-subheader-header-colors: ( - 'default': #ff9ebb, - 'green': #ffb3c9, - 'blue': #ff9ebb, - 'pink': #75e3ff, - 'yellow': #75e3ff, - 'orange': #bdf1ff, - 'red': #75e3ff, - 'purple': #75e3ff, + 'default': #ff5297, + 'green': #ff85b5, + 'blue': #ff5297, + 'pink': #33d5ff, + 'yellow': #33d5ff, + 'orange': #33d5ff, + 'red': #33d5ff, + 'purple': #33d5ff, + 'grey': #33d5ff, ); */ @@ -1101,6 +1116,7 @@ $alert-stripe-colors: ( 'orange': #431b16, 'red': #420000, 'purple': #220c24, + 'grey': #252525, ); $alert-stripe-alternate-colors: ( @@ -1112,6 +1128,7 @@ $alert-stripe-alternate-colors: ( 'orange': #50211b, 'red': #520000, 'purple': #2b0f2e, + 'grey': #292929, ); $alert-major-header-colors: ( @@ -1123,6 +1140,7 @@ $alert-major-header-colors: ( 'orange': #e79f79, 'red': #ff4542, 'purple': #bf9cde, + 'grey': #ff4542, ); $alert-subheader-header-colors: ( @@ -1134,6 +1152,7 @@ $alert-subheader-header-colors: ( 'orange': #ffddbd, 'red': #e9aa72, 'purple': #f7cfcf, + 'grey': #e9aa72, ); // SKYRAT EDIT CHANGE END diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss index 6ee5c6c4ce74a6..81955e9eded2db 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss @@ -737,8 +737,14 @@ h2.alert { font-size: 185%; } +.spiderbreacher { + color: #804b02; + font-weight: bold; + font-size: 140%; +} + .spiderscout { - color: #1b10cd; + color: #0c0674; font-weight: bold; font-size: 120%; } @@ -989,6 +995,7 @@ $alert-stripe-colors: ( 'orange': #ffe2b3, 'red': #ffb3b3, 'purple': #fac2ff, + 'grey': #e3e3e3, ); $alert-stripe-alternate-colors: ( @@ -1000,6 +1007,7 @@ $alert-stripe-alternate-colors: ( 'orange': #ffe8c2, 'red': #ffc2c2, 'purple': #fbd1ff, + 'grey': #ebebeb, ); $alert-major-header-colors: ( @@ -1011,6 +1019,7 @@ $alert-major-header-colors: ( 'orange': #823208, 'red': #800029, 'purple': #450d8c, + 'grey': #800033, ); $alert-subheader-header-colors: ( @@ -1022,6 +1031,7 @@ $alert-subheader-header-colors: ( 'orange': #002c85, 'red': #002c85, 'purple': #002c85, + 'grey': #002c85, ); */ @@ -1034,6 +1044,7 @@ $alert-stripe-colors: ( 'orange': #ffe2b3, 'red': #ffbbb3, 'purple': #e6d1f0, + 'grey': #e3e3e3, ); $alert-stripe-alternate-colors: ( @@ -1045,6 +1056,7 @@ $alert-stripe-alternate-colors: ( 'orange': #ffe8c2, 'red': #ffc8c2, 'purple': #ead9f2, + 'grey': #ebebeb, ); $alert-major-header-colors: ( @@ -1056,6 +1068,7 @@ $alert-major-header-colors: ( 'orange': #b14810, 'red': #a80e00, 'purple': #5b2673, + 'grey': #a80e00, ); $alert-subheader-header-colors: ( @@ -1067,6 +1080,7 @@ $alert-subheader-header-colors: ( 'orange': #002c85, 'red': #483c3c, 'purple': #991200, + 'grey': #002c85, ); // SKYRAT EDIT CHANGE END diff --git a/tgui/packages/tgui/components/LabeledList.tsx b/tgui/packages/tgui/components/LabeledList.tsx index 283c0a2b912032..d89423aded2bfa 100644 --- a/tgui/packages/tgui/components/LabeledList.tsx +++ b/tgui/packages/tgui/components/LabeledList.tsx @@ -8,6 +8,7 @@ import { BooleanLike, classes, pureComponentHooks } from 'common/react'; import { InfernoNode } from 'inferno'; import { Box, unit } from './Box'; import { Divider } from './Divider'; +import { Tooltip } from './Tooltip'; type LabeledListProps = { children?: any; @@ -20,19 +21,20 @@ export const LabeledList = (props: LabeledListProps) => { LabeledList.defaultHooks = pureComponentHooks; -type LabeledListItemProps = { - className?: string | BooleanLike; - label?: string | InfernoNode | BooleanLike; - labelColor?: string | BooleanLike; - labelWrap?: boolean; - color?: string | BooleanLike; - textAlign?: string | BooleanLike; - buttons?: InfernoNode; +type LabeledListItemProps = Partial<{ + className: string | BooleanLike; + label: string | InfernoNode | BooleanLike; + labelColor: string | BooleanLike; + labelWrap: boolean; + color: string | BooleanLike; + textAlign: string | BooleanLike; + buttons: InfernoNode; /** @deprecated */ - content?: any; - children?: InfernoNode; - verticalAlign?: string; -}; + content: any; + children: InfernoNode; + verticalAlign: string; + tooltip: string; +}>; const LabeledListItem = (props: LabeledListItemProps) => { const { @@ -46,20 +48,46 @@ const LabeledListItem = (props: LabeledListItemProps) => { content, children, verticalAlign = 'baseline', + tooltip, } = props; + + let innerLabel; + if (label) { + innerLabel = label; + if (typeof label === 'string') innerLabel += ':'; + } + + if (tooltip !== undefined) { + innerLabel = ( + + + {innerLabel} + + + ); + } + + let labelChild = ( + + {innerLabel} + + ); + return ( - - {label ? (typeof label === 'string' ? label + ':' : label) : null} - + {labelChild} { {tab === 1 && } {tab === 2 && } + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx b/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx index e8471a6a5acf7c..7000b324aa9433 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx @@ -1,6 +1,9 @@ import { useBackend } from '../backend'; import { Box, Collapsible, Divider, LabeledList, Section, Stack } from '../components'; import { Objective } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END import { Window } from '../layouts'; @@ -25,6 +28,7 @@ export const AntagInfoBlob = (props, context) => { + diff --git a/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx b/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx index f3eda78c6615bb..339c115e30c74a 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx @@ -4,6 +4,9 @@ import { useBackend, useSharedState } from '../backend'; import { Button, Dimmer, Dropdown, Section, Stack, NoticeBox } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const hivestyle = { fontWeight: 'bold', @@ -54,9 +57,10 @@ type Info = { can_change_objective: BooleanLike; }; +// SKYRAT EDIT change height from 750 to 900 export const AntagInfoChangeling = (props, context) => { return ( - + { + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoClock.tsx b/tgui/packages/tgui/interfaces/AntagInfoClock.tsx index 8912a666bc5040..96b94c703393d7 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoClock.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoClock.tsx @@ -1,16 +1,20 @@ import { useBackend } from '../backend'; import { Icon, Section, Stack } from '../components'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END type Info = { antag_name: string; }; +// SKYRAT EDIT change height from 250 to 350 export const AntagInfoClock = (props, context) => { const { data } = useBackend(context); const { antag_name } = data; return ( - +
@@ -19,6 +23,11 @@ export const AntagInfoClock = (props, context) => { {' You are the ' + antag_name + '! '} + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx b/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx index 33b7623c44f62f..7aa7b80eea0ca3 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx @@ -2,23 +2,32 @@ import { useBackend } from '../backend'; import { Section, Stack } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END type Info = { antag_name: string; objectives: Objective[]; }; +// SKYRAT EDIT increase height from 250 to 500 export const AntagInfoGeneric = (props, context) => { const { data } = useBackend(context); const { antag_name, objectives } = data; return ( - +
You are the {antag_name}! + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx b/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx index da4331026cc477..ffc5d54fbfe663 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx @@ -3,6 +3,9 @@ import { Section, Stack, Box, Tabs, Button, BlockQuote } from '../components'; import { Window } from '../layouts'; import { BooleanLike } from 'common/react'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const hereticRed = { color: '#e03c3c', @@ -64,6 +67,12 @@ const IntroductionSection = (props, context) => { + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} + diff --git a/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx b/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx index 0344f11d2eeb88..76e7944cfd7c53 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx @@ -5,6 +5,9 @@ import { BlockQuote, Button, Section, Stack, Tabs } from '../components'; import { BooleanLike } from 'common/react'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const allystyle = { fontWeight: 'bold', @@ -55,6 +58,7 @@ const IntroductionSection = (props, context) => { /> } /> +
diff --git a/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx b/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx index fb98e1aa35b90a..58c379ab522992 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx @@ -1,5 +1,8 @@ import { BlockQuote, Stack } from '../components'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const goodstyle = { color: 'lightgreen', @@ -48,6 +51,11 @@ export const AntagInfoMorph = (props, context) => { {' '} + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */}
diff --git a/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx b/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx index 327e114e2fd5ef..6d4b105c498247 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx @@ -1,5 +1,8 @@ import { BlockQuote, LabeledList, Section, Stack } from '../components'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const tipstyle = { color: 'white', @@ -68,6 +71,11 @@ export const AntagInfoNightmare = (props, context) => {
+ {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */}
diff --git a/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx b/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx index a537888af750a4..0615e46e05d01b 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx @@ -3,6 +3,9 @@ import { useBackend } from '../backend'; import { Icon, Section, Stack } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const ninja_emphasis = { color: 'red', @@ -48,6 +51,11 @@ export const AntagInfoNinja = (props, context) => { what you can do! + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} { + const { data } = useBackend(context); + const { antag_name } = data; + switch (antag_name) { + case 'Abductor Agent' || 'Abductor Scientist' || 'Abductor Solo': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Drifting Contractor': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Cortical Borer': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Venus Human Trap': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Obsessed': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Revenant': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Space Dragon': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Space Pirate': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Blob': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Changeling': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'ClockCult': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'AssaultOps': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Heretic': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Malf AI': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Morph': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Nightmare': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Ninja': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Wizard': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + default: + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + } +}; diff --git a/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx b/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx index cc62986c085d97..083e3b2372c157 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx @@ -4,6 +4,9 @@ import { BlockQuote, Button, Dimmer, Section, Stack } from '../components'; import { BooleanLike } from 'common/react'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const allystyle = { fontWeight: 'bold', @@ -48,6 +51,14 @@ const IntroductionSection = (props, context) => { + {/* SKYRAT EDIT ADDITION START */} + + {/* SKYRAT EDIT ADDITION START */} + + + + + {/* SKYRAT EDIT ADDITION END */} ); @@ -218,11 +229,12 @@ const CodewordsSection = (props, context) => { ); }; +// SKYRAT EDIT: change height from 580 to 650 export const AntagInfoTraitor = (props, context) => { const { data } = useBackend(context); const { theme } = data; return ( - + diff --git a/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx b/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx index e5de257851a874..94d528513d0de6 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx @@ -3,6 +3,9 @@ import { useBackend } from '../backend'; import { Box, Section, Stack } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const teleportstyle = { color: 'yellow', @@ -48,12 +51,13 @@ type Info = { can_change_objective: BooleanLike; }; +// SKYRAT CHANGE height from 630 to 700 export const AntagInfoWizard = (props, context) => { const { data, act } = useBackend(context); const { ritual, objectives, can_change_objective } = data; return ( - + @@ -78,6 +82,11 @@ export const AntagInfoWizard = (props, context) => { + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/ChemDispenser.js b/tgui/packages/tgui/interfaces/ChemDispenser.tsx similarity index 82% rename from tgui/packages/tgui/interfaces/ChemDispenser.js rename to tgui/packages/tgui/interfaces/ChemDispenser.tsx index d1035900a32c58..c8dc25e943f9d5 100644 --- a/tgui/packages/tgui/interfaces/ChemDispenser.js +++ b/tgui/packages/tgui/interfaces/ChemDispenser.tsx @@ -1,22 +1,49 @@ import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { toTitleCase } from 'common/string'; -import { Fragment } from 'inferno'; import { useBackend, useLocalState } from '../backend'; import { AnimatedNumber, Box, Button, Icon, LabeledList, ProgressBar, Section } from '../components'; import { Window } from '../layouts'; +export type BeakerReagent = { + name: string; + volume: number; +}; + +export type Beaker = { + maxVolume: number; + transferAmounts: number[]; + pH: number; + currentVolume: number; + contents: BeakerReagent[]; +}; + +type DispensableReagent = { + title: string; + id: string; + pH: number; + pHCol: string; +}; + +type Data = { + showpH: BooleanLike; + amount: number; + energy: number; + maxEnergy: number; + chemicals: DispensableReagent[]; + recipes: string[]; + recordingRecipe: string[]; + recipeReagents: string[]; + beaker: Beaker; +}; + export const ChemDispenser = (props, context) => { - const { act, data } = useBackend(context); + const { act, data } = useBackend(context); const recording = !!data.recordingRecipe; - const { recipeReagents = [] } = data; + const { recipeReagents = [], recipes = [], beaker } = data; const [hasCol, setHasCol] = useLocalState(context, 'has_col', false); - // TODO: Change how this piece of shit is built on server side - // It has to be a list, not a fucking OBJECT! - const recipes = Object.keys(data.recipes).map((name) => ({ - name, - contents: data.recipes[name], - })); - const beakerTransferAmounts = data.beakerTransferAmounts || []; + + const beakerTransferAmounts = beaker ? beaker.transferAmounts : []; const beakerContents = (recording && Object.keys(data.recordingRecipe).map((id) => ({ @@ -24,7 +51,7 @@ export const ChemDispenser = (props, context) => { name: toTitleCase(id.replace(/_/, ' ')), volume: data.recordingRecipe[id], }))) || - data.beakerContents || + beaker?.contents || []; return ( @@ -41,10 +68,10 @@ export const ChemDispenser = (props, context) => { )} + } + /> + } + /> + } + /> + } + /> + } + /> + {material.requested > 0 && ( + x {material.requested} + )} ))} @@ -167,7 +228,6 @@ export const MatMarket = (props, context) => { }; const MarketCrashModal = (props, context) => { - const { act, data } = useBackend(context); return ( ATTENTION! THE MARKET HAS CRASHED diff --git a/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx b/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx index 04a1100fa13385..e891337c275fca 100644 --- a/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx +++ b/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx @@ -290,6 +290,7 @@ const MECHA_SNOWFLAKE_ID_RADIO = 'radio_snowflake'; const MECHA_SNOWFLAKE_ID_AIR_TANK = 'air_tank_snowflake'; const MECHA_SNOWFLAKE_ID_WEAPON_BALLISTIC = 'ballistic_weapon_snowflake'; const MECHA_SNOWFLAKE_ID_GENERATOR = 'generator_snowflake'; +const MECHA_SNOWFLAKE_ID_CLAW = 'lawclaw_snowflake'; export const ModuleDetailsExtra = (props: { module: MechModule }, context) => { const module = props.module; @@ -308,6 +309,8 @@ export const ModuleDetailsExtra = (props: { module: MechModule }, context) => { return ; case MECHA_SNOWFLAKE_ID_GENERATOR: return ; + case MECHA_SNOWFLAKE_ID_CLAW: + return ; default: return null; } @@ -887,3 +890,27 @@ const SnowflakeGeneraor = (props, context) => { ); }; + +const SnowflakeLawClaw = (props, context) => { + const { act, data } = useBackend(context); + const { ref } = props.module; + const { autocuff } = props.module.snowflake; + return ( + + act('equip_act', { + ref: ref, + gear_action: 'togglecuff', + }) + } + /> + } + /> + ); +}; diff --git a/tgui/packages/tgui/interfaces/PortableChemMixer.js b/tgui/packages/tgui/interfaces/PortableChemMixer.tsx similarity index 65% rename from tgui/packages/tgui/interfaces/PortableChemMixer.js rename to tgui/packages/tgui/interfaces/PortableChemMixer.tsx index 7228a37b44d912..aea59d95dd7afb 100644 --- a/tgui/packages/tgui/interfaces/PortableChemMixer.js +++ b/tgui/packages/tgui/interfaces/PortableChemMixer.tsx @@ -1,28 +1,35 @@ import { sortBy } from 'common/collections'; -import { toTitleCase } from 'common/string'; +import { Beaker } from './ChemDispenser'; import { useBackend } from '../backend'; import { AnimatedNumber, Box, Button, LabeledList, Section } from '../components'; import { Window } from '../layouts'; +type DispensableReagent = { + title: string; + id: string; + volume: number; + pH: number; +}; + +type Data = { + amount: number; + chemicals: DispensableReagent[]; + beaker: Beaker; +}; + export const PortableChemMixer = (props, context) => { - const { act, data } = useBackend(context); - const recording = !!data.recordingRecipe; - const beakerTransferAmounts = data.beakerTransferAmounts || []; - const beakerContents = - (recording && - Object.keys(data.recordingRecipe).map((id) => ({ - id, - name: toTitleCase(id.replace(/_/, ' ')), - volume: data.recordingRecipe[id], - }))) || - data.beakerContents || - []; - const chemicals = sortBy((chem) => chem.title)(data.chemicals); + const { act, data } = useBackend(context); + const { beaker } = data; + const beakerTransferAmounts = beaker ? beaker.transferAmounts : []; + const beakerContents = beaker ? beaker.contents : []; + const chemicals = sortBy((chem: DispensableReagent) => chem.id)( + data.chemicals + ); return ( - +
(
(